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>
diff --git a/util/systemc/systemc_within_gem5/README b/util/systemc/systemc_within_gem5/README
index 6c743b9..af10fc4 100644
--- a/util/systemc/systemc_within_gem5/README
+++ b/util/systemc/systemc_within_gem5/README
@@ -26,6 +26,7 @@
 
 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
diff --git a/util/systemc/systemc_within_gem5/systemc_tlm/SConscript b/util/systemc/systemc_within_gem5/systemc_tlm/SConscript
new file mode 100644
index 0000000..62b9b1d
--- /dev/null
+++ b/util/systemc/systemc_within_gem5/systemc_tlm/SConscript
@@ -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')
diff --git a/util/systemc/systemc_within_gem5/systemc_tlm/config.py b/util/systemc/systemc_within_gem5/systemc_tlm/config.py
new file mode 100755
index 0000000..0d20e9e
--- /dev/null
+++ b/util/systemc/systemc_within_gem5/systemc_tlm/config.py
@@ -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))
diff --git a/util/systemc/systemc_within_gem5/systemc_tlm/sc_tlm.cc b/util/systemc/systemc_within_gem5/systemc_tlm/sc_tlm.cc
new file mode 100644
index 0000000..472e870
--- /dev/null
+++ b/util/systemc/systemc_within_gem5/systemc_tlm/sc_tlm.cc
@@ -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;
+}