Change-Id: I2cb0c95773b8c6d15ffdffffaafbe3133a392a54 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/59549 Reviewed-by: Jason Lowe-Power <power.jg@gmail.com> Tested-by: kokoro <noreply+kokoro@google.com> Maintainer: Jason Lowe-Power <power.jg@gmail.com>
255 lines
7.5 KiB
C++
255 lines
7.5 KiB
C++
/*
|
|
* 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;
|
|
}
|