Title: CPE 626 The SystemC Language
1CPE 626 The SystemC Language
- Aleksandar Milenkovic
- E-mail milenka_at_ece.uah.edu
- Web http//www.ece.uah.edu/milenka
2Outline
- Motivation for SystemC
- What is SystemC?
- Modules
- Processes
3Standard 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
4Designing Big Digital Systems
- Current conditions
- Every system company was doing this differently
- Every system company used its own simulation
library - System designers dont know Verilog or VHDL
- Verilog or VHDL coders dont understand system
design - Problems with standard methodology
- Manual conversion from C to HDL
- Error prone and time consuming
- Disconnect between system model and HDL model
- C model becomes out of date as changes are made
only to the HDL model - System testing
- Tests used for C model cannot be run against HDL
model gt they have to be converted to the HDL
environment
5Idea 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
6SystemC 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 reusedsaving time
- Future releases will have constructs to model
RTOS
7What 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
8What Is SystemC?
- Language definition is publicly available
- Libraries are freely distributed
- Compiler is an expensive commercial product
- See www.systemc.org for more information
9Quick 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)
10Modules
- Hierarchical entity
- Similar to Verilogs 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
11Modules
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 /
12Ports
- 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_inltboolgt load, read
sc_inoutltintgt data sc_outltboolgt full /
rest of the module /
13Signals
- 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_signalltsc_uintlt32gt gt s1, s2 sc_signalltboolgt
reset / / SC_CTOR(mymod) /
Instances of modules that connect to the signals
/
14Instances of Modules
- Each instance is a pointer to an object in the
module
Connect instances ports to signals
SC_MODULE(mod1) SC_MODULE(mod2)
SC_MODULE(foo) mod1 m1 mod2 m2
sc_signalltintgt a, b, c SC_CTOR(foo) m1
new mod1(i1) (m1)(a, b, c) m2 new
mod2(i2) (m2)(c, b)
15Positional 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
sample SC_MODULE(filter) sample s1 //
pointer declarations coeff c1 mult m1
// signal declarations sc_signalltsc_uintlt32gt gt
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)
16Named Connection
include "systemc.h // systemC classes include
"mult.h // decl. of mult include "coeff.h
// decl. of coeff include "sample.h // decl.
of sample SC_MODULE(filter) sample s1
coeff c1 mult m1 sc_signalltsc_uintlt32gt gt
q, s, c SC_CTOR(filter) s1 new sample
("s1") s1-gtdin(q) // din of s1 to signal q
s1-gtdout(s) // dout to signal s c1 new
coeff ("c1") c1-gtout(c) // out of c1 to
signal c m1 new mult ("m1") m1-gta(s)
// a of m1 to signal s m1-gtb(c) // b of m1
to signal c m1-gtq(q) // q of m1 to signal c
17Internal 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_inltboolgt load sc_inltintgt din // input
port sc_inltboolgt clock // input port
sc_outltintgt dout // output port int count_val
// internal data storage void count_up()
SC_CTOR(count) SC_METHOD(count_up) //Method
process sensitive_pos ltlt clock
// count.cc include "count.h" void
countcount_up() if (load) count_val
din else // could be count_val
count_val count_val 1 dout count_val
18Processes
- 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 Verilogs initial blocks
19Processes (contd)
- 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
20Three Types of Processes
Determines how the process is called and executed
- METHOD
- Models combinational logic
- THREAD
- Models testbenches
- CTHREAD
- Models synchronous FSMs
21METHOD Processes
- Triggered in response to changes on inputs
- Cannot store control state between invocations
- Designed to model blocks of combinational logic
22METHOD Processes
Process is simply a method of this class
SC_MODULE(onemethod) sc_inltboolgt in
sc_outltboolgt out void inverter()
SC_CTOR(onemethod) SC_METHOD(inverter)
sensitive(in)
Instance of this process created
and made sensitive to an input
23METHOD Processes
- Invoked once every time input in changes
- Should not save state between invocations
- Runs to completion should not contain infinite
loops - Not preempted
void onemethodinverter() bool internal
internal in out internal
Read a value from the port
Write a value to an output port
24THREAD 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
25THREAD Processes
Process is simply a method of this class
SC_MODULE(onemethod) sc_inltboolgt in
sc_outltboolgt out void toggler()
SC_CTOR(onemethod) SC_THREAD(toggler)
sensitive ltlt in
Instance of this process created
alternate sensitivity list notation
26THREAD 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 onemethodtoggler() bool last false
for () last in out last wait()
last in out last wait()
27CTHREAD 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
28CTHREAD Processes
SC_MODULE(onemethod) sc_in_clk clock
sc_inltboolgt trigger, in sc_outltboolgt out
void toggler() SC_CTOR(onemethod)
SC_CTHREAD(toggler, clock.pos())
Instance of this process created and relevant
clock edge assigned
29CTHREAD 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 in
which the trigger input is 1
void onemethodtoggler() bool last false
for () wait_until(trigger.delayed()
true) last in out last wait()
last in out last wait()
Relinquish control until the next clock cycle
30A CTHREAD for Complex Multiply
struct complex_mult sc_module sc_inltintgt
a, b, c, d sc_outltintgt 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())
31Put It All Together
Process Type SC_METHOD SC_THREAD SC_CTHREAD
Exec. Trigger Signal Events Signal Events Clock Edge
Exec. Suspend NO YES YES
Infinite Loop NO YES YES
Suspend / Resume by N.A. wait() wait() wait_until()
Construct Sensitize Method 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())
32Watching
- SC_THREAD and SC_CTHREAD processes typicallyhave
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
33Watching An Example
// datagen.h include "systemc.h" SC_MODULE(data_g
en) sc_in_clk clk sc_inoutltintgt data
sc_inltboolgt 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.
34Local 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
here watching(...) watching(...) W_DO // This
is where the process functionality
goes ... W_ESCAPE // This is where the handlers
// for the watched events go if (..)
... W_END
W_BEGIN macro marks the beginning of the local
watching block. W_BEGIN W_DO watching
declarations W_DO W_ESCAPEprocess
functionality W_ESCAPE W_ENDevent
handlers W_END macro ends local watching block
35Local 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
36D-FF in SystemC
// dff.h include "systemc.h" SC_MODULE(dff)
sc_inltboolgt din // data input sc_inltboolgt
clock // clock input sc_outltboolgt 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 ltlt clock
// dff.cc include "dff.h" void dffdoit()
dout din
37Bus 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
38Bus Controller bus.h
// bus.h include "systemc.h" SC_MODULE(bus)
sc_in_clk clock sc_inltboolgt newaddr
sc_inltsc_uintlt32gt gt addr sc_inltboolgt ready
sc_outltsc_uintlt32gt gt data sc_outltboolgt start
sc_outltboolgt datardy sc_inoutltsc_uintlt8gt gt
data8 sc_uintlt32gt tdata sc_uintlt32gt taddr
void xfer() SC_CTOR(bus) SC_CTHREAD(xfer,
clock.pos()) // ready to accept new address
datardy true
39Bus Controller bus.cc
// bus.cc include "bus.h" void busxfer()
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()
40Bus Controller bus.cc (contd)
// 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
41Local 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)
42Local 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