blob: 472e870a97a7b971d944359e42feefeed5db4aa6 [file] [log] [blame]
/*
* Copyright 2022 Fraunhofer IESE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <tlm_utils/simple_initiator_socket.h>
#include <tlm_utils/simple_target_socket.h>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <vector>
#include "base/trace.hh"
#include "systemc/ext/systemc"
#include "systemc/ext/tlm"
#define N 1024
using namespace std;
using namespace sc_core;
using namespace gem5;
SC_MODULE(Initiator)
{
public:
tlm_utils::simple_initiator_socket<Initiator> iSocket;
protected:
int data[16];
public:
SC_CTOR(Initiator): iSocket("iSocket")
{
SC_THREAD(process);
for (int i=0; i<16; i++) {
data[i] = 0;
}
}
protected:
void process()
{
sc_time delay;
for (int i = 0; i < N; i++)
{
tlm::tlm_generic_payload trans;
data[i % 16] = i;
trans.set_address(rand()%N);
trans.set_data_length(4);
trans.set_streaming_width(4);
trans.set_command(tlm::TLM_WRITE_COMMAND);
trans.set_data_ptr(reinterpret_cast<unsigned char*>(&data[i%16]));
trans.set_response_status( tlm::TLM_INCOMPLETE_RESPONSE );
sc_time delay = sc_time(10, SC_NS);
iSocket->b_transport(trans, delay);
if (trans.is_response_error())
{
SC_REPORT_FATAL(name(), "Response error");
}
wait(delay);
cout << "\033[1;31m("
<< name()
<< ")@" << setfill(' ') << setw(12) << sc_time_stamp()
<< ": " << setw(12) << "Write to "
<< "Addr = " << setfill('0') << setw(8)
<< dec << trans.get_address()
<< " Data = " << "0x" << setfill('0') << setw(8)
<< hex << data[i%16] << "(b_transport) \033[0m" << endl;
}
}
};
SC_MODULE(Target)
{
public:
tlm_utils::simple_target_socket<Target> tSocket;
private:
unsigned char mem[512];
public:
SC_HAS_PROCESS(Target);
Target(sc_module_name name, unsigned int bufferSize = 8) :
sc_module(name),
tSocket("tSocket")
{
tSocket.register_b_transport(this, &Target::b_transport);
}
virtual void b_transport(tlm::tlm_generic_payload& trans,
sc_time& delay)
{
executeTransaction(trans);
}
// Common to b_transport and nb_transport
void executeTransaction(tlm::tlm_generic_payload& trans)
{
tlm::tlm_command cmd = trans.get_command();
sc_dt::uint64 adr = trans.get_address();
unsigned char* ptr = trans.get_data_ptr();
unsigned int len = trans.get_data_length();
unsigned char* byt = trans.get_byte_enable_ptr();
unsigned int wid = trans.get_streaming_width();
if (trans.get_address() >= 512) {
trans.set_response_status( tlm::TLM_ADDRESS_ERROR_RESPONSE );
return;
}
if (byt != 0) {
trans.set_response_status( tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE );
return;
}
if (len > 4 || wid < len) {
trans.set_response_status( tlm::TLM_BURST_ERROR_RESPONSE );
return;
}
if (cmd == tlm::TLM_READ_COMMAND)
{
memcpy(&mem[trans.get_address()], // destination
trans.get_data_ptr(), // source
trans.get_data_length()); // size
}
else if (cmd == tlm::TLM_WRITE_COMMAND)
{
memcpy(trans.get_data_ptr(), // destination
&mem[trans.get_address()], // source
trans.get_data_length()); // size
}
cout << "\033[1;32m("
<< name()
<< ")@" << setfill(' ') << setw(12) << sc_time_stamp()
<< ": " << setw(12) << (cmd ? "Exec. Write " : "Exec. Read ")
<< "Addr = " << setfill('0') << setw(8) << dec << adr
<< " Data = " << "0x" << setfill('0') << setw(8) << hex
<< *reinterpret_cast<int*>(ptr)
<< "\033[0m" << endl;
trans.set_response_status( tlm::TLM_OK_RESPONSE );
}
};
template<unsigned int I, unsigned int T>
SC_MODULE(Interconnect)
{
public:
tlm_utils::simple_target_socket_tagged<Interconnect> tSocket[T];
tlm_utils::simple_initiator_socket_tagged<Interconnect> iSocket[I];
SC_CTOR(Interconnect)
{
for (unsigned int i = 0; i < T; i++) {
tSocket[i].register_b_transport(this,
&Interconnect::b_transport,
i);
}
}
private:
int routeFW(int inPort, tlm::tlm_generic_payload &trans)
{
int outPort = 0;
// Memory map implementation:
if (trans.get_address() < 512) {
outPort = 0;
} else if (trans.get_address() >= 512 && trans.get_address() < 1024) {
// Correct Address:
trans.set_address(trans.get_address() - 512);
outPort = 1;
} else {
trans.set_response_status( tlm::TLM_ADDRESS_ERROR_RESPONSE );
}
return outPort;
}
virtual void b_transport( int id,
tlm::tlm_generic_payload& trans,
sc_time& delay )
{
sc_assert(id < T);
int outPort = routeFW(id, trans);
iSocket[outPort]->b_transport(trans, delay);
}
};
int
sc_main (int __attribute__((unused)) sc_argc,
char __attribute__((unused)) *sc_argv[])
{
Initiator * cpu1 = new Initiator("C1");
Initiator * cpu2 = new Initiator("C2");
Target * memory1 = new Target("M1");
Target * memory2 = new Target("M2");
Interconnect<2,2> * bus = new Interconnect<2,2>("B1");
cpu1->iSocket.bind(bus->tSocket[0]);
cpu2->iSocket.bind(bus->tSocket[1]);
bus->iSocket[0].bind(memory1->tSocket);
bus->iSocket[1].bind(memory2->tSocket);
sc_core::sc_start();
return 0;
}