#include <map>
#ifndef AXI_MASTER_IF
#define AXI_MASTER_IF
#include "AXI_SIGNAL_PORTS.h"
SC_MODULE(AXI_master_if) {
public:
//Port of AXI master interface
sc_in<bool> clk{ "Master_if_clk" };
//sc_in<bool> reset;
MASTER_PORTS ports;
// Read, write buffer
sc_uint<32> read_buffer[16];
sc_uint<32> write_buffer[16];
// Events of master if
sc_event AR_master_event;
sc_event R_master_event;
sc_event read_transfer_done;
sc_event AW_master_event;
sc_event W_master_event;
sc_event B_master_event;
sc_event write_transfer_done;
// AXI_TRANSACTION INFORMATIONS
std::map<sc_uint<2>, AXITransaction*> activeWrites;
std::map<sc_uint<2>, AXITransaction*> activeReads;
void mAR() {
//initialize AR if
wait(); // wait for AR_master_event notify
while (1) {
#ifdef VERBOSE
std::cout << std::endl << "===== " << this->name() << " Master AR Channel (" << sc_time_stamp() << ")====" << std::endl;
std::cout << "AR Channel simulation process wake up" << std::endl;
#endif
std::map<sc_uint<2>, AXITransaction*>::iterator it = activeReads.begin();
// read activeReads map for read transfer data
for (; it != activeReads.end(); ++it) {
ports.ARID.write(it->second->ID);
ports.ARADDR.write(it->second->addr);
ports.ARSIZE.write(it->second->size);
ports.ARBURST.write(it->second->type);
ports.ARLEN.write(it->second->len);
// AR Channel handshake here
ports.ARVALID.write(1);
do {
wait(clk.posedge_event());
} while (ports.ARREADY.read() == 0); // wait until ARREADY 1
// Finish AR channel transfer
R_master_event.notify();
ports.ARVALID.write(0);
}
wait(); // wait next AR_master_event
}
}
void mR() {
//initialize R Channel
wait();// wait for R_master_event notify
while (1) {
std::map<sc_uint<2>, AXITransaction*>::iterator it = activeReads.begin();
if (it == activeReads.end()) {
cout << "[" << sc_time_stamp() << "] Read transfer error occurred" << endl;
cout << "activeReads is empty" << endl;
exit(0);
}
sc_uint<4> len = it->second->len;
for (int i = 0; i < len + 1; i++) {
ports.RREADY.write(1); // write RREADY
do {
wait(clk.posedge_event());
} while (ports.RVALID.read() == 0); // wait until RVALID 1
read_buffer[i] = ports.RDATA.read();
ports.RREADY.write(0);
}
//erase activeReads here
read_transfer_done.notify();
wait(); // wait next R_master_event
}
}
void mAW() {
//initialize AW Channel
ports.AWID.write(0);
ports.AWADDR.write(0);
ports.AWLEN.write(0);
ports.AWSIZE.write(0);
ports.AWBURST.write(0);
ports.AWVALID.write(0);
wait();// wait for AW_master_event notify
while (1) {
std::map<sc_uint<2>, AXITransaction*>::iterator it = activeWrites.begin();
for (; it != activeWrites.end(); ++it) {
ports.AWID.write(it->second->ID);
ports.AWADDR.write(it->second->addr);
ports.AWSIZE.write(it->second->size);
ports.AWBURST.write(it->second->type);
ports.AWLEN.write(it->second->len);
ports.AWVALID.write(1);
do {
wait(clk.posedge_event());
} while (ports.AWREADY == 0); // wait until AWREADY 1
W_master_event.notify();
ports.AWVALID.write(0);
wait(clk.posedge_event());
}
wait(); // wait next AW_master_event
}
}
void mW() {
ports.WVALID.write(0);
wait();
while (1) {
#ifdef VERBOSE
std::cout << std::endl << "===== " << this->name() << " Master W Channel (" << sc_time_stamp() << ")====" << std::endl;
std::cout << " W Channel simulation process wake up" << std::endl;
#endif
std::map<sc_uint<2>, AXITransaction*>::iterator it = activeWrites.begin();
if (it == activeWrites.end()) {
// error condition
// if activewrite is empty exit simulation
// fix master simulation process module
cout << "[" << sc_time_stamp() << "] Read transfer error occured" << endl;
cout << "activeWrites is empty" << endl;
exit(0);
}
for (; it != activeWrites.end(); ++it) {
sc_uint <2> master_id = it->second->ID;
sc_uint <32> start_addr = it->second->addr;
sc_uint <3> size = it->second->size;
sc_uint <2> type = it->second->type;
sc_uint <4> len = it->second->len;
for (int i = 0; i < len + 1; i++) {
bool WLAST = false;
if (i == len){
WLAST = true;
}
ports.WID.write(master_id);
ports.WDATA.write(write_buffer[i]);
ports.WLAST.write(WLAST);
ports.WVALID.write(1);
do {
wait(clk.posedge_event());
} while (ports.WREADY.read() == 0);
}
B_master_event.notify();
ports.WVALID.write(0);
ports.WLAST.write(0);
}
wait(); // wait next W_master_event
}
}
void mB() {
ports.BREADY.write(0);
wait();
while (1) {
ports.BREADY.write(1);
do {
wait(clk.posedge_event());
} while (ports.BVALID == 0); // wait until AWREADY 1
ports.BREADY.write(0);
write_transfer_done.notify();
wait(); // wait next B_master_event
}
}
int master_write(sc_uint<2> ID, sc_uint<32> addr, sc_uint<32> data, sc_uint<3> size, sc_uint<2> burst, sc_uint<4> len) {
AXITransaction* activeWrite = new AXITransaction;
activeWrite->ID = ID;
activeWrite->addr = addr;
activeWrite->size = size;
activeWrite->type = burst;
activeWrite->len = len;
write_buffer[0] = data;
activeWrites[ID] = activeWrite;
AW_master_event.notify();
wait(write_transfer_done); // wait for write if finish
return 0;
}
int master_write(sc_uint<2> ID, sc_uint<32> addr, sc_uint<32> * data, sc_uint<3> size, sc_uint<2> burst, sc_uint<4> len) {
AXITransaction* activeWrite = new AXITransaction;
activeWrite->ID = ID;
activeWrite->addr = addr;
activeWrite->size = size;
activeWrite->type = burst;
activeWrite->len = len;
for (int i = 0; i < len+1; i++) {
write_buffer[i] = data[i];
}
activeWrites[ID] = activeWrite;
AW_master_event.notify();
wait(write_transfer_done); // wait for write if finish
return 0;
}
sc_uint<32>* master_read(sc_uint<2> ID, sc_uint<32> addr, sc_uint<3> size, sc_uint<2> burst, sc_uint<4> len) {
AXITransaction* activeRead = new AXITransaction();
activeRead->ID = ID;
activeRead->addr = addr;
activeRead->size = size;//2; // Byte size, Default size is 4 bytes
activeRead->type = burst;//1; // increase burst only
activeRead->len = len;
AXI_master_if::activeReads[activeRead->ID] = activeRead;
AR_master_event.notify();
wait(read_transfer_done);
return read_buffer;
}
SC_CTOR(AXI_master_if) {
SC_THREAD(mAR); sensitive << AR_master_event;
SC_THREAD(mR); sensitive << R_master_event;
SC_THREAD(mAW); sensitive << AW_master_event;
SC_THREAD(mW); sensitive << W_master_event;
SC_THREAD(mB); sensitive << B_master_event;
}
};
#endif // AXI_master_if