510 likes | 771 Views
Modules and Processes in SystemC. A Presentation by: Najmeh Fakhraie Mozhgan Nazarian-Naeini Hardware-Software Codesign Spring 2006 . SystemC. The Nightmares of Citation. SystemC. References:.
E N D
Modules and Processes in SystemC A Presentation by: Najmeh Fakhraie Mozhgan Nazarian-Naeini Hardware-Software Codesign Spring 2006 SystemC
The Nightmares of Citation SystemC
References: • An Introduction to SystemC 1.0 : Bernard Niemann, Fraunhoffer Institute for Integrated Circuits • SystemC Tutorial: John Moondanos, Strategic CAD labs, Intel Corp. GSRC Visiting Fellow, UC Berkeley • SystemC 2.0.1 Language Reference Manual • SystemC Tutorial: Anonymous Author • Compositional Approach to SystemC Design : Semantics of SystemC : R.K Shyamasundar, IBM Research Lab • Doulos SystemC Tutorial • The NEW YORKER Cartoon Bank SystemC
Modules in SystemC • A module is the basic structural building block in SystemC. Modules may contain: • Ports • Data Members • Channel • Processes • Member functions not registered as processes • Instances of other modules • A new type of module is created by deriving from the container class sc_module • Publicly deriving from class sc_module. • Or alternatively, a module can be created with use of the SC_MODULE macro. SystemC
Modules in SystemC An example for the former would be: And an example for the latter: class my_module : public sc_module { .... }; SC_MODULE(my_module) { .... }; SystemC
Module Constructor • Every module can have a module constructor • Accepts one argument which is the module name • Will be thoroughly explained in the upcoming sections
Modules Instantiation • Instantiation develops hierarchy through out the design • Declaration SC_MODULE(ex2) { . . . ex1 ex1_instance; SC_CTOR(ex2) : ex1_instance(“ex1_anyname”) { //body } }; SystemC
Modules Instantiation • Pointer SC_MODULE(ex2) { . . . ex1 *ex1_instance; SC_CTOR(ex2) { ex1_instance = new ex1(“ex1_anyname”); //body } }; SystemC
Module Destructor SC_MODULE(ex2) { ~ex2() { delete ex1_instance; } }; SystemC
Processes in SystemC • An argument that begs the question: Processes are small pieces of code that run concurrently with other processes. • All high-level system level design (SLD) tools use an underlying model of a network of processes. • Functionality is described in processes. Processes must be contained within a module. • They are registered as processes with the SystemC kernel, using a process declaration in the module constructor. • Processes accept no arguments and produce no output SystemC
XOR Using Four NAND Gates SystemC
Step One: Modeling the NAND Gate • A NAND Gate is a combination circuit. Its output is purely a function of its input. • Use the simplest kind of SystemC process to model it: SC_METHOD. • SC_METHODs are simply C++ functions. Therefore, the SystemC class library must make them behave like processes, in particular: • The SystemC class library contains a simulation kernel – a piece of code that models the passing of time, and calls functions to calculate their outputs whenever their inputs change. • The function must be declared an SC_METHOD and made sensitive to its inputs. SystemC
NAND Gate #include "systemc.h" SC_MODULE(nand2) //declare nand2 sc_module { sc_in<bool> A, B; //input signal ports sc_out<bool> F; //output signal ports void do_nand2() //a C++ function { F.write( !(A.read() && B.read()) ); } SC_CTOR(nand2) { SC_METHOD(do_nand2); //register do_nand2 with kernel sensitive << A << B: //sensitivity list } }; SystemC
What just happened? • SC_MODULE: Hierarchy in SystemC is created by using a class sc_module. sc_module may be used directly, or may be “hidden” using the macro SC_MODULE. The example SC_MODULE above creates an sc_module class object called nand2. • Ports: SystemC numerous predefined ports such as sc_in<>, sc_out<>, sc_inout<>. The language also allows the definition of user defined ports through the use of the sc_port<> class. sc_port<sc_signal_in_if<bool>, 1> clk; SystemC
The NAND Function • do_nand2: • The function that does the work is declared. The input and output ports include methods read( ) and write( ) to allow reading and writing to the ports. A and B are read, the NAND function is calculated and the result is written to F using the write( ) method. • We could get away without writing the read( ) and write( ) methods by using operators: F = !( A && B); SystemC
Constructor for sc_module Instance nand2 SystemC provides a shorthand way of writing the constructor using a macro SC_CTOR. This constructor does the following: • Create hierarchy (none in this case) • Register functions as processes with the simulation kernel • Declare sensitivity list for processes • Accepts one argument only, which is the module name In this example, the constructor declares that do_nand2 is an SC_METHOD, and says that any event on ports A and B must make the kernel run the function (calculate a new value for F). SystemC
XOR Gate #include "systemc.h" #inclue "nand2.h" SC_MODULE(xor2) { sc_in<bool> A, B; sc_out<bool> F; nand2 n1, n2, n3, n4; sc_signal<bool> S1, S2, S3; SC_CTOR(xor2) : n1("N1"), n2("N2"), n3("N3"), n4("N4") { n1.A(A); n1.B(B); n1.F(S1); SystemC
XOR Gate (continued) n2 << A << S1 << S2; n3(S1); n3(B); n3(S3); n4.A(S2); n4.B(S3); n4.F(F); } }; SystemC
What just Happened II? • Header Files: • Note the inclusion of nand2.h. This allows access to the module containing the NAND gate. • Ports: • It is permitted to reuse the names A, B and F as this a different level of the hierarchy. • Declaring Intermediate Wires: • They are declared using sc_signal. sc_signal is a class with a template parameter specifying the type of data the signal can hold – bool in this example. It is a primitive, built-in channel with the SystemC library. SystemC
XOR Constructor • Must have four instances of nand2. After the port declarations, they are declared. And a label must be declared for each instance. • The four labels, N1, N2, N3 and N4 are passed to the constructors of the instances of nand2 by using an initializer list on the constructor of xor2. • Lastly, the ports are wired up. This can be done using parentheses “()” or “<<“ and “>>”. • Using “<<“ and “>>” only allows the ports and signals to be listed by position (n2). • Using “()” allows either by position (n3) or by name (n1 and n4). SystemC
More on Modules • They map functionality of HW/SW blocks • The basic building block of every system • Can contain a whole hierarchy of sub-modules and provide private variable/signals. • Modules can interface to each other via ports/interfaces/channels • Module functionality is achieved by means of processes SystemC
Module Hierarchy SystemC
Ports, Interfaces, Channels • Data transmitted and held via “channels” • Interfaces provide the operations that the channel provides • Ports standardize interaction of modules with the external world • At elaboration time, ports are BOUNDED to channels via interfaces SystemC
Interfaces • An interface consists of a set of operations (their “prototype”), not of their implementation which is a burden on the channels. • There are two basic interfaces derived from sc_interface class: • sc_signal_in_if<T> • provides a virtual functional read( ) returning a reference to T • sc_signal_inout_if<T> • provides a virtual functional write( ) taking a reference to T • an out interface is identical to an inout interface SystemC
Ports • They provide communication functions to modules • Derived from SystemC class sc_port<> • On the outside, they connect to channels by means of interfaces • Typical channel (in RTL mode): sc_signal • Specialized classes were derived: sc_in<class T>, sc_out<class T>, sc_inout<classT>, which are ports connected to N = 1 interfaces of type sc_signal_in_if<class T> • The interface sc_signal_in_if<> defines the restricted set of available messages that can be send to the port clk. For instance, the functions: read() or default_event() are defined by this class. SystemC
Channels • SystemC’s communication medium • This feature of SystemC differentiates it from other HDLs such as Verilog • Provides abstraction at the interface level of components and thus achieves greater design modeling flexibilities • By definition, modules are interconnected via channels and ports. • In turn, channels and ports communication via a common interface • Implementation of interfaces’ functions SystemC
Channels • Communication among modules and among processes within a module • Any channel must: • be derived from sc_channel class • be derived from one or more classes derived from sc_interface • provide implementations for all pure virtual functions defined in its parents interfaces SystemC
Fifo Example SystemC
FIFO: Declaration of Interfaces class write_if : public sc_interface { public: virtual void write(char) = 0; virtual void reset() = 0; }; class read_if : public sc_interface { public: virtual void read(char&) = 0; virtual int num_available() = 0; }; SystemC
FIFO: Declaration of Channel void write(char c) { if (fifo_full()) wait(read_event); data[ <you calculate> ] = c; ++num_elements; write_event.notify(); } void read(char &c) { if (fifo_empty()) wait(write_event); c = data[first]; --num_elements; first = ...; read_event.notify(); } class fifo: public sc_channel, public write_if, public read_if { private: int max_elements=10; char data[max_elements]; int num_elements, first; sc_event write_event, read_event; bool fifo_empty() {…}; bool fifo_full() {…}; public: fifo() : num_elements(0), first(0); SystemC
FIFO: Declaration of Channel void reset() { num_elements = first = 0; } int num_available() { return num_elements; } }; // end of class declarations SystemC
FIFO: Producer & Consumer SC_MODULE(producer) { public: sc_port<write_if> out; SC_CTOR(producer) { SC_THREAD(main); } void main() { char c; while (true) { out.write(c); if(…) out.reset(); } } }; SC_MODULE(consumer) { public: sc_port<read_if> in; SC_CTOR(consumer) { SC_THREAD(main); } void main() { char c; while (true) { in.read(c); cout<< in.num_available(); } } }; SystemC
FIFO Completed SC_MODULE(top) { public: fifo afifo; producer *pproducer; consumer *pconsumer; SC_CTOR(top) { pproducer=new producer(“Producer”); pproducer->out(afifo); pconsumer=new consumer(“Consumer”); pconsumer->in(afifo); } }; SystemC
More on Processes • They provide module functionality • Implemented as member functions of the module and declared to be SystemC process in SC_CTOR • Three kinds of process available: • SC_METHOD • SC_THREAD • SC_CTHREAD • These macros are needed because a member function is not necessarily a process. The macros operate specifics registrations with the scheduler • All these processes in the design run concurrently • Code inside of each process is sequential SystemC
SC_METHOD • Sensitive to any changes on input ports (i.e., it is sensitive to a set of signals, on its “sensitivity list. It can be sensitive to any change on a signal – e.g., the positive or negative edge of a Boolean signal). • Usually used to model purely combinational logic (i.e., NORs, NANDs, MUX) • Cannot be suspended. All the function code is executed every time the SC_METHOD is invoked (whenever any of the inputs it is sensitive to change). • Instructions are executed in order. • Does not remember internal state among invocations (unless explicitly kept in member variables) SystemC
Defining the Sensitivity List of a Process • sensitive with the ( ) operator • Takes a single port or signal as argument • sensitive(sig1); sensitive(sig2); sensitive(sig3); • sensitive with the stream notation • Takes an arbitrary number of arguments • sensitive << sig1 << sig2 << sig3; • sensitive_pos with either ( ) or << operator • Defines sensitivity to positive edge of Boolean signal or clock • sensitive_pos << clk; • sensitive_neg with either ( ) or << operator • Defines sensitivity to negative edge of Boolean signal or clock • sensitive_neg << clk; SystemC
SC_THREAD • Still has a sensitivity list and may be sensitive to any change on a signal. • It is reactivated whenever any of the inputs it is sensitive to changes. Once it is reactivated: • Instructions are executed infinitely fast (in terms of internal simulation time) until the next occurrence of a wait( ) statement. • Instructions are executed in order. • The next time the process is reactivated, the execution will continue after the wait( ) statement. • wait( ) suspends execution of the process until the process is invoked again SystemC
SC_THREAD • Akin to a Verilog initial block • Executes only once during simulation and then suspends • Designers commonly use an infinite loop inside an SC_THREAD to prevent it from ever exiting before the end of the simulation • Adds the ability to be suspended to SC_METHOD processes by means of wait() calls (and derivatives) • Remembers its internal state among invocations (i.e., execution resumes from where it was left) • Very useful for clocked systems, memory elements, multi-cycle behavior SystemC
An Example of SC_THREAD void do_count() { while(true) { if(reset) { value = 0; } else if (count) { value++; q.write(value); } wait(); } } SystemC
Thread Processes: wait( ) Function • wait( ) may be used in both SC_THREAD and SC_CTHREAD processes but not in SC_METHOD process block • wait( ) suspends execution of the process until the process is invoked again • wait(<pos_int>) may be used to wait for a certain number of cycles (SC_CTHREAD only) • In Synchronous process (SC_CTHREAD) • Statements before the wait( ) are executed in one cycle • Statements after the wait( ) executed in the next cycle • In Asynchronous process (SC_THREAD) • Statements before the wait( ) are executed in the last event • Statements after the wait( ) are executed in the next event SystemC
Another Example SC_MODULE(my_module) { sc_in<bool> id; sc_in<bool> clock; sc_in<sc_uint<3> > in_a; sc_in<sc_uint<3> > in_b; sc_out<sc_uint<3> > out_c; void my_thread(); SC_CTOR(my_module) { SC_THREAD(my_thread); sensitive << clock.pos(); } }; //my_module.cpp void my_module:: my_thread() { while(true) { if (id.read()) out_c.write(in_a.read()); else out_c.write(in_b.read()); wait(); } }; SystemC
SC_CTHREAD • Will be deprecated in future releases • Almost identical to SC_THREAD, but implements “clocked threads” • Sensitive only to one edge of one and only one clock • It is not triggered if inputs other than the clock change • Models the behavior of unregistered inputs and registered outputs • Useful for high level simulations, where the clock is used as the only synchronization device • Adds wait_until( ) and watching( ) semantics for easy deployment SystemC
SC_CTHREAD • Once invoked: • The statements execute until a wait( ) statement is encountered. • At the wait( ) statement, the process execution is suspended • At the next execution, process execution starts from the statement after the wait( ) statement • Local variables defined in the process function are saved each time the process is suspended SystemC
Counter in SystemC SystemC
Counter in SystemC SC_MODULE(countsub) { sc_in<double> in1; sc_in<double> in2; sc_out<double> sum; sc_out<double> diff; sc_in<bool> clk; void addsub(); //Constructor: SC_CTOR(addsub) { //Declare addsub as SC_METHOD SC_METHOD(addsub); dont_intialize(); //make it sensitive to positive clock sensitive_pos << clk; } }; //Definition of addsub method void countsub::addsub() { double a; double b; a = in1.read(); b = in2.read(); sum.write(a+b); diff.write(a-b); }; SystemC
The End SystemC