#include "AXI_SIGNAL_PORTS.h"
#include "Memory_map.h"
#include <map>
#include <string>
class AXI_BUS : public sc_module {
public:
// Member variables
sc_in<bool> clk;
SLAVE_PORTS* mPorts;
MASTER_PORTS* sPorts;
unsigned int master_num;
unsigned int slave_num;
typedef struct master_transaction_count {
unsigned int read;
unsigned int write;
}MASTER_TRANS_CNT;
MASTER_TRANS_CNT * trans_counter;
SC_HAS_PROCESS(AXI_BUS);
AXI_BUS(sc_module_name name_, int master_num, int slave_num)
: sc_module(name_),
master_num(master_num),
slave_num(slave_num)
{
//SC_THREAD(arbitrate);
//sensitive << clk.pos();
mPorts = new SLAVE_PORTS[master_num];
trans_counter = new MASTER_TRANS_CNT[master_num];
sPorts = new MASTER_PORTS[slave_num];
SC_METHOD(arbitrate);
sensitive << clk.pos();
for (int i = 0; i < master_num; ++i) {
sensitive << mPorts[i].ARVALID;
sensitive << mPorts[i].RVALID;
sensitive << mPorts[i].AWVALID;
sensitive << mPorts[i].WVALID;
sensitive << mPorts[i].WDATA;
sensitive << mPorts[i].BREADY;
trans_counter[i].read = 0;
trans_counter[i].write = 0;
}
for (int i = 0; i < slave_num; ++i) {
sensitive << sPorts[i].ARREADY;
sensitive << sPorts[i].RVALID;
sensitive << sPorts[i].RDATA;
sensitive << sPorts[i].AWREADY;
sensitive << sPorts[i].WREADY;
sensitive << sPorts[i].BVALID;
}
set_memory_map();
}
void arbitrate() {
for (int i = 0; i < master_num; ++i) {
if (mPorts[i].AWVALID.read() == 1) {
sc_uint<2> new_master_ID = mPorts[i].AWID.read();
sc_uint<32> new_master_addr = mPorts[i].AWADDR.read();
std::map<sc_uint<2>, AXITransaction*>::iterator it1;
std::map<sc_uint<2>, AXITransaction*>::iterator it2;
std::map<sc_uint<2>, AXITransaction*>::iterator it3;
bool is_new_write = true;
if (!writeB.empty()) {
it3 = writeB.find(i);
if (it3 != writeB.end()) {
if (it3->second->ID == new_master_ID &&
it3->second->addr == new_master_addr) {
is_new_write = false;
}
}
}
if (!writeData.empty()) {
it2 = writeData.find(i);
if (it2 != writeData.end()) {
if (it2->second->ID == new_master_ID &&
it2->second->addr == new_master_addr) {
is_new_write = false;
}
}
}
if (!writeReq.empty()) {
it1 = writeReq.find(i);
if (it1 != writeReq.end()) {
if (it1->second->ID == new_master_ID &&
it1->second->addr == new_master_addr) {
is_new_write = false;
}
}
}
if (is_new_write) {
AXITransaction* actWrite = new AXITransaction();
actWrite->ID = new_master_ID;
actWrite->addr = mPorts[i].AWADDR.read();
writeReq[i] = actWrite;
trans_counter[i].write++;
}
}
if (mPorts[i].ARVALID.read() == 1) {
sc_uint<2> new_master_ID = mPorts[i].ARID.read();
sc_uint<32> new_master_addr = mPorts[i].ARADDR.read();
std::map<sc_uint<2>, AXITransaction*>::iterator it1;
std::map<sc_uint<2>, AXITransaction*>::iterator it2;
bool is_new_read = true;
if (!readData.empty()) {
it2 = readData.find(i);
if (it2 != readData.end()) {
if (it2->second->ID == new_master_ID &&
it2->second->addr == new_master_addr) {
is_new_read = false;
}
}
}
if (!readReq.empty()) {
it1 = readReq.find(i);
if (it1 != readReq.end()) {
if (it1->second->ID == new_master_ID &&
it1->second->addr == new_master_addr) {
is_new_read = false;
}
}
}
if (is_new_read) {
//cout << "new read port num: " << i << endl;
//cout << "address: " << i << endl;
AXITransaction* activeRead = new AXITransaction();
activeRead->ID = new_master_ID;
activeRead->addr = mPorts[i].ARADDR.read();
activeRead->bus_allow = true;
readReq[i] = activeRead;
trans_counter[i].read++;
}
}
}
// AR Channel
if (!readReq.empty()) {
for (std::map<sc_uint<2>, AXITransaction*>::iterator i = readReq.begin(); i != readReq.end(); i++) {
// check same destination address
std::map<sc_uint<2>, AXITransaction*>::iterator j = i;
j++;
for (; j != readReq.end(); j++) {
if (find_slave_id(i->second->addr) == find_slave_id(j->second->addr)) {
// same destination address is exisit
if (trans_counter[i->first].read <= trans_counter[j->first].read)
j->second->bus_allow = false;
}
}
}
for (std::map<sc_uint<2>, AXITransaction*>::iterator it = readReq.begin(); it != readReq.end(); it++) {
if (it->second->bus_allow == true) {
sc_uint<2> current_master_port = it->first;
sc_uint<32> current_read_addr = it->second->addr;
int current_read_addr_slave = find_slave_id(current_read_addr); //find slave id
sync_master_n_slave_ar(current_master_port, current_read_addr_slave);
// Synchronize master and slave AR channels
if (mPorts[current_master_port].ARVALID.read() == 1) {
if (mPorts[current_master_port].ARREADY.read() == 1 &&
sPorts[current_read_addr_slave].ARVALID.read() == 1) {
// If all AW channel transfer is finished,
// delete AW transfer information and pass W channel transfer
it->second->ar_released = true;
}
}
if (it->second->ar_released && mPorts[current_master_port].ARVALID.read() == 0) {
readData[current_master_port] = readReq[current_master_port];
it++;
readReq.erase(readReq.find(current_master_port));
if (readReq.empty()) {
break;
}
else if (it != readReq.begin()) {
it--;
}
}
}
else {
it->second->bus_allow = true;
}
}
}
if (!readData.empty()) {
for (std::map<sc_uint<2>, AXITransaction*>::iterator i = readData.begin(); i != readData.end(); i++) {
// check same destination address
std::map<sc_uint<2>, AXITransaction*>::iterator j = i;
j++;
for (; j != readData.end(); j++) {
if (find_slave_id(i->second->addr) == find_slave_id(j->second->addr)) {
// same destination address is exisit
if (trans_counter[i->first].read <= trans_counter[j->first].read) {
j->second->bus_allow = false;
}
else {
i->second->bus_allow = false;
}
}
}
}
for (std::map<sc_uint<2>, AXITransaction*>::iterator it = readData.begin(); it != readData.end(); it++) {
if (it->second->bus_allow == true) {
sc_uint<2> current_master_port = it->first;
sc_uint<32> current_read_addr = it->second->addr;
int current_readData_slave = find_slave_id(current_read_addr); //find slave id
sync_master_n_slave_r(current_master_port, current_readData_slave);
// Synchronize master and slave AR channels
if (sPorts[current_readData_slave].RVALID.read() == 1) {
if (mPorts[current_master_port].RLAST.read() == 1 &&
mPorts[current_master_port].RVALID.read() == 1 &&
sPorts[current_readData_slave].RREADY.read() == 1) {
// If all W channel transfer is finished,
// delete W transfer information and pass B channel transfer
it->second->r_released = true;
}
}
if (it->second->r_released && mPorts[current_master_port].RVALID.read() == 0) {
it->second->r_released = false;
it++;
readData.erase(readData.find(current_master_port));
if (readData.empty()) {
break;
}
else if (it != readData.begin()) {
it--;
}
}
}
else {
it->second->bus_allow = true;
}
}
}
//AW channel
if (!writeReq.empty()) {
for (std::map<sc_uint<2>, AXITransaction*>::iterator i = writeReq.begin(); i != writeReq.end(); i++) {
// check same destination address
std::map<sc_uint<2>, AXITransaction*>::iterator j = i;
j++;
for (; j != writeReq.end(); j++) {
if (find_slave_id(i->second->addr) == find_slave_id(j->second->addr)) {
// same destination address is exisit
if (trans_counter[i->first].read <= trans_counter[j->first].read) {
j->second->bus_allow = false;
}
else {
i->second->bus_allow = false;
}
}
}
}
for (std::map<sc_uint<2>, AXITransaction*>::iterator it = writeReq.begin(); it != writeReq.end(); it++) {
if (it->second->bus_allow == true) {
sc_uint<2> current_master_port = it->first;
sc_uint<32> current_write_addr = it->second->addr;
int current_write_addr_slave = find_slave_id(current_write_addr); //find slave id
sync_master_n_slave_aw(current_master_port, current_write_addr_slave);
// Synchronize master and slave AW channels
if (mPorts[current_master_port].AWVALID.read() == 1) {
if (mPorts[current_master_port].AWREADY.read() == 1 &&
sPorts[current_write_addr_slave].AWVALID.read() == 1) {
// If all AW channel transfer is finished,
// delete AW transfer information and pass W channel transfer
it->second->aw_released = true;
}
}
if (it->second->aw_released &&
mPorts[current_master_port].AWVALID.read() == 0) {
writeData[current_master_port] = writeReq[current_master_port];
it++;
writeReq.erase(writeReq.find(current_master_port));
if (writeReq.empty()) {
break;
}
else if (it != writeReq.begin()) {
it--;
}
}
}
else {
it->second->bus_allow = true;
}
}
}
//W channel
if (!writeData.empty()) {
for (std::map<sc_uint<2>, AXITransaction*>::iterator i = writeData.begin(); i != writeData.end(); i++) {
// check same destination address
std::map<sc_uint<2>, AXITransaction*>::iterator j = i;
j++;
for (; j != writeData.end(); j++) {
if (find_slave_id(i->second->addr) == find_slave_id(j->second->addr)) {
// same destination address is exisit
if (trans_counter[i->first].read <= trans_counter[j->first].read) {
j->second->bus_allow = false;
}
else {
i->second->bus_allow = false;
}
}
}
}
for (std::map<sc_uint<2>, AXITransaction*>::iterator it = writeData.begin(); it != writeData.end(); it++) {
if (it->second->bus_allow == true) {
sc_uint<2> current_master_port = it->first;
sc_uint<32> current_write_addr = it->second->addr;
int current_writeData_slave = find_slave_id(current_write_addr); //find slave id
sync_master_n_slave_w(current_master_port, current_writeData_slave);
if (mPorts[current_master_port].WVALID.read() == 1) {
if (mPorts[current_master_port].WLAST.read() == 1 &&
mPorts[current_master_port].WVALID.read() == 1 &&
sPorts[current_writeData_slave].WREADY.read() == 1) {
// If all W channel transfer is finished,
// delete W transfer information and pass B channel transfer
it->second->w_released = true;
}
}
if (it->second->w_released &&
sPorts[current_writeData_slave].WVALID.read() == 0) {
writeB[current_master_port] = writeData[current_master_port];
writeData.erase(writeData.find(current_master_port));
if (writeData.empty()) {
break;
}
else if (it != writeData.begin()) {
it--;
}
}
else {
it->second->bus_allow = true;
}
}
}
}
//B channel
if (!writeB.empty()) {
for (std::map<sc_uint<2>, AXITransaction*>::iterator i = writeB.begin(); i != writeB.end(); i++) {
// check same destination address
std::map<sc_uint<2>, AXITransaction*>::iterator j = i;
j++;
for (; j != writeB.end(); j++) {
if (find_slave_id(i->second->addr) == find_slave_id(j->second->addr)) {
// same destination address is exisit
if (trans_counter[i->first].read <= trans_counter[j->first].read)
j->second->bus_allow = false;
}
}
}
for (std::map<sc_uint<2>, AXITransaction*>::iterator it = writeB.begin(); it != writeB.end(); it++) {
if (it->second->bus_allow == true) {
sc_uint<2> current_master_port = it->first;
sc_uint<32> current_write_addr = it->second->addr;
int current_writeB_slave = find_slave_id(current_write_addr);//find slave id
sync_master_n_slave_b(current_master_port, current_writeB_slave);
//wait(SC_ZERO_TIME);
//sync_master_n_slave_b(current_master_port, current_writeB_slave);
// Synchronize master and slave B channels
if (sPorts[current_writeB_slave].BVALID.read() == 1) {
if (mPorts[current_master_port].BREADY.read() == 1 &&
sPorts[current_writeB_slave].BVALID.read() == 1) {
// If all transfer is finished, delete transfer information
it->second->b_released = true;
}
}
if (it->second->b_released &&
mPorts[current_master_port].BVALID.read() == 0) {
it->second->b_released = false;
it++;
writeB.erase(writeB.find(current_master_port));
if (writeB.empty()) {
break;
}
else if (it != writeB.begin()) {
it--;
}
}
}
else {
it->second->bus_allow = true;
}
}
}
}
void sync_master_n_slave_ar(int master, int slave) {
//master output / slave input
sPorts[slave].ARID.write(mPorts[master].ARID.read());
sPorts[slave].ARADDR.write(mPorts[master].ARADDR.read());
sPorts[slave].ARLEN.write(mPorts[master].ARLEN.read());
sPorts[slave].ARSIZE.write(mPorts[master].ARSIZE.read());
sPorts[slave].ARBURST.write(mPorts[master].ARBURST.read());
sPorts[slave].ARVALID.write(mPorts[master].ARVALID.read());
mPorts[master].ARREADY.write(sPorts[slave].ARREADY.read());
}
void sync_master_n_slave_r(int master, int slave) {
//master output / slave input
sPorts[slave].RREADY.write(mPorts[master].RREADY.read());
mPorts[master].RID.write(sPorts[slave].RID.read());
mPorts[master].RDATA.write(sPorts[slave].RDATA.read());
mPorts[master].RLAST.write(sPorts[slave].RLAST.read());
mPorts[master].RVALID.write(sPorts[slave].RVALID.read());
}
void sync_master_n_slave_aw(int master, int slave) {
//master output / slave input
sPorts[slave].AWID.write(mPorts[master].AWID.read());
sPorts[slave].AWADDR.write(mPorts[master].AWADDR.read());
sPorts[slave].AWLEN.write(mPorts[master].AWLEN.read());
sPorts[slave].AWSIZE.write(mPorts[master].AWSIZE.read());
sPorts[slave].AWBURST.write(mPorts[master].AWBURST.read());
sPorts[slave].AWVALID.write(mPorts[master].AWVALID.read());
mPorts[master].AWREADY.write(sPorts[slave].AWREADY.read());
}
void sync_master_n_slave_w(int master, int slave) {
//master output / slave input
sPorts[slave].WID.write(mPorts[master].WID.read());
sPorts[slave].WDATA.write(mPorts[master].WDATA.read());
sPorts[slave].WLAST.write(mPorts[master].WLAST.read());
sPorts[slave].WVALID.write(mPorts[master].WVALID.read());
mPorts[master].WREADY.write(sPorts[slave].WREADY.read());
}
void sync_master_n_slave_b(int master, int slave) {
//master output / slave input
mPorts[master].BID.write(sPorts[slave].BID.read());
sPorts[slave].BREADY.write(mPorts[master].BREADY.read());
mPorts[master].BVALID.write(sPorts[slave].BVALID.read());
}
int find_slave_id(int addr) {
int tmp_addr = addr;
for (int i = 0; i < slave_num; i++) {
if (s_mm[i].base_addr <= tmp_addr &&
tmp_addr < s_mm[i].base_addr + s_mm[i].addr_size) {
return i;
}
}
return 16;
}
void set_memory_map() {
s_mm[0].base_addr = SLAVE_BASE_ADDR_00;
s_mm[0].addr_size = SLAVE_ADDR_SIZE_00;
s_mm[0].slave_id = 0;
s_mm[1].base_addr = SLAVE_BASE_ADDR_01;
s_mm[1].addr_size = SLAVE_ADDR_SIZE_01;
s_mm[1].slave_id = 1;
s_mm[2].base_addr = SLAVE_BASE_ADDR_02;
s_mm[2].addr_size = SLAVE_ADDR_SIZE_02;
s_mm[2].slave_id = 2;
s_mm[3].base_addr = SLAVE_BASE_ADDR_03;
s_mm[3].addr_size = SLAVE_ADDR_SIZE_03;
s_mm[3].slave_id = 3;
s_mm[4].base_addr = SLAVE_BASE_ADDR_04;
s_mm[4].addr_size = SLAVE_ADDR_SIZE_04;
s_mm[4].slave_id = 4;
s_mm[5].base_addr = SLAVE_BASE_ADDR_05;
s_mm[5].addr_size = SLAVE_ADDR_SIZE_05;
s_mm[5].slave_id = 5;
s_mm[6].base_addr = SLAVE_BASE_ADDR_06;
s_mm[6].addr_size = SLAVE_ADDR_SIZE_06;
s_mm[6].slave_id = 6;
s_mm[7].base_addr = SLAVE_BASE_ADDR_07;
s_mm[7].addr_size = SLAVE_ADDR_SIZE_07;
s_mm[7].slave_id = 7;
s_mm[8].base_addr = SLAVE_BASE_ADDR_08;
s_mm[8].addr_size = SLAVE_ADDR_SIZE_08;
s_mm[8].slave_id = 8;
s_mm[9].base_addr = SLAVE_BASE_ADDR_09;
s_mm[9].addr_size = SLAVE_ADDR_SIZE_09;
s_mm[9].slave_id = 9;
s_mm[10].base_addr = SLAVE_BASE_ADDR_10;
s_mm[10].addr_size = SLAVE_ADDR_SIZE_10;
s_mm[10].slave_id = 10;
s_mm[11].base_addr = SLAVE_BASE_ADDR_11;
s_mm[11].addr_size = SLAVE_ADDR_SIZE_11;
s_mm[11].slave_id = 11;
s_mm[12].base_addr = SLAVE_BASE_ADDR_12;
s_mm[12].addr_size = SLAVE_ADDR_SIZE_12;
s_mm[12].slave_id = 12;
s_mm[13].base_addr = SLAVE_BASE_ADDR_13;
s_mm[13].addr_size = SLAVE_ADDR_SIZE_13;
s_mm[13].slave_id = 13;
s_mm[14].base_addr = SLAVE_BASE_ADDR_14;
s_mm[14].addr_size = SLAVE_ADDR_SIZE_14;
s_mm[14].slave_id = 14;
s_mm[15].base_addr = SLAVE_BASE_ADDR_15;
s_mm[15].addr_size = SLAVE_ADDR_SIZE_15;
s_mm[15].slave_id = 15;
}
struct memory_map {
int base_addr;
int addr_size;
int slave_id;
};
std::map<sc_uint<2>, AXITransaction*> readReq;
std::map<sc_uint<2>, AXITransaction*> readData;
std::map<sc_uint<2>, AXITransaction*> writeReq;
std::map<sc_uint<2>, AXITransaction*> writeData;
std::map<sc_uint<2>, AXITransaction*> writeB;
struct memory_map s_mm[16];
};