Lecture 5
Lecture 5
Lecture 5
Overview:
Hardware-Software Co-Specification
SystemC and Co-specification
Introduction to SystemC for Co-specification
A SystemC Primer
Hardware-Software Codesign
Co-design of Embedded Systems consists of the
following parts:
Co-Specification
Developing system specification that describes hardware,
software modules and relationship between the hardware
and software
Co-Synthesis
Automatic and semi-automatic design of hardware and
software modules to meet the specification
Co-Simulation and Co-verification
Simultaneous simulation of hardware and software
HW/SW Co-Specification
• SystemC types:
Types for systems modeling
2 values (‘0’,’1’)
4 values (‘0’,’1’,’Z’,’X’)
Arbitrary size integer (Signed/Unsigned)
Fixed point types
SC_Logic, SC_int types
SC_Logic: More general than bool, 4 values :
(‘0’ (false), ‘1’ (true), ‘X’ (undefined) , ‘Z’(high-impedance) )
Assignment like bool
my_logic = ‘0’;
my_logic = ‘Z’;
Operators like bool but Simulation time bigger than bool
Declaration
sc_logic my_logic;
sc_bv<16> x, sc_bv<8> y;
y = x.range(0,7);
sc_lv<32> bus2;
cout << “bus = “ << bus2.to_string();
SystemC Specific Features
• Modules:
A class called a module: A hierarchical entity that can
have other modules or processes contained in it.
• Ports:
Modules have ports through which they connect to other
modules.
Single-direction and bidirectional ports.
• Signals:
SystemC supports resolved and unresolved signals.
• Processes:
used to describe functionality.
contained inside modules.
Modules
The basic building block in SystemC to partition a design.
• Modules are similar to „entity“ in VHDL
• Modules allow designers to hide internal data
representation and algorithms from other modules.
Declaration
Using the macro SC_MODULE
SC_MODULE(modulename) {
Using typical C++ struct or class declaration:
struct modulename : sc_module {
Elements:
Ports, local signals, local data, other modules,
processes, and constructors
SystemC Constructor
Constructor: Each module should include a constructor that
identifies processes as methods using the SC_METHOD macro.
SC_METHOD ( funct ) ; Identifies the function or process funct
Methods are called similar to C++ as:
function_type module_name::function_name(data_type var_name) { … }
module module
Signals and Ports
Ports of a module are the external interfaces that pass information to
and from a module.
sc_inout<data_type> port_name;
• Create an input-output port of ‘data_type’ with name
‘port_name’.
• sc_in and sc_out create input and output ports respectively.
Signals are used to connect module ports allowing modules to
communicate.
sc_signal<data_type> sig_name ;
• Create a signal of type ‘data_type’ and name it ‘sig_name’.
• hardware module has its own input and output ports to which
these signals are mapped or bound.
For example:
in_tmp = in.read( );
out.write(out_temp);
2-to-1 Mux Modules
Module constructor – SC_CTOR is Similar to an
“architecture“ in VHDL
SC_MODULE( Mux21 ) {
sc_in< sc_uint<8> > in1;
sc_in< sc_uint<8> > in2;
sc_in< bool > selection;
sc_out< sc_uint<8> > out;
Inst_module.a(s);
Inst_module.b(c);
Inst_module.q(q);
pInst_module -> a(s);
pInst_module -> b(c);
pInst_module -> q(q);
Sub-module Connections
Signals
sc_signal<type > q, s, c;
Positional Connection
Named Connection
Named and Positional Connections
SC_MODULE(filter) {
// Sub-modules: “components
sample *s1;
coeff *c1;
mult *m1;
sc_signal<sc_uint <32> > q,s,c;
// Constructor :“architecture”
SC_CTOR(filter) {
//Sub-modules instantiation/mapping
s1 = new sample (“s1”);
s1->din(q); // named mapping
s1->dout(s);
c1 = new coeff(“c1”);
c1->out(c); // named mapping
m1 = new mult (“m1”);
(*m1)(s, c, q)//positional mapping
}
}
Communication and
Synchronization
• SystemC 2.0 and higher has general-purpose
• Channel
A mechanism for communication and synchronization
They implement one or more interfaces
• Interface
Specify a set of access methods to the channel
But it does not implement those methods
• Event
Flexible, low-level synchronization primitive
Used to construct other forms of synchronization
Communication and
Synchronization
Interfaces
Module1 Module2
Channel
Events
Ports to Interfaces
Interfaces
Interface is purely functional and does not provide the
implementation of the methods.
• Interface only provides the method's signature.
Interfaces are bound to ports.
• They define what can be done through a particular port.
FIFO
Read Interface
Problem definition: FIFO communication channel with blocking read and write operation
Source available in SystemC installation, under “examples\systemc” subdirectory
Processes
Processes are functions identified to the SystemC kernel
and called if a signal of the sensitivity list changes.
• Processes implement the funcionality of modules.
• Similar to C++ functions or methods
Three types of Processes: Methods, Threads and Cthreads
Methods : When activated, executes and returns
SC_METHOD(process_name)
Threads: can be suspended and reactivated
- wait( ) -> suspends
- one sensitivity list event -> activates
SC_THREAD(process_name)
Cthreads: are activated by the clock pulse
SC_CTHREAD(process_name, clock value);
Processes
Type SC_METHOD SC_THREAD SC_CTHREAD
Activates Event in sensit. list Event in sensit. List Clock pulse
Exec.
Suspends NO YES YES
Exec.
Infinite Loop NO YES YES
suspended/ N.D. wait() wait()
reactivated wait_until()
by
Constructor SC_METHOD(call_back); SC_THREAD(call_back); SC_CTHREAD(
& sensitive(signals); sensitive(signals); call_back,
Sensibility sensitive_pos(signals); sensitive_pos(signals); clock.pos() );
definition sensitive_neg(signals); sensitive_neg(signals); SC_CTHREAD(
call_back,
clock.neg());
Sensitivity List of a Process
• sensitive with the ( ) operator
Takes a single port or signal as argument
sensitive(s1);sensitive(s2);sensitive(s3)
• sensitive with the stream notation
Takes an arbitrary number of arguments
sensitive << s1 << s2 << s3;
• 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;
Multiple Process Example
SC_MODULE(ram) {
sc_in<int> addr;
sc_in<int> datain;
sc_in<bool> rwb;
sc_out<int> dout;
int memdata[64];
// local memory storage
int i;
void ramread(); // process-1
void ramwrite();// process-2
SC_CTOR(ram){
SC_METHOD(ramread);
sensitive << addr << rwb;
SC_METHOD(ramwrite);
sensitive << addr << datain << rwb;
for (i=0; i++; i<64) {
memdata[i] = 0;
} }
};
Thread Process and 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)
2 12 22 32 42
sc_time
sc_time data type to measure time. Time is expressed in two parts:
a numeric magnitude and a time unit e.g. SC_MS, SC_NS,
SC_PS, SC_SEC, etc.
sc_time t(20, SC_NS);
//var t of type sc_time with value of 20ns
More Examples:
sc_time t_PERIOD(5, SC_NS) ;
sc_time t_TIMEOUT (100, SC_MS) ;
sc_time t_MEASURE, t_CURRENT, t_LAST_CLOCK;
t_MEASURE = (t_CURRENT-t_LAST_CLOCK) ;
if (t_MEASURE > t_HOLD) { error ("Setup violated") }
Time representation in SystemC
Set Time Resolution:
sc_set_time_resolution (10, SC_PS) ;
Any time value smaller than this is rounded off
default; 1 Peco-Second
sc_time t2(3.1416, SC_NS); // t2 gets 3140 PSEC
To Control Simulation:
sc_start( ) ;
sc_stop( ) ;
To Report Time Information:
sc_time_stamp( ) // returns the current simulation time
cout << sc_time_stamp( ) << endl ;
sc_simulation_time( )
Returns a value of type double with the current simulation
time in the current default time unit
sc_event
Event
Something that happens at a specific point in time.
Has no value or duration
sc_event:
A class to model an event
• Can be triggered and caught.
Important
(the source of a few coding errors):
Events have no duration you must be watching to
catch it
• If an event occurs, and no processes are waiting to
catch it, the event goes unnoticed.
sc_event
You can perform only two actions with an
sc_event:
wait for it
• wait(ev1)
• SC_THREAD(my_thread_proc);
• sensitive << ev_1; // or
• sensitive(ev_1)
cause it to occur
notify(ev1)
Common misunderstanding:
if (event1) do_something
• Events have no value
• You can test a Boolean that is set by the process that caused an
event;
• However, it is problematic to clear it properly.
notify( )
To Trigger an Event:
event_name.notify(args);
event_name.notify_delayed(args);
notify(args, event_name);
Immediate Notification:
causes processes which are sensitive to the event to be made
ready to run in the current evaluate phase of the current
delta-cycle.
Delayed Notification:
causes processes which are sensitive to the event to be made
ready to run in the evaluate phase of the next delta-cycle.
Timed Notification:
causes processes which are sensitive to the event to be made
ready to run at a specified time in the future.
notify( ) Examples
sc_event my_event ; // event
sc_time t_zero (0, SC_NS) ; // variable t_zero of type sc_time
sc_time t(10, SC_MS) ; // variable t of type sc_time
Immediate
my_event.notify();
notify(my_event); // current delta cycle
Delayed
my_event.notify_delayed();
my_event.notify(t_zero);
notify(t_zero, my_event); // next delta cycle
Timed
my_event.notify(t);
notify(t, my_event);
my_event.notify_delayed(t); // 10 ms delay
cancel ( )
Cancels pending notifications for an event.
• It is supported for delayed and timed notifications.
• not supported for immediate notifications.
Given:
sc_event a, b, c; // events
sc_time t_zero (0,SC_NS); // variable t_zero of type sc_time
sc_time t(10, SC_MS); // variable t of type sc_time
…
a.notify(); // current delta cycle
notify(t_zero, b); // next delta cycle
notify(t, c); // 10 ms delay
Cancel of Event Notification:
a.cancel(); // Error! Can't cancel immediate notification
b.cancel(); // cancel notification on event b
c.cancel(); // cancel notification on event c
SC_MODULE(missing_event) {
SC_CTOR(missing_event) { Problem with
SC_THREAD(B_thread); // ordered
SC_THREAD(A_thread); // to cause events
SC_THREAD(C_thread); // problems
}
void A_thread( ) {
a_event.notify( ) ; // immediate!
cout << "A sent a_event!" << endl;
}
void B_thread() {
wait(a_event) ;
cout << "B got a_event!" << endl;
}
If wait(a_event) is issued after
void C_thread() {
the immediate notification
wait(a_event) ;
a_event.notify( )
cout << "C got a_event!" << endl;
Then B_thread and C_thread
}
can wait for ever.
sc_event a_event;
Unless a_avent is issued again.
}
Properly Ordered Events
SC_MODULE(ordered_events) { void B_thread() {
SC_CTOR(ordered_events) { while (true) {
SC_THREAD(B_thread); b_event.notify(SC_ZERO_TIME);
SC_THREAD(A_thread); cout << "B sent b_event!" << endl;
SC_THREAD(C_thread); wait(a_event);
// ordered to cause problems cout << "B got a_event!" << endl;
} } // endwhile
}
void A_thread() { void C_thread() {
while (true) { while (true) {
a_event.notify(SC_ZERO_TIME); c_event.notify(SC_ZERO_TIME);
cout << "A sent a_event!" << endl; cout << "C sent c_event!" << endl;
wait(c_event); wait(b_event);
cout << "A got c_event!" << endl; cout << "C got b_event!" << endl;
} // endwhile } // endwhile
} }
sc_event a_event, b_event, c_event;
};
Time & Execution Interaction
Simulated
Execution
Activity
wait( ) and watching( )
Legacy SystemC code for Clocked Thread
wait(N); // delay N clock edges
wait_until (delay_expr); // until expr true @ clock
Same as
For (i=0; i!=N; i++)
wait( ) ; //similar as wait(N)
do wait ( ) while (!expr) ; // same as
// wait_until(delay_expr)
Previous versions of SystemC also included other
constructs to watch signals such as watching(),
Traffic Light Controller
Highway
Normally has a green light.
Sensor:
A car on the East-West side road triggers N
the sensor
• The highway light: green => yellow => red,
• Side road light: red => green.
SystemC Model:
S
Uses two different time delays:
• green to yellow delay >= yellow to red delay
(to represent the way that a real traffic light works).
Traffic Controller Example
// traff.h
#include "systemc.h“
SC_MODULE(traff) {
// Constructor
// input ports SC_CTOR(traff) {
sc_in<bool> roadsensor; SC_THREAD(control_lights);
sc_in<bool> clock; // Thread
sensitive << roadsensor;
// output ports sensitive << clock.pos();
sc_out<bool> NSred; }
sc_out<bool> NSyellow; };
sc_out<bool> NSgreen;
sc_out<bool> EWred;
sc_out<bool> EWyellow;
sc_out<bool> EWgreen;
void control_lights();
int i;
Traffic Controller Example
// traff.cpp
#include "traff.h"
void traff::control_lights() {
NSred = false;
NSyellow = false;
NSgreen = true;
EWred = true;
EWyellow = false; NSgreen = false; // times up for EW green
EWgreen = false; NSyellow = false; // set EW to yellow
while (true) { NSred = true;
while (roadsensor == false) EWgreen = false;
wait(); EWyellow = true;
NSgreen = false;// road sensor triggered EWred = false;
NSyellow = true; // set NS to yellow for (i=0; i<5; i++)
NSred = false; // times up for EW yellow
for (i=0; i<5; i++) wait();
wait(); NSgreen = true; // set EW to red
NSgreen = false; // yellow interval over NSyellow = false; // set NS to green
NSyellow = false; // set NS to red NSred = false;
NSred = true; // set EW to green EWgreen = false;
EWgreen = true; EWyellow = false;
EWyellow = false; EWred = true;
EWred = false; for (i=0; i<50; i++) // wait one more long
for (i= 0; i<50; i++) wait(); // interval before allowing
wait(); // a sensor again
}
}
References