#include "AXI_slave_if.h"
/*! Fixed point arithmetic shift. */
#define SHIFT 13
/*! Fixed point co-ord shift. */
#define COORD_SHIFT 20
#define CONST_VALUE (256 / 2)
SC_MODULE(Mybrot){
public:
// Ports
AXI_slave_if* s_if;
sc_out <bool> interrupt;
unsigned int register_num;
unsigned int slave_read_delay;
unsigned int slave_write_delay;
// Base address
sc_uint<32> base_address;
// Brot hardware register
sc_uint<32> r_STATE;
sc_uint<32> r_INTERRUPT;
sc_uint<32> r_INT_ENABLE;
sc_uint<32> r_PX;
sc_uint<32> r_PY;
sc_uint<32> r_DX;
sc_uint<32> r_OPSTART;
int max_delay; //delay
int each_delay[32];
sc_uint<32> col_array[16]; //result
sc_event brot_start;
void register_reset(){
r_STATE = 1;
r_INTERRUPT = 0;
r_INT_ENABLE = 0;
r_PX = 0;
r_PY = 0;
r_DX = 0;
r_OPSTART = 0;
}
void brot_execution(){
// Brot reset
register_reset();
wait();
while(1){
Handling_FSM();
}
}
typedef enum {
ST_NONE = 0,
ST_IDLE = 1,
ST_EXECUTE = 2,
ST_INTERRUPT = 3
}BROT_STATE;
SC_HAS_PROCESS(Mybrot);
Mybrot(sc_module_name _name, sc_uint<32> b_addr, unsigned int addr_size){
s_if = new AXI_slave_if("simple_slave_if", b_addr, addr_size);
slave_read_delay = 1;
slave_write_delay = 1;
base_address = b_addr;
register_num = addr_size >> 2;
max_delay = 0;
base_address = b_addr;
SC_THREAD(brot_execution);
sensitive << brot_start;
SC_THREAD(set_slave_data);
sensitive << s_if->write_reg_event;
SC_THREAD(get_slave_data);
sensitive << s_if->read_reg_event;
}
void Handling_FSM() {
switch (r_STATE) {
case ST_IDLE:
if (r_OPSTART != 0) {
#ifdef VERBOSE
cout << "\nFSM: IDLE -> EXECUTE\n" << endl;
#endif
max_delay = 0;
int px = (int)r_PX;
int py = (int)r_PY;
for (int i = 0; i < 16; i++) {
if (r_OPSTART & ((sc_uint<32>)1 << i)) {
each_delay[i] = 0;
col_array[i] = calc(px >> (COORD_SHIFT - SHIFT), py >> (COORD_SHIFT - SHIFT), i);
if (max_delay < each_delay[i]){
max_delay = each_delay[i] - 1;
}
px += (int)r_DX;
}
else {
break;
}
}
r_STATE = ST_EXECUTE;
r_OPSTART = 0;
}
else {
wait();
}
break;
case ST_EXECUTE:
if ((max_delay--) == 0) {
if (r_INT_ENABLE == 1) {
#ifdef VERBOSE
cout << "\nFSM: EXECUTE -> INTERRUPT\n" << endl;
#endif
r_STATE = ST_INTERRUPT;
r_INTERRUPT = 1;
interrupt.write(1);
}
else {
#ifdef VERBOSE
cout << "\nFSM: EXECUTE -> IDLE\n" << endl;
#endif
r_STATE = ST_IDLE;
r_INTERRUPT = 0;
wait();
}
}
wait(s_if->clk.posedge_event());
break;
case ST_INTERRUPT:
if (r_INTERRUPT == 0) {
#ifdef VERBOSE
cout << "\nFSM: INTERRUPT -> IDLE\n" << endl;
#endif
interrupt.write(0);
r_STATE = ST_IDLE; // Move to IDLE state
wait();
}
wait(s_if->clk.posedge_event());
break;
default:
break;
}
}
int calc(long sx, long sy, int delay_idx) {
int count = 0;
long px = sx, py = sy;
long valueCheck = 4 << SHIFT;
each_delay[delay_idx] = 0;
for (count = 0; count < CONST_VALUE; count++) {
long px2, py2;
each_delay[delay_idx] += 4;//delay
px2 = (px * px) >> (SHIFT + 1);
py2 = (py * py) >> (SHIFT + 1);
// Terminate when (px^2 + py^2) > 2^2.
if (px2 + py2 > valueCheck) {
return count;
}
py = ((px * py) >> (SHIFT - 1)) + sy;
px = px2 - py2 + sx;
}
return -1;
}
void get_slave_data() {
wait();
while (1) {
std::map<sc_uint<2>, AXITransaction*>::iterator it = s_if->activeReads.begin();
if (it == s_if->activeReads.end()) {
// error condition
// if activewrite is empty exit simulation
// fix master simulation process module
cout << "[" << sc_time_stamp() << "] Read transfer error occured" << endl;
cout << "activeReads is empty" << endl;
exit(0);
}
// Slave read delay
for (int j = 0; j < slave_read_delay + 1; j++) {
if (j == slave_read_delay) { s_if->read_ready_event.notify(); }
wait(s_if->clk.posedge_event());
}
sc_uint<32> start_addr = it->second->addr;
sc_uint <3> byte = it->second->size; // simple slave un-support byte size
sc_uint <2> type = it->second->type;
sc_uint <4> len = it->second->len;
sc_uint<32> addr = start_addr;
s_if->Rlen = len;
s_if->Rid = it->second->ID;
sc_uint<32> tmp_data;
for (int i = 0; i < len + 1; i++) {
sc_uint<32> offset = addr - base_address;
switch (offset) {
case BROT_REG_OFFSET_STATE:
tmp_data = r_STATE;
break;
case BROT_REG_OFFSET_INTERRUPT:
tmp_data = r_INTERRUPT;
break;
case BROT_REG_OFFSET_INT_ENABLE:
tmp_data = r_INT_ENABLE;
break;
case BROT_REG_OFFSET_PX:
tmp_data = r_PX;
break;
case BROT_REG_OFFSET_PY:
tmp_data = r_PY;
break;
case BROT_REG_OFFSET_DX:
tmp_data = r_DX;
break;
case BROT_REG_OFFSET_OPSTART:
tmp_data = r_OPSTART;
break;
default:
if (offset >= BROT_REG_OFFSET_COL00 && offset <= BROT_REG_OFFSET_COL15)
tmp_data = (sc_uint<32>) col_array[(offset - BROT_REG_OFFSET_COL00) >> 2];
break;
}
addr = s_if->burst_addr_change(addr, start_addr, byte, type, len);
s_if->read_buffer = tmp_data;
s_if->set_read_data_event.notify();
wait(s_if->get_read_data_event);
}
wait();
}
}
void set_slave_data() {
wait();
while (1) {
std::map<sc_uint<2>, AXITransaction*>::iterator it = s_if->activeWrites.begin();
if (it == s_if->activeWrites.end()) {
// error condition
// if activewrite is empty exit simulation
// fix master simulation process module
cout << "[" << sc_time_stamp() << "] Write transfer error occured" << endl;
cout << "activeWrites is empty" << endl;
exit(0);
}
for (int j = 0; j < slave_write_delay + 1; j++) { wait(s_if->clk.posedge_event()); }
sc_uint<32> start_addr = it->second->addr;
sc_uint <3> byte = it->second->size;
sc_uint <2> type = it->second->type;
sc_uint <4> len = it->second->len;
sc_uint<32> addr = start_addr;
s_if->Wid = it->second->ID;
s_if->Wlen = len;
s_if->write_ready_event.notify();
for (int i = 0; i < len + 1; i++) {
wait(s_if->set_write_data_event);
sc_uint<32> offset = addr - base_address;
sc_uint<32> tmp_data = s_if->write_buffer;
switch (offset) {
case BROT_REG_OFFSET_STATE:
r_STATE = tmp_data;
break;
case BROT_REG_OFFSET_INTERRUPT:
r_INTERRUPT = tmp_data;
break;
case BROT_REG_OFFSET_INT_ENABLE:
r_INT_ENABLE = tmp_data;
break;
case BROT_REG_OFFSET_PX:
r_PX = tmp_data;
break;
case BROT_REG_OFFSET_PY:
r_PY = tmp_data;
break;
case BROT_REG_OFFSET_DX:
r_DX = tmp_data;
break;
case BROT_REG_OFFSET_OPSTART:
r_OPSTART = tmp_data;
if (r_OPSTART == 1) brot_start.notify();
break;
default:
break;
}
addr = s_if->burst_addr_change(addr, start_addr, byte, type, len);
s_if->write_resp_event.notify();
}
wait();
}
return;
}
};