Jump to content

Eyck

Members
  • Posts

    356
  • Joined

  • Last visited

  • Days Won

    87

Everything posted by Eyck

  1. When posting code it is best to show an example using https://www.edaplayground.com. I copied part of ypur code at https://www.edaplayground.com/x/NSAs The problem is the missing initialization of m_trigger_flag. Depending of your build settings and many more factors it might be true or false. When being false the method is only executed during the initial evalauation phase....
  2. Eyck

    sc_signal

    Connecting a signal to a port can only happen before the simulation starts (before end_of_elaboartion() ). Signal manipulation can only happen during simulation. So the answer is no.
  3. This is a fairly complex topic. I try to summarize in a few sentences At first you need to define what your requirements are. Let's assume you have a piece of software which needs to run at a certain speed. So the most important factors to this is the perfomance of the processor in terms of instruction per cycle and the performance of the interconnect and memory subsystem in terms of bandwidth and latency. In the next step you need to gather or develop respective models running in cycle-approximate (CA) or cycle-accurate (CT) mode. They need to provide means to collect the timing information like signal and transaction traces. Then you setup test runs and collect the information. In a postprocessing step you can then calculate the relevant measures and check them against your requirements. Now you can reconfigure your elements until the measures fulfill the requirements. Important here is that you need CA or CT models for the interconnect(s) and the processors. If using TLM2.0 based AMBA interfaces, you might have a look at https://github.com/Arteris-IP/tlm2-interfaces which is also integrated into https://github.com/Minres/SystemC-Components which provides a few more AT protocol implementations on top.
  4. One example is a APB initiator: https://github.com/Minres/SystemC-Components/blob/develop/src/bus_interfaces/apb/pe/apb_initiator.cpp#L40 for the notification and https://github.com/Minres/SystemC-Components/blob/develop/src/bus_interfaces/apb/pe/apb_initiator.cpp#L63 for pulling entries
  5. I don't think so. Although you call notify with a reference it internally stores the pointer to to the object. You as modeler are in charge of the lifetime of the object pointed to. So if you have a shared_ptr with local lifetime (which is the use-model of a shared_ptr) the peq has a danglng pointer once the local shared_ptr is destroyed (not the object it pointed to). This is one reason we wrote our own peq at https://github.com/Minres/SystemC-Components/blob/main/src/sysc/scc/peq.h
  6. The prblem is the use of plain C datatypes for communication. Although SystemC simulates parallel exeution everything is executed in a sequential manner. When clk has a rising edge thread_1 as well as thread_2 have to be executed in the evalauation phase an the SystemC kernel decides in which order. Now if thread_1 executes first the value change of wait_t_2 is immediatley seen in thread_1 (and vice versa). Therefore you need an element which defers the value update until the next evaluation phase. This element is a signal.... So you sould use sc_core::signal<bool> instead of a bool.
  7. If these things are modeled to consume time then it will be reflected....
  8. Without any code this is impossible to answer. You may use https://www.edaplayground.com/ for this or post it here.
  9. You are using a signal (via a port) and expect an immediate update of the value. This is true for plain C++ data types but not for signals. Signals provide the value (via read() ) being written in the next delta cycle. Please consult the SystemC LRM or some books about SystemC...
  10. Eventually all modules in a common SystemC design have the same parent wiich is sc_main. So the example still aplies. If you have hierarchies you can use ports to connect up and down.
  11. If you really model the performance and timing relevant details of AXI4 the TLM2.0 base protocol is not sufficient. This is due things like burst beats, interleaving, and alike. This means you need to align with your customer on a protocol specification/implementation. You may find such a specification at https://github.com/Arteris-IP/tlm2-interfaces/blob/develop/doc/axitlm/axi_tlm2_spec.pdf. There you also find an implementation of the protocol at https://github.com/Arteris-IP/tlm2-interfaces/blob/develop/axi/axi_tlm.h This interface definition is in productive use by commercial IP suppliers which means it is fairly complete and tested. So this might ease the discussion with your customer to agree on the use of the interface defintion.
  12. Actually there is no requirement to use TLM2.0 for any communication. You can mix and match with your use model. TLM2.0 is intended to model bus based communication. So for example interrups, gpio, or alike is nothing to model in TLM2.0. When starting to model AXI4 you might want to have a look at https://github.com/Arteris-IP/tlm2-interfaces which provides a complete AT implementation of the AXI4, ACE, and ACELite protocol incl. protocol engines and targets. This might gitve you a jump start and avoids 'yet another' implementation. If you miss a feature you are encuraged to file enhancement tickets. Additionaly at https://github.com/Minres/SystemC-Components/tree/develop/src/bus_interfaces/axi you will find complete drivers and pin-level adapters which allows to connect the AT-TLM to RTL interfaces (the library uses the tlm2-interfaces repo under the hood. At https://github.com/Minres/SystemC-Components/tree/develop/examples you find also simple examples on how to use the AXI4 implementation and the pin-level adapters.
  13. Hmm, I guess you lost me a bit. If you want to stop the kernel to process further event and advance time you just need to not return control to the kernel e.g. waiting for a socket event. After receiving soemthing you need to return control to the SC kernel by calling wait(). If the processing needs some SystemC time to happen you need to allow the kernel to advance. Waiting for an event is not a halt for the simulation kernel, it is just a halt for the thread calling the wait since you return control to the kernel.
  14. Actually you try to call an array operator for the port i_i in mux_4_to_1. This does not access the respective bit in the data but the n-th interface of a (potential) multi-port. So you need to do a explcit read to the the sc_bit and then an array access: // Multiplexer Logic void mux(){ // Convert bit vector to int int select_value = s_i.read().to_uint(); auto in_val = i_i.read(); switch(select_value){ case 0 : y_o.write(in_val[0]); break; case 1 : y_o.write(in_val[1]); break; case 2 : y_o.write(in_val[2]); break; case 3 : y_o.write(in_val[3]); break; default : y_o.write(false); } } There are several other things to your code: You should use C++11 You should name your ports and signals. Using C++11 this would look like sc_out<sc_bv<4>> i_i{"i_i"}; This eases debugging (and tracing). sc_main should only instantiate the toplevel module/testbench. No structural code and no signals in sc_main. This eases reuse of modules and porting it to other simulators (Synopsys, SiemensEDA, or Cadence). The only other code should be paring command line arguments, setting up tracing/logging, starting simulation and evaluating the results. It also unifies your sc_main across different models. Maros SC_CTOR and SC_MODULE are discuraged and, as far as I know, will be deprecated and removed from future standards. The do not add substantial functionality.
  15. Well, your solution should work as well. But as far as I can tell your simulation will reach quite soon large timestamps as there is nothing preventing the SC kernel from continueing since your main thread in Foo just does a wait(). My proposal was to let the simulaton wait until some external event is being injected and then run for a certain period of time. This way you can control the time advance in the simulator.
  16. This strongly depends on how you struture your testbench. We presented a poster (and had a talk) about using UVM-SystemC to verify a processor (teh pdf can be found here: https://riscv-europe.org/media/proceedings/posters/2023-06-07-Stanislaw-KAUSHANSKI-abstract.pdf). We chose to have TLM2.0 as the VIF which allowed us to hook-up the testbench with a verilated representation of the desing as well as an HDL Simulator or even some FPGA based solution. This way we can re-use the entire tesbench at different abstraction levels.
  17. I'd rather use dynamic_cast<producer*> as it checks that the pointer is of correct type. If not it returns a nullptr sp you might have to check this before using it. And you should publicly inherit of blockBase. Did you have a look at UVM-SystemC (https://systemc.org/overview/systemc-verification/)? There all those mechanics are available and well testet. And its purpose is to structure verification environments and testbenches...
  18. The SystemC kernel is not aware of 'external' events. So if it does not have any further event to process it will finish the simulation. A solution to this might be keep your polling event but extend the logic a bit: while (1) { wait(10, SC_NS); wait(async_event); } This async_event is something like the ThreadSafeEvent in the post you referenced. This way you block the SysremC kernel until you get an external event and then let it run for 10ns.
  19. You have to use ports and signals or fifos. If you have a look at https://agra.informatik.uni-bremen.de/doc/lehrmat/sose03/qhe/6_sc_20.pdf slide 15 you will see a complete example. sc_signal works in a similar fashion except there are specialized ports called sc_in/so_out/sc_inout.
  20. Did you try using Verilator with its SystemC wrapper? Not everyone has access to Quartus or wants to install it. And it removes the burden to have a co-simulation...
  21. This library gets automatically build when you build the libsystemc either using cmake or the autoconf tools according to the documentation. This package is used by SystemC to implement SC_THREADs so it will be part of libsystemc
  22. Not of a NoC but a router for LT traffic: https://github.com/Minres/SystemC-Components/blob/develop/src/components/scc/router.h Besides tlm::scc::initiator_mixin<tlm::tlm_initiator_socket<BUSWIDTH>> (and respective target socket) you might use tlm_utils::simple_initiator_socket<...> which work similar.
  23. If you write to the signal a copy of pkt is stored. This is C++ value semantics. Even an implementation like this void main() { while (true) { pkt p(64); out->write(p); wait(p.len/rate, SC_NS); } } works correcty and even better than yours as you created a memory leak. Since at the reassignment of p using new the previously allocated memory gets lost. Better to use a std::unique_ptr. I highly suggest to revive your C++ knowledge based on a modern C++ standard (C++11 or better C++17).
  24. To your orginal question: yes, you can use multi-passthrough sockets to model a NoC. You need to implement the AT protocol (depending on the socket id) and bind it to the sockets, there is no difference. There is one drawback you might encounter: if you need to hierarchically bind the sockets of your NoC and split the connections this will not be possible.This is because multi_passthrough_target_socket does not bind to tlm::target_socket, only to tlm::initialtor_socket. Therefore my suggestion to use a sc_vector of TLM sockets...
×
×
  • Create New...