#include <string>
#include "AXI_slave_if.h"
#include "AXI_master_if.h"
#include "Memory_map.h"
#define DMAC_REG_DEFAULT_VALUE_STATE 0x00000001
#define DMAC_REG_DEFAULT_VALUE_INTERRUPT 0x00000000
#define DMAC_REG_DEFAULT_VALUE_INT_ENABLE 0x00000000
#define DMAC_REG_DEFAULT_VALUE_SRC_ADDR 0x00000000
#define DMAC_REG_DEFAULT_VALUE_DST_ADDR 0x00000000
#define DMAC_REG_DEFAULT_VALUE_DATASIZE 0x00000000
#define DMAC_REG_DEFAULT_VALUE_OPSTART 0x00000000
#define DMAC_REG_NUM 0x00000020
SC_MODULE(MyDMAC) {
// DMAC ports
AXI_master_if* m_if;
AXI_slave_if* s_if;
sc_out<bool> interrupt;
// DMAC registers
sc_uint<32> r_STATE;
sc_uint<32> r_INTERRUPT;
sc_uint<32> r_INT_ENABLE;
sc_uint<32> r_SRC_ADDR;
sc_uint<32> r_DST_ADDR;
sc_uint<32> r_DATASIZE;
sc_uint<32> r_OPSTART;
/// Member variables
sc_uint<2> Master_ID;
sc_uint<32> base_address;
unsigned int slave_read_delay;
unsigned int slave_write_delay;
sc_uint<32>* data_buffer; // Master data buffer
bool isInterruptSet; // Flag varible for interrupt
// DMAC event for start simulation process
sc_event transfer;
// constructor
SC_HAS_PROCESS(MyDMAC);
MyDMAC(sc_module_name _name, int ID, sc_uint<32> b_addr) {
Master_ID = ID;
base_address = b_addr;
slave_read_delay = 1;
slave_write_delay = 1;
m_if = new AXI_master_if("DMAC_master_if");
s_if = new AXI_slave_if("DMAC_slave_if", b_addr, DMAC_REG_NUM);
SC_THREAD(dmac_execute);
sensitive << transfer;
SC_THREAD(set_slave_data);
sensitive << s_if->write_reg_event;
SC_THREAD(get_slave_data);
sensitive << s_if->read_reg_event;
}
void register_reset() {
r_STATE = DMAC_REG_DEFAULT_VALUE_STATE;
r_INTERRUPT = DMAC_REG_DEFAULT_VALUE_INTERRUPT;
r_INT_ENABLE = DMAC_REG_DEFAULT_VALUE_INT_ENABLE;
r_SRC_ADDR = DMAC_REG_DEFAULT_VALUE_SRC_ADDR;
r_DST_ADDR = DMAC_REG_DEFAULT_VALUE_DST_ADDR;
r_DATASIZE = DMAC_REG_DEFAULT_VALUE_DATASIZE;
r_OPSTART = DMAC_REG_DEFAULT_VALUE_OPSTART;
isInterruptSet = false;
}
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 DMAC_OFF_STATE:
tmp_data = r_STATE;
break;
case DMAC_OFF_INTERRUPT:
tmp_data = r_INTERRUPT;
break;
case DMAC_OFF_INT_ENABLE:
tmp_data = r_INT_ENABLE;
break;
case DMAC_OFF_SRC_ADDR:
tmp_data = r_SRC_ADDR;
break;
case DMAC_OFF_DST_ADDR:
tmp_data = r_DST_ADDR;
break;
case DMAC_OFF_DATASIZE:
tmp_data = r_DATASIZE;
break;
case DMAC_OFF_OPSTART:
tmp_data = r_OPSTART;
break;
default:
tmp_data = 0xBEFFBEFF;
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 DMAC_OFF_STATE:
r_STATE = tmp_data;
break;
case DMAC_OFF_INTERRUPT:
r_INTERRUPT = tmp_data;
break;
case DMAC_OFF_INT_ENABLE:
r_INT_ENABLE = tmp_data;
break;
case DMAC_OFF_SRC_ADDR:
r_SRC_ADDR = tmp_data;
break;
case DMAC_OFF_DST_ADDR:
r_DST_ADDR = tmp_data;
break;
case DMAC_OFF_DATASIZE:
r_DATASIZE = tmp_data;
break;
case DMAC_OFF_OPSTART:
r_OPSTART = tmp_data;
transfer.notify();
break;
default:
break;
}
addr = s_if->burst_addr_change(addr, start_addr, byte, type, len);
s_if->write_resp_event.notify();
}
wait();
}
return;
}
void dmac_execute() {
//reset
register_reset();
wait();
while (1) {
Handling_FSM();
}
}
void Handling_FSM() {
switch (r_STATE) {
case ST_IDLE:
if (r_OPSTART == 1) {
r_STATE = ST_TRANSFER; // Move to TRANSFER state
r_OPSTART = 0; // Clear OPSTART
}
else {
wait();
}
break;
case ST_TRANSFER:
while (1) {
sc_uint<4> burstLength;
if (r_DATASIZE > 64) {
r_DATASIZE = r_DATASIZE - 64;
burstLength = BURST_LEN_16;
data_buffer = m_if->master_read(Master_ID, r_SRC_ADDR, DATA_SIZE_4BYTE, BURST_INCRESE, burstLength);
m_if->master_write(Master_ID, r_DST_ADDR, data_buffer, DATA_SIZE_4BYTE, BURST_INCRESE, burstLength);
}
else {
r_DATASIZE = 0;
burstLength = (r_DATASIZE >> 2) - 1;
data_buffer = m_if->master_read(Master_ID, r_SRC_ADDR, DATA_SIZE_4BYTE, BURST_INCRESE, burstLength);
m_if->master_write(Master_ID, r_DST_ADDR, data_buffer, DATA_SIZE_4BYTE, BURST_INCRESE, burstLength);
break;
}
r_SRC_ADDR = r_SRC_ADDR + 64;
r_DST_ADDR = r_DST_ADDR + 64;
}
if (r_INT_ENABLE == 0) {
r_STATE = ST_IDLE;
wait();
}
else {
r_STATE = ST_INTERRUPT;
r_INTERRUPT = 1;
isInterruptSet = false;
}
break;
case ST_INTERRUPT:
if (r_INTERRUPT == 0x0) {
interrupt.write(0);
r_STATE = ST_IDLE; // Move to IDLE state
isInterruptSet = false; // Clear isInterruptSet flag
wait();
}
else {
if (!isInterruptSet) {
isInterruptSet = true; // Set isInterruptSet flag
interrupt.write(1);
}
}
wait(s_if->clk.posedge_event());
break;
default:
break;
}
}
typedef enum {
ST_NONE = 0,
ST_IDLE = 1,
ST_TRANSFER = 2,
ST_INTERRUPT = 4,
}DMAC_STATE;
};