Jump to content

David Black

Members
  • Posts

    507
  • Joined

  • Last visited

  • Days Won

    116

Posts posted by David Black

  1. It is doubtful to support since it would devote too many resources (specification, design, implementation, security, verification, training) from too many companies (SYNOPSYS, Cadence, Siemens EDA, Aldec) for something of little real benefit (commercial and practical). Another language interface would fragment support for an already complex language. No thank you. 
     

    You can always use SWIG if you really feel the need. 
     

  2. Your observations are correct, but it really is not a problem. Even in Verilog you cannot do differently:

    // Verilog/SystemVerilog
    module Design( input CLK, AV, RD );
      always @(posedge CLK)
        if ( AV == 0 && RD == 1 ) begin
          WriteDataOut(...);
        end
    endmodule

    So in SystemC:

    #include <systemc>
    using namespace sc_core; //< Simplifying bad practice
    SC_MODULE(Design) {
      sc_in<bool> CLK, AV, RD
      SC_CTOR(Design) {
        SC_METHOD(main_method);
        sensitive << CLK.pos();
      }
      void main_method() {
        if( not AV->read() && RD->read() ) {
          WriteDataOut(...);
        }
      }
    };

    Event driven simulators trigger on events, not values.

    In case you get distracted, here is a solution that will not work despite appearances:

    #include <systemc>
    using namespace sc_core; //< Simplifying bad practice
    SC_MODULE(Design) {
      sc_in<bool> CLK, AV, RD
      SC_CTOR(Design) {
        SC_METHOD(main_method);
      }
      void main_method() {
        next_trigger( CLK->posedge_event() & AV->posedge_event() & RD->negedge_event()); //< not what you might think
        if( not AV->read() && RD->read() ) {
          WriteDataOut(...);
        }
      }
    };

    The & in the next trigger means that invocation will occur when all three events have happened; however, there is no requirement on when they occur. In other words, they won't be lined up correctly.

     

  3. It is not correct to bind a port to another port directly except in the case of a hierarchical connection. Furthermore, there is no such thing as an input port or an output port in SystemC. Ports are simply sophisticated pointers to channel objects that provide methods for exchanging information. Some methods are directional in nature by g to heir behavior. For instance, sc_signal<int>::write(value) deposits it’s contents into memory managed by the sc_signal<int> channel. 

  4. You did not post any error message, so it is practically impossible to answer your question. Perhaps you have run-time variables in the template parameters, which are strictly compile-time.

    In any case, this is not part of SystemC, but looks to possibly be part of an Intel FPGA package. SystemC identifiers generally begin with `sc_`. Consider:

    1. Take your question elsewhere (e.g., Intel FPGA forum)

    2. Look at the header file from whence it came and learn the C++ API from whence it came. If that does not make sense to you, then consider taking a course in C++.

  5. I concur with Eyck's comments. A few more thoughts:

    1. SystemC-processes are very different from OS processes.
    2. SystemC itself runs inside a single OS-thread.
    3. SystemC uses cooperative multitasking to simulate SystemC processes, which come in three flavors: SC_THREAD, SC_METHOD, and SC_CTHREAD (for synthesis).
      • This is common among discrete event-driven simulators (e.g., Verilog, SystemVerilog, and VHDL use the same idea)
      • Cooperative multitasking simplifies the coding a lot to make it easier for designers using these simulators.
    4. When documenting, I find it useful to keep these distinctions clear. To re-iterate:
      • OS-processes and OS-threads are preemptive in nature.
      • OS-threads live within the context of OS-processes. The primary distinction being that OS-threads share common resources (primarily memory).
      • SystemC-processes live within a single OS-thread.
      • SystemC-processes are not preemptive in nature, and must yield in order to allow other processes to run (i.e., cooperate to allow the simulation to proceed).
      • The distinction between SystemC-processes is the manner in which they yield to each other:
        • SC_THREAD-processes and SC_CTHREAD-processes yield by calling sc_core::wait().
        • SC_METHOD-processes yield by returning.
    5. When communicating between SystemC and an external OS-thread, SystemC events may only be invoked from within the context of the SystemC OS-thread. To inject an event, you may devise a primitive channel using async_request_update() to inject events via the update() method.
    6. C++11 provides an OS-agnostic library to create OS-threads, which is very handy.
    7. Keep in mind that data transfers between two processes must be carefully guarded using a proper mutex (available in C++11). I suggest you use a guarded mutex.
  6. That's an odd question since:

    1. SystemC is software (C++ actually).

    2. SystemC is used to model software running on hardware.

    So, most folks would model the hardware and use the software to validate the use cases. The next step would be to implement the hardware and then run the software on the real hardware. Some of the software used in a SystemC model would possibly be transformed into hardware (e.g., using an HLS synthesis tool such as Cadence Stratus, Siemens EDA's Catapult or Xilinx Vitis_HLS) or conventionally with RTL.

    Where is the software you ask? It depends on your approach to the modeling.

    1. In some cases, it is represented by code inside a thread that uses calls to access TLM. In that case, the calls would need to be replaced with direct hardware access (e.g., with memory mapped accesses using a pointer).

    2. In more traditional situations, the software would have been cross-compiled and run on an ISS wrapped into the SystemC model. Some companies even sell these.

  7. If you want real help, you need to show us the source code. At a minimum, we would need to see the signal declarationwithin its context, and the location of it's constructor and write method. If using a custom datatype, we need to know that definition. 

    Also, what compiler switches are used (e.g., -Wall -Wextra -std=?)? What compilation warnings are emitted?

    What version of SystemC?

     

     

     

  8. Suggestions:

    1. use stricter compilation rules such as -pedantic -Wall -Wextra and require all compilations to have zero warnings. This methodology will catch most errors. Use Ptah as to make exceptions around specific warnings you allow but only when you are certain and only for short code segments. 
    2. Switch from g++ to clang++
    3. Run static analysis and lint tools on your code 

    Consider using Jetbrains’ CLion toolset. Inexpensive for what it does. 

  9. Consider using a uvm_event from the uvm_event pool and possibly a uvm_event_callback.

    Monitor 1 sends a delayed event:

    task monitor1::run_phase( uvm_phase phase);
      My_transaction sent_txn;
      uvm_event sent_evt = uvm_event_pool::get_global_pool().get("my_timed_event");
      uvm_event rcvd_evt = uvm_event_pool::get_global_pool().get("my_received_event");
      forever begin
        ... collect transaction ...
        timeout: fork
          begin received_evt.wait_trigger(); disable timeout;
          #timeout evt.trigger( sent_txn );
        join_none
      end
    endtask: monitor1

    Monitor 2 sends received transaction:

    task monitor2::run_phase( uvm_phase phase);
      My_transaction rcvd_txn;
      uvm_event rcvd_evt = uvm_event_pool::get_global_pool().get("my_received_event");
      forever begin
        ... collect transaction ...
        rcvd_evt.trigger( rcvd_txn );
        ...
      end
    endtask: monitor2

    Scoreboard waits for either:

    task My_scoreboard::run_phase(uvm_phase);
      My_transaction txn;
      uvm_event sent_evt = uvm_event_pool::get_global_pool().get("my_timed_event");
      uvm_event rcvd_evt = uvm_event_pool::get_global_pool().get("my_received_event");
      forever begin
        bit timeout = 0;
        get_data: fork
          timed_out: begin
            sent_evt.wait_trigger();
            $cast( txn, sent_evt.get_trigger_data() );
            timeout = 1;
            disable received;
          end
          received: begin
            rcvd_evt.wait_trigger();
            $cast( txn, rcvd_evt.get_trigger_data() );
            disable timed_out;
          end
        join_any
        ...
      end
    endtask: My_scoreboard::run_phase

    You might need the callback to disable an event in flight.

×
×
  • Create New...