#include <map>
#ifndef AXI_SLAVE_IF
#define AXI_SLAVE_IF
#include "AXI_SIGNAL_PORTS.h"
SC_MODULE(AXI_slave_if) {
public:
// slave interface ports
sc_in <bool> clk;
SLAVE_PORTS ports;
sc_uint <2> Rid;
sc_uint <4> Rlen;
sc_uint<32> read_buffer;
sc_uint <2> Wid;
sc_uint <4> Wlen;
sc_uint<32> write_buffer;
sc_event read_reg_event;
sc_event read_ready_event;
sc_event get_read_data_event;
sc_event set_read_data_event;
sc_event write_reg_event;
sc_event write_ready_event;
sc_event set_write_data_event;
sc_event write_resp_event;
sc_event R_slave_event;
sc_event W_slave_event;
sc_event B_slave_event;
sc_uint<32> baseAddr;
unsigned int addrRange;
std::map<sc_uint<2>, AXITransaction*> activeWrites;
std::map<sc_uint<2>, AXITransaction*> activeReads;
void sAR() {
ports.ARREADY.write(0);
wait(); // finish initialize phase
while (1) {
do {
wait(clk.posedge_event());//wait for arvalid signal high
} while (ports.ARVALID.read() == 0);
AXITransaction* activeRead = new AXITransaction();
activeRead->ID = ports.ARID.read();
activeRead->addr = ports.ARADDR.read();
activeRead->size = ports.ARSIZE.read();
activeRead->type = ports.ARBURST.read();
activeRead->len = ports.ARLEN.read();
activeReads[activeRead->ID] = activeRead;
read_reg_event.notify();
wait(read_ready_event);
ports.ARREADY.write(1);
wait(clk.posedge_event());
R_slave_event.notify();
ports.ARREADY.write(0);
wait(clk.posedge_event());
wait();
}
}
void sR() {
ports.RID.write(0);
ports.RDATA.write(0);
ports.RLAST.write(0);
ports.RVALID.write(0);
wait();
while (1) {
for (int i = 0; i < Rlen + 1; i++) {
sc_uint<32> data = read_buffer;
bool RLAST;
if (i == Rlen) { RLAST = true; }
else { RLAST = false; }
ports.RID.write(Rid);
ports.RDATA.write(data);
ports.RVALID.write(1);
ports.RLAST.write(RLAST);
do {
wait(clk.posedge_event());
} while (ports.RREADY.read() == 0);
get_read_data_event.notify();
if (i != Rlen) {
wait(set_read_data_event);
}
}
ports.RLAST.write(0);
ports.RVALID.write(0);
wait();
}
}
void sAW() {
ports.AWREADY.write(0);
wait();
while (1) {
while (ports.AWVALID.read() == 0){
wait(clk.posedge_event());//wait for arvalid signal high
}
AXITransaction* activeWrite = new AXITransaction();
activeWrite->ID = ports.AWID.read();
activeWrite->addr = ports.AWADDR.read();
activeWrite->size = ports.AWSIZE.read();
activeWrite->type = ports.AWBURST.read();
activeWrite->len = ports.AWLEN.read();
activeWrites[activeWrite->ID] = activeWrite;
write_reg_event.notify();
wait(write_ready_event);
ports.AWREADY.write(1);
wait(clk.posedge_event());
ports.AWREADY.write(0);
W_slave_event.notify();
wait();
}
}
void sW() {
ports.WREADY.write(0);
wait();
while (1) {
for (int i = 0; i < Wlen + 1; i++) {
ports.WREADY.write(1);
do {
wait(clk.posedge_event());
} while (ports.WVALID.read() == 0);
write_buffer = ports.WDATA.read();
set_write_data_event.notify();
ports.WREADY.write(0);
if (i != Rlen) {
wait(write_resp_event);
}
}
B_slave_event.notify();
ports.WREADY.write(0);
wait();
}
}
void sB() {
ports.BVALID.write(0);
wait();
while (1) {
std::map<sc_uint<2>, AXITransaction*>::iterator it = activeWrites.begin();
sc_uint<2> BID_val = it->second->ID;
ports.BID.write(BID_val);
ports.BVALID.write(1);
do {
wait(clk.posedge_event());
} while (ports.BREADY.read() == 0);
ports.BVALID.write(0);
wait();
}
}
// burst address calculate function
sc_uint<32> burst_addr_change( // Return next address
sc_uint<32> current_addr, // Current address
sc_uint<32> start_addr, // Initial address
sc_uint<3> bytes, // Initial address
sc_uint<2> type, // Burst type
sc_uint<4> burst_len // Burst size
) {
sc_uint<32> n_addr;
sc_uint<32> Wrap_Boundary = (sc_uint<32>(start_addr / (bytes * burst_len + 1))) * (bytes * burst_len + 1);
sc_uint<32> Address_N = Wrap_Boundary + (bytes * burst_len);
switch (type) {
case 0:
n_addr = start_addr;
break;
case 1:
n_addr = current_addr + ((sc_uint<32>)1 << bytes);
break;
case 2:
if (current_addr + bytes == Address_N) {
n_addr = Wrap_Boundary;
}
else
n_addr = current_addr + bytes;
break;
case 3:
#ifdef VERBOSE
cout << sc_time_stamp() << "Burst type error" << endl;
#endif
break;
default:
#ifdef VERBOSE
cout << sc_time_stamp() << "Burst type error" << endl;
#endif
break;
}
return n_addr;
}
// Slave interface constructor
SC_HAS_PROCESS(AXI_slave_if);
AXI_slave_if(sc_module_name _name, sc_uint<32> base_address, unsigned int address_range) :
sc_module(_name) {
// Initialize member variables with construct arguments
baseAddr = base_address;
addrRange = address_range;
// Register simulation processes
SC_THREAD(sAR); sensitive << ports.ARVALID;
SC_THREAD(sR); sensitive << R_slave_event;
SC_THREAD(sAW); sensitive << ports.AWVALID;
SC_THREAD(sW); sensitive << W_slave_event;
SC_THREAD(sB); sensitive << B_slave_event;
}
};
#endif // AXI_SLAVE_IF