systemc: Simple TLM Example added

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>
This commit is contained in:
Matthias Jung
2022-05-10 14:54:14 +02:00
committed by Matthias Jung
parent 3d5bb844ee
commit 4bc5efbc37
4 changed files with 350 additions and 0 deletions

View File

@@ -26,6 +26,7 @@ Existing examples:
systemc_sc_main - Run code based on an sc_main function.
systemc_simple_object - Build systemc objects into a gem5 object hierarchy.
systemc_tlm - Simple LT-Based TLM system
Note that these directories all have a systemc_ prefix so that when EXTRAS

View File

@@ -0,0 +1,28 @@
# Copyright 2018 Google, Inc.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# 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;
# neither the name of the copyright holders 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
# OWNER 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.
Import('*')
Source('sc_tlm.cc')

View File

@@ -0,0 +1,67 @@
# Copyright 2018 Google, Inc.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# 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;
# neither the name of the copyright holders 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
# OWNER 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.
import argparse
import m5
import sys
from m5.objects import SystemC_Kernel, Root
# pylint:disable=unused-variable
# The python version of the systemc kernel acts as an interface to sc_main. The
# c++ version of the kernel object has a lot of important jobs supporting
# systemc objects and needs to exist in simulations using systemc.
kernel = SystemC_Kernel()
root = Root(full_system=True, systemc_kernel=kernel)
parser = argparse.ArgumentParser()
parser.add_argument('--word', action="append", default=[],
help='Add a word to the list of words to print. Can be repeated.')
args = parser.parse_args()
# Tell gem5 to run the c++ sc_main function. If one isn't defined, gem5 will
# detect that and report an error. If gem5 isn't finding your sc_main, make
# sure its signature matches exactly so your compiler doesn't think it's a
# different function.
#
# The arguements passed to this function will be treated as the argv values
# passed to the c++ sc_main, with the argc value set appropriately.
m5.systemc.sc_main(*args.word);
# Construct the SimObject hierarchy. Anything sc_main built has already been
# constructed.
m5.instantiate(None)
# Run the simulation until something kicks us back to the config file. sc_main
# will be at the point it first called sc_start and may keep executing as the
# simulation runs, or it may be completed if it never called sc_start.
cause = m5.simulate(m5.MaxTick).getCause()
# If sc_main finished, extract what it returned and do something with it.
result = m5.systemc.sc_main_result()
if result.code != 0:
sys.exit(int(result.code))

View File

@@ -0,0 +1,254 @@
/*
* 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;
}