cpe 626 the systemc language aleksandar milenkovic web:milenkamilenka
DESCRIPTION
A. Milenkovic 3 Standard Methodology for ICs System-level designers write a C or C++ model Written in a stylized, hardware-like form Sometimes refined to be more hardware-like C/C++ model simulated to verify functionality Parts of the model to be implemented in hardware are given to Verilog/VHDL coders Verilog or VHDL specification written Models simulated together to test equivalence Verilog/VHDL model synthesizedTRANSCRIPT
CPE 626 The SystemC Language
Aleksandar MilenkovicE-mail: [email protected]: http://www.ece.uah.edu/~milenka
A. Milenkovic 2
Outline Motivation for SystemC What is SystemC? Modules Processes
A. Milenkovic 3
Standard Methodology for ICs System-level designers write a
C or C++ model Written in a stylized,
hardware-like form Sometimes refined to be
more hardware-like C/C++ model simulated to
verify functionality Parts of the model to be implemented in
hardware are given to Verilog/VHDL coders Verilog or VHDL specification written Models simulated together to test equivalence Verilog/VHDL model synthesized
A. Milenkovic 4
Designing Big Digital Systems Current conditions
Every system company was doing this differently Every system company used its own simulation library System designers don’t know Verilog or VHDL Verilog or VHDL coders don’t understand system design
Problems with standard methodology: Manual conversion from C to HDL
o Error prone and time consuming Disconnect between system model and HDL model
o C model becomes out of date as changes are made only to the HDL model
System testingo Tests used for C model cannot be run against HDL model =>
they have to be converted to the HDL environment
A. Milenkovic 5
Idea of SystemC C and C++ are being used as
ad-hoc modeling languages Why not formalize their use? Why not interpret them as
hardware specification languages just as Verilog and VHDL were?
SystemC developed at Synopsys to do just this
A. Milenkovic 6
SystemC Design Methodology Refinement methodology
Design is slowly refined in small sections to add necessary hardware and timing constructs
Written in a single language higher productivity due to
modeling at a higher level testbenches can be reused
saving time
Future releases will have constructs to model RTOS
A. Milenkovic 7
What Is SystemC? A subset of C++ that models/specifies
synchronous digital hardware A collection of simulation libraries that can be used
to run a SystemC program A compiler that translates
the “synthesis subset” of SystemC into a netlist
A. Milenkovic 8
What Is SystemC? Language definition is publicly available
Libraries are freely distributed
Compiler is an expensive commercial product
See www.systemc.org for more information
A. Milenkovic 9
Quick Overview A SystemC program consists of module definitions
plus a top-level function that starts the simulation Modules contain processes (C++ methods) and
instances of other modules Ports on modules define their interface
Rich set of port data types (hardware modeling, etc.) Signals in modules convey information between instances Clocks are special signals that run periodically and
can trigger clocked processes Rich set of numeric types
(fixed and arbitrary precision numbers)
A. Milenkovic 10
Modules Hierarchical entity Similar to Verilog’s module
Actually a C++ class definition
Simulation involves Creating objects of this class They connect themselves together Processes in these objects (methods) are called
by the scheduler to perform the simulation
A. Milenkovic 11
Modules
SC_MODULE(mymod) { // struct mymod : sc_module { /* port definitions */ /* signal definitions */ /* clock definitions */
/* storage and state variables */
/* process definitions */
SC_CTOR(mymod) { /* Instances of processes and modules */ }};
A. Milenkovic 12
Ports Define the interface to each module Channels through which data is communicated Port consists of a direction
input sc_in output sc_out bidirectional sc_inout
and any C++ or SystemC type
SC_MODULE(mymod) { sc_in<bool> load, read; sc_inout<int> data; sc_out<bool> full;
/* rest of the module */};
A. Milenkovic 13
Signals Convey information between modules within a module Directionless: module ports define direction of data transfer Type may be any C++ or built-in type
SC_MODULE(mymod) { /* port definitions */ sc_signal<sc_uint<32> > s1, s2; sc_signal<bool> reset;
/* … */ SC_CTOR(mymod) { /* Instances of modules that connect to the signals */ }};
A. Milenkovic 14
Instances of Modules Each instance is a pointer to an object in the module
Connect instance’s ports to signals
SC_MODULE(mod1) { … };SC_MODULE(mod2) { … };SC_MODULE(foo) { mod1* m1; mod2* m2; sc_signal<int> a, b, c; SC_CTOR(foo) { m1 = new mod1(“i1”); (*m1)(a, b, c); m2 = new mod2(“i2”); (*m2)(c, b); }};
A. Milenkovic 15
Positional Connection// filter.h#include "systemc.h“ // systemC classes#include "mult.h“ // decl. of mult#include "coeff.h“ // decl. of coeff#include "sample.h“ // decl. of sampleSC_MODULE(filter) { sample *s1; // pointer declarations coeff *c1; mult *m1; // signal declarations sc_signal<sc_uint<32> > q, s, c; SC_CTOR(filter) { // constructor s1 = new sample ("s1"); // create obj. (*s1)(q,s); // signal mapping c1 = new coeff ("c1"); (*c1)(c); m1 = new mult ("m1"); (*m1)(s,c,q); }}
A. Milenkovic 16
Named Connection#include "systemc.h“ // systemC classes#include "mult.h“ // decl. of mult#include "coeff.h“ // decl. of coeff#include "sample.h“ // decl. of sampleSC_MODULE(filter) { sample *s1; coeff *c1; mult *m1; sc_signal<sc_uint<32> > q, s, c; SC_CTOR(filter) { s1 = new sample ("s1"); s1->din(q); // din of s1 to signal q s1->dout(s); // dout to signal s c1 = new coeff ("c1"); c1->out(c); // out of c1 to signal c m1 = new mult ("m1"); m1->a(s); // a of m1 to signal s m1->b(c); // b of m1 to signal c m1->q(q); // q of m1 to signal c }}
A. Milenkovic 17
Internal Data Storage Local variables to store data within a module May be of any legal C++, SystemC, or user-defined type Not visible outside the module unless it is made explicitly// count.h#include "systemc.h"SC_MODULE(count) { sc_in<bool> load; sc_in<int> din; // input port sc_in<bool> clock; // input port sc_out<int> dout; // output port
int count_val; // internal data storage void count_up(); SC_CTOR(count) { SC_METHOD(count_up); //Method process sensitive_pos << clock; }};
// count.cc#include "count.h"void count::count_up() { if (load) { count_val = din; } else { // could be count_val++ count_val = count_val + 1; } dout = count_val;}
A. Milenkovic 18
Processes Only thing in SystemC that actually does anything
Functions identified to the SystemC kernel and called whenever signals these processes are sensitive to change value
Statements are executed sequentially until the end of the process occurs, or the process is suspended using wait function
Very much like normal C++ methods + Registered with the SystemC kernel
Like Verilog’s initial blocks
A. Milenkovic 19
Processes (cont’d) Processes are not hierarchical
no process can call another process directly can call other methods and functions that are not processes
Have sensitivity lists signals that cause the process to be invoked,
whenever the value of a signal in this list changes Processes cause other processes to execute
by assigning new values to signals in the sensitivity lists of the processes
To trigger a process, a signal in the sensitivity list of the process must have an event occur
A. Milenkovic 20
Three Types of Processes
METHOD Models combinational logic
THREAD Models testbenches
CTHREAD Models synchronous FSMs
Determines how the process is called and executed
A. Milenkovic 21
METHOD Processes Triggered in response to changes on inputs
Cannot store control state between invocations
Designed to model blocks of combinational logic
A. Milenkovic 22
METHOD Processes
Process is simply a method of this class
Instance of this process created
and made sensitive to an input
SC_MODULE(onemethod) { sc_in<bool> in; sc_out<bool> out;
void inverter();
SC_CTOR(onemethod) {
SC_METHOD(inverter); sensitive(in);
}};
A. Milenkovic 23
METHOD Processes Invoked once every time input “in” changes
Should not save state between invocations
Runs to completion: should not contain infinite loops Not preempted
Read a value from the port
Write a value to an output port
void onemethod::inverter() { bool internal; internal = in; out = ~internal;}
A. Milenkovic 24
THREAD Processes Triggered in response to changes on inputs
Can suspend itself and be reactivated Method calls wait() function that suspends process execution Scheduler runs it again when an event occurs
on one of the signals the process is sensitive to
Designed to model just about anything
A. Milenkovic 25
THREAD Processes
Process is simply a method of this class
Instance of this process created
alternate sensitivity list notation
SC_MODULE(onemethod) { sc_in<bool> in; sc_out<bool> out;
void toggler();
SC_CTOR(onemethod) {
SC_THREAD(toggler); sensitive << in; }
};
A. Milenkovic 26
THREAD Processes Reawakened whenever an input changes
State saved between invocations
Infinite loops should contain a wait()
Relinquish control until the next change of a signal on the sensitivity list for this process
void onemethod::toggler() { bool last = false; for (;;) { last = in; out = last; wait(); last = ~in; out = last; wait(); }}
A. Milenkovic 27
CTHREAD Processes Triggered in response to a single clock edge
Can suspend itself and be reactivated Method calls wait to relinquish control Scheduler runs it again later
Designed to model clocked digital hardware
A. Milenkovic 28
CTHREAD Processes
Instance of this process created and relevant clock edge assigned
SC_MODULE(onemethod) { sc_in_clk clock; sc_in<bool> trigger, in; sc_out<bool> out;
void toggler();
SC_CTOR(onemethod) {
SC_CTHREAD(toggler, clock.pos()); }
};
A. Milenkovic 29
CTHREAD Processes Reawakened at the edge of the clock State saved between invocations Infinite loops should contain a wait()
Relinquish control until the next clock cycle
Relinquish control until the next clock cycle in which the trigger input is 1
void onemethod::toggler() { bool last = false; for (;;) { wait_until(trigger.delayed() == true); last = in; out = last; wait(); last = ~in; out = last; wait(); }}
A. Milenkovic 30
A CTHREAD for Complex Multiplystruct complex_mult : sc_module { sc_in<int> a, b, c, d; sc_out<int> x, y; sc_in_clk clock;
void do_mult() { for (;;) { x = a * c - b * d; wait(); y = a * d + b * c; wait(); } }
SC_CTOR(complex_mult) { SC_CTHREAD(do_mult, clock.pos()); }};
A. Milenkovic 31
Put It All Together
Process Type SC_METHOD SC_THREAD SC_CTHREAD
Exec. Trigger Signal Events Signal Events Clock EdgeExec.Suspend
NO YES YES
Infinite Loop NO YES YESSuspend / Resume by
N.A. wait() wait()wait_until()
Construct &SensitizeMethod
SC_METHOD(call_back);sensitive(signals);sensitive_pos(signals);sensitive_neg(signals);
SC_THREAD(call_back);sensitive(signals);sensitive_pos(signals);sensitive_neg(signals);
SC_CTHREAD(call_back,clock.pos());SC_CTHREAD(call_back,clock.neg());
A. Milenkovic 32
Watching SC_THREAD and SC_CTHREAD processes typically
have infinite loops that will continuously execute Use watching construct to jump out of the loop Watching construct will monitor a specified condition When condition occurs control is transferred
from the current execution point to the beginning of the process
A. Milenkovic 33
Watching: An Example// datagen.h#include "systemc.h"SC_MODULE(data_gen) { sc_in_clk clk; sc_inout<int> data; sc_in<bool> reset; void gen_data(); SC_CTOR(data_gen){ SC_CTHREAD(gen_data, clk.pos()); watching(reset.delayed() == true); }};
// datagen.cc#include "datagen.h"void gen_data() { if (reset == true) { data = 0; } while (true) { data = data + 1; wait(); data = data + 2; wait(); data = data + 4; wait(); }}
Watching expressions are tested at the wait() or wait_until() calls.
All variables defined locally will lose their value on the control exiting.
A. Milenkovic 34
Local Watching Allows us to specify exactly
which section of the process is watching which signal, and where event handlers are located
W_BEGIN// put the watching declarations herewatching(...);watching(...);W_DO// This is where the process functionality goes...W_ESCAPE// This is where the handlers // for the watched events goif (..) {...}W_END
W_BEGIN macro marks the beginning of the local watching block.
W_BEGIN – W_DO: watching declarations
W_DO – W_ESCAPE:process functionality
W_ESCAPE – W_END:event handlers
W_END macro ends local watching block
A. Milenkovic 35
Local Watching Rules All of the events in the declaration block have the same
priority. If a different priority is needed then local watching blocks will need to be nested
Local watching only works in SC_CTHREAD processes The signals in the watching expressions are sampled only
on the active edges of the process. In an SC_CTHREAD process this means only when the clock that the process is sensitive to changes
Globally watched events have higher priority than locally watched events
A. Milenkovic 36
D-FF in SystemC
// dff.h#include "systemc.h"SC_MODULE(dff) { sc_in<bool> din; // data input sc_in<bool> clock; // clock input sc_out<bool> dout; // data output
void doit(); // method in the module SC_CTOR(dff) { // constructor SC_METHOD(doit); // doit type is SC_METHOD // method will be called whenever a // positive edge occurs on port clock sensitive_pos << clock; }};
// dff.cc#include "dff.h"void dff::doit() { dout = din;}
A. Milenkovic 37
Bus Controller in SystemC Assumptions
32-bit internal data path; 8-bit external data path every address and data transaction
will have to be multiplexed over the 8-bit bus Protocol
32-bit address is sent to the bus controller (BC) process address will be multiplexed byte by byte and sent to MC bus controller will wait for ready signal from memory receive the data send the data to microcontroller
A. Milenkovic 38
Bus Controller: bus.h// bus.h#include "systemc.h"SC_MODULE(bus) { sc_in_clk clock; sc_in<bool> newaddr; sc_in<sc_uint<32> > addr; sc_in<bool> ready; sc_out<sc_uint<32> > data; sc_out<bool> start; sc_out<bool> datardy; sc_inout<sc_uint<8> > data8; sc_uint<32> tdata; sc_uint<32> taddr; void xfer(); SC_CTOR(bus) { SC_CTHREAD(xfer, clock.pos()); // ready to accept new address datardy = true; }};
A. Milenkovic 39
Bus Controller: bus.cc// bus.cc#include "bus.h"void bus::xfer() { while (true) { // wait for a new address to appear wait_until( newaddr.delayed() == true); // got a new address so process it taddr = addr.read(); datardy = false; // cannot accept new address now data8 = taddr.range(7,0); start = true; // new addr for memory controller wait(); // wait 1 clock between data transfers data8 = taddr.range(15,8); start = false; wait(); data8 = taddr.range(23,16); wait(); data8 = taddr.range(31,24); wait();
A. Milenkovic 40
Bus Controller: bus.cc (cont’d)
// now wait for ready signal from memory controller wait_until(ready.delayed() == true); // now transfer memory data to databus tdata.range(7,0) = data8.read(); wait(); tdata.range(15,8) = data8.read(); wait(); tdata.range(23,16) = data8.read(); wait(); tdata.range(31,24) = data8.read(); data = tdata; datardy = true; // data is ready, new addresses ok }}
A. Milenkovic 41
Local Watching Example Modify bus controller
by allowing the bus controller to be interrupted during the transfer from the memory but not to the memory
... // now wait for ready signal from memory controller wait_until(ready.delayed() == true);
A. Milenkovic 42
Local Watching Example W_BEGIN watching(reset.delayed()); // Active value of reset will trigger watching W_DO // the rest of this block is as before tdata.range(7,0) = data8.read(); // now transfer memory data to databus wait(); tdata.range(15,8) = data8.read(); wait(); tdata.range(23,16) = data8.read(); wait(); tdata.range(31,24) = data8.read(); data = tdata; datardy = true; // data is ready, new addresses ok W_ESCAPE if (reset) { datardy = false; } W_END }}