high level hardware design and verification with...

Post on 04-Feb-2020

9 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

High level hardware design

and verification with SystemC

Mikhail Moiseev

2015

2

Introduction

Curriculum

SystemC language basic

SystemC modeling semantic

Synthesizable subset of SystemC

Real-world design architecture in SystemC

SystemC design verification

TLM 2.0

High level synthesis with Cadence CtoS tool

Knowledge required

C++, Verilog/VHDL, Hardware design

3

Hardware design techniques

Year Hardware complexity Design technique

1970 Tiny CPU, 10^4 Gate-level design

1980 One core CPU, 10^6 Gate-level design and Verilog/VHDL

1990 2-4 core CPU, 10^8 Verilog/VHDL

2000 8-32 core CPU and SoC, 10^10 Verilog/VHDL/System Verilog and

ESL design with C/C++

2010 Manycore CPU and large SoC Verilog/VHDL/System Verilog and

ESL design with

SystemC/OpenCL/C/C++

4

SystemC language

SystemC is a C++ based language and a methodology to create a models

of hardware and hardware/software designs

SystemC intended for

System level modelling System-on-Chip (SoC)

Algorithm verification and parameter estimation

Hardware design, verification and synthesis

Virtual prototyping for software/hardware co-design and co-verification

SystemC implemented as a C++ template library

SystemC is defined and promoted by the Accellera Systems Initiative

www.accelera.org

5

History

1999 Open SystemC Initiative announced

2000 SystemC v1.0 released

2001 SystemC v2.0 specification

2005 SystemC 2.1 and TLM 1.0 standard

2005 IEEE approves the IEEE 1666–2005 standard for SystemC

2007 SystemC v2.2 released

2009 TLM-2.0 released

2011 IEEE approves the IEEE 1666–2011 standard for SystemC

2014 SystemC v2.3.1 released

2016 SystemC synthesizable subset standard 1.4.7

6

What is System-on-Chip?

System-on-Chip is a hardware or hardware/software implementation of a

system

CPU coreCPU core

HW

accelerator 1

HW

accelerator N

Inter chip comminucation

On-chip

memory

External bus

controller

...

7

Classic SoC design methodology

Reference

code C, C++,

...

Specification

with some

algorithms

Analysis

C, C++

System Level

Model

Verilog/VHDL

Results

Simulation

Synthesis

C, C++ for

CPU cores

Compilation

Manual

transformation

8

SystemC based methodology

Reference

code C, C++,

...

Specification

with some

algorithms

SystemC

Simulation

Refinement

High level

synthesis

Verilog/VHDL

Automatic

transformation

C, C++ for

CPU cores

9

Why SystemC is based on C++?

Reference algorithms usually presented in C, C++

SystemC based on C++ to provide

Seamless transition from reference code to target implementation

Reuse reference testbench

C++ quite popular language, specially in HW world

What C++ standard is SystemC based?

There are other languages for hardware synthesis based on

Scala (chisel)

Phython (pyverilog)

10

SystemC model levels

Cycle-accurate models

Model behaviour strictly corresponded to target system

Slow simulation, high analysis precision

Approximately-timed (TLM 2.0 supported)

Time information annotated into process interaction or timed events, processes

executed in common simulation time

Fast simulation

Loosely-timed (TLM 2.0 supported)

Time information annotated into process interaction, processes executed in its

own time up to explicit synchronization points

Very fast simulation

Untimed

No time annotations, processes synchronization in pre-determined points

11

Use case and coding styles

Use case Coding style

Virtual prototyping and software

performance analysis

Loosely-timed, untimed

Hardware architectural analysis and

functional verification

Loosely-timed, approximately-timed

Hardware performance verification Approximately-timed, cycle-accurate

Synthesis of SoC top level Approximately-timed, cycle-accurate

Synthesis of critical hardware modules

and SoC`s

Cycle-accurate

12

Hello world!!!

#include "systemc.h"

int sc_main(int argc, char* argv[]) {

cout << "Hello world!!!" << endl;

}

13

Hello world in SC process

#include "systemc.h"

SC_MODULE(MyModule) {

SC_HAS_PROCESS(MyModule);

SC_CTOR(MyModule) {

SC_THREAD(myProc); // Run process with myProc function

}

void myProc() {

cout << "Hello world!!!" << endl;

}

};

int sc_main(int argc, char* argv[]) {

MyModule m("MyModule");

sc_start();

}

14

SystemC installation

Requirement

Linux, gcc/clang

Windows, MinGW/Cygwin/VS

Download systemc-2.3.1 from Accellera web-site

http://www.accellera.org/downloads/standards/systemc

Linux installation, unpack and follow INSTALL instructions

mkdir objdir

cd objdir

../configure –enable-debug –disable-optimize

make

make install

15

Make with SystemC

$SYSTEMC_HOME = /opt/systemc-2.3.1/

include/systemc.h

include/tlm.h

lib-linux64/systemc.a (/lib-mingw)

lib-linux64/systemc.so

g++

-I$(SYSTEMC_HOME)/include

-L$(SYSTEMC_HOME)/lib-linux64 -lsystemc

16

SystemC language basics

17

SystemC project structure

SystemC project includes

Design under test (DUT)

Testbench (TB)

sc_main function where DUT and TB are constructed and simulation

run with sc_start call

DUTTB

sc_main

18

Design under test

DUT contains one or more modules (sc_module class inheritor

instances) which are connected to each other and to TB by signals

(sc_signal class instances)

Module is the main structural unit, like module in Verilog

Processes, which implement logic

Internal and external signals and ports

Data fields

Module instances

19

sc_module

sc_module implemented as a C++ class which is used as base class

for the design modules

SC_MODULE(MyModule){...}

class MyModule : public sc_module{...}

SC_HAS_PROCESS(MyModule)

Module instantiation

MyModule m(“MyModule”)

MyModule* m = new MyModule(“MyModule”)

m(“MyModule”), …

Module in SystemC design is C++ class

There are some limitation for synthesizable DUT modules

20

sc_module example

class A : public sc_module {

public:

A(const sc_module_name& name) : sc_module(name) {}

};

SC_MODULE(B) {

A a;

SC_CTOR(B) :

a("a")

{}

};

int sc_main(int argc, char* argv[]) {

B* b1 = new B("b1");

B b2("b2");

sc_start();

}

21

sc_module example

template<class T, int N>

class A : public sc_module {

public:

A(const sc_module_name& name) : sc_module(name) {}

private:

T fifo_array[N];

};

SC_MODULE(B) {

A<char, 5> a;

SC_CTOR(B) :

a("a")

{}

};

22

Processes in SystemC

There are three kinds of processes macro defined in sc_module

SC_METHOD(fname)

SC_THREAD(fname)

SC_CTHREAD(fname, clk)

Called from module constructor

Process function has signature void(void)

It is normal C++ function may have local variables, other function calls, ...

DUT logic is usually implemented in processes, not in module constructors

23

sc_time

sc_time represents simulation time and time intervals, including delays and

time-outs

sc_time is implemented as a C++ class

sc_time()

sc_time(double val, sc_time_unit time_unit)

enum sc_time_unit {SC_FS, SC_PS, SC_NS, SC_US, SC_MS, SC_SEC}

24

sc_time example

int sc_main(int argc, char* argv[]) {

sc_time t1(1.5, SC_PS);

sc_time t2(10, SC_NS);

sc_time t3(50.5, SC_MS);

}

25

sc_event

sc_event is an object for process synchronization

Process may be triggered or resumed by event notification

Event notification works for all processes, waiting for the event

Event notification has no delayed effect

sc_event is implemented as a C++ class which is instantiated as a

global variable or a sc_module field

sc_event()

sc_event(char* name)

notify()

notify(sc_time&)

cancel()

26

sc_event example

sc_event e1;

class A : public sc_module {

public:

sc_event e2;

sc_event* e4;

A(const sc_module_name& name, sc_event* e) :

sc_module(name),

e2("e2"),

e4(e)

{}

};

int sc_main(int argc, char* argv[]) {

sc_event* e3 = new sc_event("e3");

A a("a", e3);

}

27

sc_clock

sc_clock is intended to model the behavior of a digital clock signal

sc_clock is implemented as a C++ class which is usually

instantiated in sc_main()

sc_clock(char* name)

sc_clock(char* name, sc_time& period,

double duty_cycle = 0.5,

sc_time& start_time = SC_SERO_TIME,

bool posedge_first = true)

sc_event& posedge_event()

sc_event& negedge_event()

28

sc_in_clk

sc_in_clk is input clock port in sc_module

inheritor of sc_in<bool>, which is input port of 1-bit value

sc_in_clk

void bind (sc_signal_in_if<bool>& )

void operator() (sc_signal_in_if<bool>& )

sc_event_finder& pos()

sc_event_finder& neg()

29

sc_clock and sc_in_clk example

class A : public sc_module {

public:

sc_in_clk clk;

A(const sc_module_name& name) :

sc_module(name),

clk("clk")

{}

};

int sc_main(int argc, char* argv[]) {

sc_clock clock1("clock1", sc_time(10, SC_NS));

A a("a");

a.clk(clock1); // a.clk.bind(clock1);

}

30

sc_sensitive

sc_sensitive provides the operators to build the static sensitivity of

processes

sc_sensitive

sc_sensitive& operator<< (sc_event& )

sc_sensitive& operator<< (sc_interface& )

sc_sensitive& operator<< (sc_port_base& )

sc_sensitive& operator<< (sc_event_finder& )

31

SC_METHOD

Method process implements logic which is activated by an event the process

is sensitive

Method function is called each time the event occurred

Method function is usually stateless

Method body is executed in one delta cycle

Method sensitivity is specified with context variable sensitive which is instance

of sc_sensitive class

HL synthesis of SC_METHOD produces combinational logic

32

SC_METHOD exampleSC_MODULE(A) {

public:

sc_in_clk clk;

sc_in<bool> enbl;

SC_CTOR(A) : clk("clk") {

SC_METHOD(proc);

sensitive << clk.pos() << enbl;

}

void proc() {

if (enbl) cout << sc_time_stamp() << endl;

}

};

int sc_main(int argc, char* argv[]) {

sc_clock clk("clk", sc_time(10, SC_NS));

A a("a");

a.clk(clk);

sc_start();

}

33

next_trigger method

next_trigger call from SC_METHOD process body, sets dynamic

sensitivity of the current process, which overrides static sensitivity

Dynamic sensitivity is set up to very next process occasion and only for that

In multiple calls of next_trigger only last call is applied

next_trigger is a method of sc_module and sc_prim_channel

next_trigger() – static sensitive is activated

next_trigger(sc_event& e) – process triggered by event e

next_trigger(sc_time& t) – process triggered after the time given

next_trigger(sc_time& t, sc_event& e)

34

next_trigger exampleSC_MODULE(A) {

public:

sc_in<bool> rst;

sc_in<bool> enbl;

SC_CTOR(A) : clk("clk") {

SC_METHOD(proc);

sensitive << rst;

}

void proc() {

if (rst) {

next_trigger(enbl);

} else

if (enbl) {

cout << “do something” << endl;

next_trigger();

}

}};

35

Method another exampletemplate<class T> A : public sc_module {

public:

sc_in<T> a, b;

sc_out<T> sum;

sc_signal<bool> sign; // sc_signal may be used in module interface

SC_HAS_PROCESS(A);

A(const sc_module_name& name) : sc_module(name),a(“a"),b(“b”),sum(“sum”) {

SC_METHOD(proc);

sensitive << a << b;

}

void proc() {

sign = a > b;

sum = (a > b) ? a - b : a + b;

}

};

36

wait method

wait suspend process execution to the corresponding event or specified time

wait is a method of sc_module

May be called from module processes only

wait() – suspend process until next event

wait(int n) – suspend process until n next events

wait(sc_event& e) – suspend process until event e

wait(sc_time& t) – suspend process period t

wait(SC_ZERO_TIME) – suspend process to next delta cycle

37

SC_THREAD

Thread process implements logic which is resumed by an event the process is

sensitive

Thread function is called once if no reset happens

Thread function usually has state based on local or global variable

Thread function usually has reset section and main loop, which executes infinitely

Thread sensitivity is specified with context variable sensitive

Thread function may call all wait methods

HL synthesis of SC_THREAD produces sequential and combinational logic

38

SC_THREAD example 9SC_MODULE(A) {

sc_in_clk clk;

sc_in<bool> rst;

sc_in<T> A, B; sc_out<T> sum;

SC_CTOR(A) {

SC_THREAD(proc);

sensitive << clk.pos();

async_reset_signal_is(rst, true);

}

void proc() {

sum = 0; // Reset actions

wait();

while (true) {

sum = A + B;

cout << "Main loop " << sc_time_stamp() << endl;

wait();

}}

};

39

SC_CTHREAD

Clocked thread process is sensitive to single clock, given as SC_CTHREAD second

argument

Clocked thread function is called once if no reset happens

Clocked thread function has state based on local or global variable

Clocked thread function usually has reset section and infinite main loop

sensitive is not used for clocked thread

Clocked thread function may call wait() and wait(int) methods

HL synthesis of SC_CTHREAD produces sequential and combinational logic

40

SC_CTHREADSC_MODULE(A) {

sc_in_clk clk;

sc_in<bool> rst;

SC_CTOR(A) {

SC_CTHREAD(proc, clk.pos());

async_reset_signal_is(rst, true);

}

void proc() {

cout << "Reset actions" << endl;

wait();

while (true) {

cout << "Main loop " << sc_time_stamp() << endl;

wait();

}

}

};

41

Cthread another exampleSC_MODULE(A) {

sc_in_clk clk;

sc_in<bool> nrst;

sc_in<bool> satur;

sc_out<T> counter;

SC_CTOR(A) {

SC_CTHREAD(proc, clk.pos());

async_reset_signal_is(nrst, false);

}

void proc() {

counter = 0;

wait();

while (true) {

counter = (counter == MAX_T-1) ?

(satur ? MAX_T-1 : 0) : counter+1;

wait();

}

}};

42

Process and module connection

Process interaction, hierarchical structure and module connection are

provided with channels, ports and exports

sc_in, sc_out, sc_inout

sc_signal, sc_fifo

All channels inherited sc_prim_channel

sc_in sc_out

sc_signal

sc_signal

sc_in

sc_out

sc_signal

sc_signal

43

sc_signal

sc_signal is a predefined primitive channel intended to model the behavior

of a single piece of wire(s)

Corresponded to net or register type in Verilog

sc_signal<class T> is template class

T specifies signal type

T& read() – get current value of signal

write(T&) – set new value of signal in the next delta cycle

operator = () – to skip write()

operator T() – to skip read()

sc_event& value_changed_event

Normally has one writer and one or more readers

44

sc_signal with a bug

SC_MODULE(A) {

sc_signal<bool> s;

// proc1 and proc2 are SC_CTHREAD`s

void proc1() {

while (true) {

s.write(!s.read());

wait();

}}

void proc2() {

while (true) {

if (s.read()) cout << "s is on " << endl;

wait();

}}

45

sc_signal fixed

sc_signal<unsigned> b;

void proc1() {

s.write(0);

unsigned a = …;

wait();

while (true) {

s.write(!s.read());

wait();

b = a+1; // b.write(a);

}

}

46

sc_signal example w/o read/write

void proc1() {

s = 0;

wait();

while (true) {

s = !s;

wait();

}}

void proc2() {

while (true) {

if (s) cout << "s is on " << endl;

wait();

}}

47

sc_in

sc_in is a specialized port class to use with signals

Intended to bind input signal

Corresponded to input in Verilog

sc_in<class T> is template class

T& read() – get current value of the signal bound

sc_event& value_changed_event

void bind (sc_signal_in_if<bool>& )

void operator() (sc_signal_in_if<bool>& )

sc_in instances are fields of sc_module only

48

sc_out, sc_inout

sc_out is a specialized port class to use with signals

Intended to bind output signal

Corresponded to output in Verilog

sc_out<class T> is template class

write(T&) – set new value of signal in the next delta cycle

T& read() – get current value of the signal bound

sc_event& value_changed_event

void bind (sc_signal_in_if<bool>& )

void operator() (sc_signal_in_if<bool>& )

sc_inout is a bidirectional port

sc_out,sc_inout instances are fields of sc_module only

49

sc_in and sc_out

bool c;

SC_MODULE(A) {

sc_out<bool> so;

void proc() {

c = 1;

}

}

SC_MODULE(B) {

sc_in<bool> si;

void proc() {

… = c;

}

}

int sc_main(int argc, char* argv[]) {

sc_signal<bool> s("s");

a.so(s);

b.si(s);

50

Reset signal

Reset signal usually is bound to sc_in<bool> port

SC_METHOD reset is specified in sensitivity list

sensitive << reset

SC_CTHREAD and SC_THREAD use special function to specify reset signals

reset_signal_is(sc_in<bool>&, bool)

async_reset_signal_is(sc_in<bool>&, bool)

51

Reset signal

sc_in<bool> nrst;

sc_in<bool> rst_sync;

SC_CTOR(A) : rst("rst")

{

SC_CTHREAD(proc, clk.pos());

async_reset_signal_is(nrst, false);

sync_reset_signal_is(rst_sync, true);

}

52

SystemC simulation semantic

53

Elaboration and simulation phases

Elaboration

Construction of the module hierarchy

Callbacks before_end_of_elaboration, end_of_elaboration execution – virtual

methods of sc_module

Simulation

Callbacks start_of_simulation execution

Initialization phase

Evaluation, update, delta notification, timed notification phases

Callbacks end_of_simulation execution

Destruction of module hierarchy

54

Elaboration phase

Instances created on elaboration phase

sc_module – may be created in sc_main and in other modules

sc_prim_channel - may be created in sc_main and in other modules

sc_port/sc_export - may be created in modules only

All unspawned processes are created in elaboration phase with

SC_METHOD, SC_THREAD and SC_CTHREAD macros

Port and export binding is done is elaboration phase

In the end there is complete design structure

55

Simulation phase

Simulation of the design and testbench

There is a set of processes created in elaboration phase

Processes are executed under control of the scheduler

All processes are started in initialization phase

Non-preemptive multitasking, each SC_THREAD/SC_CTHREAD process works up

to suspend, each SC_METHOD process works up to return process at function end

Scheduler

Determines runnable processes

Runs them one by one

Gathers update requests, and notifications

Increase simulation time

56

Initialization phase

Initialization phase starts once after simulation start

Run update phase

Mark all processes as runnable except marked as dont_initialize

Run delta notification phase

Initialization phase required to set up initial values of channels

57

Simulation time

Simulation time is measured in ns, ps, fs

sc_set_time_resolution()

In synchronous designs there is one or a few clocks, which may have different

periods

Time resolution determines as minimal clock period or minimal period in timed

notification

SC_CTHREAD and SC_THREAD processes which have clock event only in

sensitivity list are executed once pre clock tick by rising or falling clock edge

58

Delta cycle

SC_METHOD process may be triggered by event notified in clocked thread

process and may notify an event, which triggers another method process

Do these activities run at the same simulation time?

To represent non-timed event order delta cycles are used

SC_CTHREAD SC_METHOD1 SC_METHOD2sc_signal

sc_time_stamp = t

sc_signal

59

Delta cycle

Delta cycle is zero long period of time, in which all values of SC channels are

updated

If a channel written at delta cycle i, then new value may be read at delta cycle i+1

Each moment of time contains a number of delta cycles enough to present all

process interactions

t325 ns 326 ns

Time resolution = 1 ns

1 2 30 ...

60

Notification types

Event notification provided with notify method of sc_event

Immediate notification – in the current delta cycle

notify()

Delta notification – in the next delta cycle

notify(SC_ZERO_TIME), #define SC_ZERO_TIME 0

Timed (delayed) notification – after the specified time period

notify(sc_time) – method of sc_event

61

Evaluation phase

Scheduler resumes or triggers each runnable process

Process runs without interruption up point where it suspends or returns

SC_THREAD/SC_CTHREAD process suspend on wait/suspend call

SC_METHOD returns at the function end

Process execution order is not specified

Active process may do immediate notification, in which case all processes

sensitive to the event becomes runnable and will be run in this evaluation

phase

Active process may operate with a channel that leads to call

request_update of the channel, results to pending update calls

Active process may do delta/delayed notification

62

Evaluation phase

SC_CTHREAD process may resume with call

wait() – for the next clock tick time

wait(int n)– for the time after n clock ticks

SC_THREAD process may resume with call

wait() and wait(int) related to events in sensitivity list

wait(sc_event) – for the delta cycle where the event is notified

wait(SC_ZERO_TIME)– for the next delta cycle

wait(sc_time)

wait(sc_time, sc_event)

63

Update phase

Update phase starts after end of evaluation phase, when no more runnable

process

Execute pending calls of update functions

For channels which request_update was called in the very last evaluation phase

Function update applies operations done with the channel

sc_signal – assign last written value to current value

sc_fifo – perform pop and push operations done and update FIFO internal state

64

Delta and timed notification phases

Delta notification phase starts after update phase

Determine runnable processes by delta notification and wait(SC_ZERO_TIME)

calls

Start evaluation and update phases

Timed notification phase starts after all delta notification phases

finished, no runnable processes

Simulation time is advanced to the moment of earlier timed notification

Determine runnable processes and start first evaluation phase

65

Initialization phase

Timed notification

phase

Delta notification

phase

Evaluation phase

Execute/Run/Notify processes

No runnable process

no yes

No runnable process yes

No runnable process

no

no

Update phase

66

SystemC data types

67

SystemC data types

All C++ core and standard library data types

uint8_t, uint16_t, uint32_t, uint64_t from stdint.h

Special data types – implemented as C++ templates

Integers with specified length

sc_int, sc_uint

sc_bigint, sc_gibuint

Fixed-point types

sc_fixed, sc_ufixed

Logic types

sc_logic –four value 1 bit logic: 0,1,X,Z

Vectors

sc_bv – bit vector

sc_lv – logic vector

68

Integer data types

Commonly used types

sc_int<int>, sc_uint<int> - limited length (1..64 bit), stored in C++ 64-bit

native type

sc_bigint<int>, sc_biguint<int> - finite length, no limitations

sc_int and sc_bigint are represented in two complement form

Take into account different ranges of signed and unsigned variables with the same

number of bits

Signed and unsigned comparison issue

Two common bugs

sc_int<3> a; sc_uint<3> b;

a = b;

for(sc_uint<3> i = 0; i < 8; ++i) {…}

69

Integer data types

sc_int, sc_uint, sc_bigint, sc_biguint methods

range(int max, int min) – get [max..min] bits of the integer, may be used in

left and right parts as well

bit(int) or operator[](int) – get the bit of integer

concat(arg0, arg1, …) or operator, - concatenation of several integers,

the result length is sum of all argument lengths

and_reduce(), or_reduce(), xor_reduce(), …

to_int, to_uint, to_long, …

May be mixed with C++ data types with unary and binary operators

Integer literal with “0x” “0o” “0b” may be used

70

Integer example

sc_uint<5> a = 0;

sc_uint<5> b = 3;

sc_uint<10> c = (a, b); // concatenation

bool d = c.bit(4);

sc_uint<1> e = !d; // implicit type conversion

sc_uint<4> f = b.range(3,e);

a.range(4,3) = (c.range(3,3), (sc_uint<3>)f);

d = a.and_reduce();

int cpp_a = 5;

b = a + cpp_a; // mix with C++ data types

d = (b == cpp_a); // signed and unsigned equality

f = cpp_a; // implicit type conversion

c = 0xA3F; // Hex literal

b = 0b011011; // Binary literal

71

Logic data type

Four value logic data type - sc_logic

Operates with sc_logic_value_t or predefined constants

Log_0=0, Log_1=1, Log_Z, Log_X

SC_LOGIC_0, SC_LOGIC_1, …

to_bool() and is_01() methods

Logic operation semantic

AND operation

OR operation

72

Vector data types

sc_bv and sc_lv represent finite length vector of bits or logic values

operator[](int)– get the specified bit

range(int max, int min) or operator()(int, int) – get [max..min] bits

and_reduce(), or_reduce(), xor_reduce(), …

lrotate(int n ), rrotate(int n) – rotate on n elements

reverse() – reverse element order

to_int, to_uint, to_long, …

is_01() – all elements are 0 or 1

length() – element number

73

Vector examples

sc_bv<4> a = 11;

sc_lv<6> b = a << 2;

b(3,2) = b(4,3);

sc_uint<4> c = a;

sc_logic e[4] = (SC_LOGIC_Z, SC_LOGIC_0, SC_LOGIC_1, SC_LOGIC_Z);

sc_lv<4> d = e;

d[3] = SC_LOGIC_X;

bool f = d.is_01();

f = (d[1] == SC_LOGIC_X);

f = (d.length() == b.length());

74

Fixed-point data types

Fixed-point types represent sequence of bits with a specified position for the

point separates integer and fractional parts

sc_fixed, sc_ufixed

sc_(u)fixed<WL, IWL, Q_MODE, O_MODE, N_BITS>

WL – word length

IWL – integer word length

Q_MODE – quantization mode

O_MODE – overflow mode

N_BITS - number of saturated bits

75

Fixed-point data types

Q_MODE – quantization mode

SC_RND, // Rounding to plus infinity

SC_RND_ZERO, // Rounding to zero

SC_RND_MIN_INF, // Rounding to minus infinity

SC_RND_INF, // Rounding to infinity

SC_RND_CONV, // Convergent rounding

SC_TRN, // Truncation

SC_TRN_ZERO // Truncation to zero

O_MODE – overflow mode

SC_SAT, // Saturation

SC_SAT_ZERO, // Saturation to zero

SC_SAT_SYM, // Symmetrical saturation

SC_WRAP, // Wrap-around

SC_WRAP_SM // Sign magnitude wrap-around

76

Fixed-point data types

Default template values

sc_(u)fixed<WL=32, IWL=32, Q_MODE=SC_TRN, O_MODE=SC_WRAP,

N_BITS=0>

sc_fixed, sc_ufixed methods

wl(), iwl(), n_bits(), o_mode(), q_mode()

overflow_flag() – last write caused overflow

quantization_flag() – last write caused quantization

77

Fixed-point examples

#include “$SC_HOME/include/sysc/datatypes/fx/sc_fixed.h”

#include “$SC_HOME/include/sysc/datatypes/fx/sc_ufixed.h”

using namespace sc_dt;

sc_fixed<5,3> a = 3.25;

sc_ufixed<4,2> b = 3.25;

bool c = (a == b);

float f = 7.45;

sc_ufixed<6,3, SC_TRN> g1 = f; // 7.375

sc_ufixed<6,3, SC_RND> g2 = f; // 7.5

sc_ufixed<4, 4, SC_TRN, SC_SAT, 4> d = 15; // d = 15

d += 1; // d = 15

78

Predefined channels and ports

79

sc_prim_channel

sc_prim_channel is the base class for all primitive channels

request_update() causes scheduler to enroll the update request of this channel

and following call of the update method at update phase, no more than one call of

the channel update method is guaranteed

virtual update() must be defined in channels, it can update only the current

object state, this method cannot get other channel states, call any

sc_prim_channel methods, does immediate notification and process control

(suspend)

wait()/next_trigger() methods are identical to sc_module onces

80

Predefined channels

Predefined channels inherited of sc_prim_channel

sc_signal<T>

sc_signal_resolved, sc_signal_rv

sc_buffer<T>

sc_clock

sc_fifo<T>

Other channels

sc_mutex

sc_semaphore

sc_event_queue

81

Data types for channels

Template parameter T of a channel must be a C++ type with predefined

assignment and equality semantic which are adequate, or type which

bool T::operator==( const T& ) adequate to provide event generation

std::ostream& operator<<( std::ostream&, const T& ) gets channel state to

print/dump functions

const T& operator=( const T& ) to assign or copy values, should correspond to

operator==

Default constructor

sc_trace() method

All SC data types comply these requirements

sc_uint, sc_int, sc_fixed, …

T cannot be sc_module, sc_signal, …, or a class contains any of them

82

sc_signal interface

template <class T, sc_writer_policy WRITER_POLICY = SC_ONE_WRITER>

class sc_signal: public sc_signal_inout_if<T>, public sc_prim_channel {...}

template <class T> class sc_signal_inout_if

: public sc_signal_in_if<T> , public sc_signal_write_if<T> {...}

template <class T>class sc_signal_write_if : virtual public sc_interface {

virtual void write( const T& ) = 0;

}

template <class T> class sc_signal_in_if : virtual public sc_interface {

virtual const T& read() const = 0;

virtual const sc_event& value_changed_event() const = 0;

virtual bool event() const = 0;

}

83

sc_signal<bool> interface

template <> class sc_signal_in_if<bool> : virtual public sc_interface {

public:

virtual const T& read() const = 0;

virtual const sc_event& value_changed_event() const = 0;

virtual const sc_event& posedge_event() const = 0;

virtual const sc_event& negedge_event() const = 0;

virtual bool event() const = 0;

virtual bool posedge() const = 0; // return true if the event occurs

virtual bool negedge() const = 0; // in the very last delta cycle

}

84

sc_signal implementation

T m_cur_val, m_new_val;

T read() { return m_cur_val;}

void write(const T& value_) {

bool value_changed = !(m_cur_val == value_);

m_new_val = value_;

if (value_changed) {

request_update();

}

}

void update() {

if (m_new_val != m_cur_val) {

m_cur_val = m_new_val;

if (m_change_event_p) m_change_event_p->notify_next_delta();

}

}

85

sc_clock

class sc_clock : public sc_signal<bool> {

sc_clock( const char* name_,

const sc_time& period_,

double duty_cycle_ = 0.5,

const sc_time& start_time_ = SC_ZERO_TIME,

bool posedge_first_ = true );

virtual const sc_event& posedge_event() const = 0;

virtual const sc_event& negedge_event() const = 0;

double duty_cycle() const;

const sc_time& start_time() const;

bool posedge_first() const;

}

86

sc_buffer

sc_buffer – primitive channel derived from sc_signal

Value-changed event is notified whenever the buffer is written, value is not

considered

87

Signals with many writers

sc_signal_resolved – primitive channel inheritor of sc_signal

Template argument T is sc_logic

If more than one process write the channel, it resolves in according with general

rules

1 and 0 -> X, 1 and X -> X, X and Z -> X, 0 and Z ->0, …

sc_signal_rv – uses sc_lv as T

88

sc_fifo interface

template <class T> class sc_fifo: public sc_fifo_in_if<T>,

public sc_fifo_out_if<T>, public sc_prim_channel {...}

template <class T> class sc_fifo_in_if :

public sc_fifo_nonblocking_in_if<T>, public sc_fifo_blocking_in_if<T> {

virtual int num_available() const = 0;

}

template <class T> class sc_fifo_nonblocking_in_if: public sc_interface {

virtual bool nb_read( T& ) = 0; // return false if FIFO is empty

virtual const sc_event& data_written_event() const = 0;

};

template <class T> class sc_fifo_blocking_in_if : public sc_interface {

virtual T read() = 0; // block until FIFO is empty

};

89

sc_fifo interface

template <class T> class sc_fifo_out_if :

public sc_fifo_nonblocking_out_if<T>, public sc_fifo_blocking_out_if<T> {

virtual int num_free() const = 0;

};

template <class T> class sc_fifo_nonblocking_out_if : public sc_interface {

virtual bool nb_write( const T& ) = 0; // return false if FIFO is full

virtual const sc_event& data_read_event() const = 0;

};

template <class T> class sc_fifo_blocking_out_if : public sc_interface {

virtual void write( const T& ) = 0; // block until FIFO is full

};

90

sc_fifo implementation

int m_size, m_free, m_ri, m_wi;

int m_num_readable;

int m_num_read, m_num_written; // in the current delta cycle

T* m_buf;

int num_available() {return (m_num_readable – m_num_read);}

void update() {

if (m_num_read > 0) m_data_read_event.notify(SC_ZERO_TIME);

if (m_num_written > 0) m_data_written_event.notify(SC_ZERO_TIME);

m_num_readable = m_size – m_free;

m_num_read = 0;

m_num_written = 0;

}

91

sc_fifo implementation

void read(T& val) {

while (num_available() == 0) wait(m_data_written_event);

m_num_read++;

buf_read(val);

request_update();

}

bool nb_read(T& val) {

if (num_available() == 0) return false;

m_num_read++;

buf_read(val);

request_update();

return true;

}

92

sc_mutex

sc_mutex – predefined channel to model SW style mutex

Not inheritor of sc_prim_channel

class sc_mutex : public sc_mutex_if, public sc_object

{

virtual int lock();

virtual int trylock();

virtual int unlock();

};

93

User defined channel

It is possible to implement own channels as C++ class

Must derived from one of primitive channels or directly from sc_prim_channel

User channel may be also implemented using one of primitive channel

Lets go to http://collabedit.com/g95cv

94

Process interaction

95

Process interaction classification

Synchronization primitive

sc_signal, sc_fifo, …

sc_event

Shared variable

C++ or external synchronization object

C++ 11 mutex, conditional variable, …

Pthread mutex, semaphore, …

Process number

1-1

1-to-N

Process types

Will discuss SC_CTHREAD and SC_METHOD

Synthesizability

96

sc_signal for SC_CTHREADs

sc_signal<bool> req;

void consumer(){

wait();

while (1) {

while (!req) wait();

...

}}

void produces(){

req = 0; wait();

while (1) {

...

req = 1;

wait();

req = 0;

}}

clk

req

1 2 3

DC: 1 2 ... DC: 1 2 ...

Producer Consumerreq

ack

97

// Request-Acknowledge synchronization

sc_signal<bool> req, ack; sc_signal<T> val;

void consumer(){

ack = 0; wait();

while (1) {

while (!req) wait();

consumeValue(val); // takes some time Tcons

ack = 1;

wait();

ack = 0;

}}

void producer(){

req = 0; wait();

while (1) {

val = produceValue(); // takes some time Tprod

req = 1;

wait();

req = 0;

while (!ack) wait();

}}

98

Tcons = 0, Tprod = 0

Tcons = 1, Tprod = 0

99

// Ready-Request synchronization

sc_signal<bool> req, rdy; sc_signal<T> val;

void consumer(){

rdy = 1; wait();

while (1) {

while (!req) wait();

rdy = 0;

val_local = val.read();

consumeValue(val_local); // takes some time Tcons, copy val if Tcons

> 1

rdy = 1; // May be asserted inside of consumeValue 1 clock before

wait(); // My be removed if Tcons > 0

}}

void producer(){

req = 0; wait();

while (1) {

while (!rdy) wait();

val = produceValue(); // takes some time Tprod

req = 1;

wait();

req = 0;

100

Tcons = 0, Tprod = 0

Tcons = 1 (wait() is removed from consumer), Tprod = 0

101

// Always ready to get request

sc_signal<bool> req; sc_signal<T> val;

void consumer(){

wait();

while (1) {

while (!req) wait();

consumeValue(val); // takes no time, i.e. Tcons = 0

wait();

}}

void producer(){

req = 0; wait();

while (1) {

val = produceValue(); // takes some time Tprod, must copy val!!!

req = 1;

wait();

req = 0;

}}

102

sc_signal for SC_METHODs

sc_signal<bool> req, ack, cond;

sc_signal<T> val, res;

// Must be Tcons = 0, Tprod = 0!!!

void consumer(){

ack = 0; res = 0;

if (req && cond) {

res = consumeValue(val);

ack = 1;

}

}}

// External signal @do_req

void producer() {

if (!rst && do_req) { // rst is not required

req = produceValue(val);

}}

103

sc_signal for SC_METHODs

SC_METHODs triggered by events notified in SC_CTHREAD

Signal modified in SC_METHOD may result

in other SC_METHOD activated

using by SC_CTHREAD at the next posedge/negedge

No backward relations of SC_METHODs are possible

Backward relation leads to combinational loop

SC_CTHREAD SC_METHOD SC_METHOD ...

104

Combinational loop

sc_signal<bool> req, rdy;

sc_signal<T> val, res;

void consumer(){

rdy = 0; res_val = 0;

if (req) {

res = consumeValue(val);

rdy = 1;

}

}}

void producer(){

req = 0;

if (do_req || rdy) {

req = produceValue(val);

}

}

105

Async/sync process usage

Complex design usually contains SC_METHODs as well as SC_CTHREADs

SC_CTHREADs are used to

Implement state control in FSM

Perform synchronous bus transactions

Store value in FF

Control operations with memory

SC_METHODs are used to

Reduce latency in process interaction, do something in the current clock tick

Provide immediate acknowledge

Provide speculative processing of bus transaction before it happens

Prepare address and data to memory request

106

// Request-Acknowledge synchronization with extra latency

sc_signal<bool> req, ack; sc_signal<T> val;

void consumer(){

ack = 0; wait();

while (1) {

while (!req) wait();

consumeValue(val); // takes some time Tcons

ack = 1;

wait();

ack = 0;

}}

void producer(){

req = 0; wait();

while (1) {

val = produceValue(); // takes some time Tprod

req = 1;

while (!req || !ack) wait(); // Why checking req here?

req = 0;

}}

107

// Request-Acknowledge synchronization without extra latency

void consumer_async(){

ack = req && reg_free;

}

void consumer_sync(){

reg_free = 1;

wait();

while (1) {

while (!req || !ack) wait();

reg_free = 0;

consumeValue(val); // Tcons > 0

reg_free = 1;

}}

108

Synchronization. Keep It Simple.

In practice, almost all time both side are ready to interact

The most difficult is provide correct pause and resume interaction

Use minimal synchronization which provides correct process interaction

Remove rdy/ack/req is the process can always produce or consume

Do not use async processes if extra latency is not a problem

Less logic generated, less chance to make mistake

90% of mistakes are done in synchronization!!!

109

Shared variable synchronization

Shared variable are synthesizable, represented with a register or memory

Normal FF is 1RW, so it accepts simultaneous access from one process only

in the delta cycle

In different delta cycle register may be accessed by various processes,

no concurrency allowed

Looks like sc_signal based synchronization

Memory (register file, SRAM block, …) may have arbitrary number of ports:

1RW, 1R1W, 2RW, …

Different cells may be accessed at the same time by several processes

Simultaneous access to one cell usually leads to undefined behavior

Shared variable does not give new possibilities compared with sc_signal

This synchronization is implicit

We have to provide no simultaneous access manually

110

sc_event synchronization

sc_event allows to synchronize all process types

In SC_CTHREADs sc_event is the macro second parameter, may do event

notification

In SC_METHODs event notification may be done, instead wait methods

next_trigger may be used

In SC_THREADs all notify and wait call types may be used

sc_event is not synthesizable

May be used for testbenches, specially if it needs represent time events not aligned

with clock

111

// Synchronization with sc_event in two SC_THREADs

sc_event e1, e2;

void consumer(){

while (1) {

wait(e1);

consumeValue(val);

e2.notify(SC_ZERO_TIME);

}}

void producer(){

while (1) {

val = produceValue(); // No time information

e1.notify(sc_time(5, SC_NS)); // Time information

wait(e2);

}}

112

// Synchronization with sc_event in SC_CTHREAD and SC_METHOD

sc_event e1, e2, e3;

{...

SC_CTHREAD(consumer, e2);

SC_METHOD(consume);

sensitive << e1;

...}

void consumer(){

while (1) {

wait(); // waiting for e2

e1.notify(SC_ZERO_TIME); // consume value in method

}}

void consume(){

consumeValue(val);

if (val > N) next_trigger(e3) else next_trigger();

}}

113

sc_fifo synchronization

sc_fifo based synchronization is very similar with sc_signal one

Lets go to

Asynchronous FIFO http://collabedit.com/s7cum

114

Spawned processes

Process types

Static process – created at elaboration phase

Dynamic process – created in end_of_elaboration callback or in simulation

Processes created with SC_METHOD, SC_THREAD, SC_CTHREAD macros

called unspawned processes, typically static processes

Processes created with sc_spawn function called spawned processes

Typically create dynamic processes

sc_process_handle template <class T> sc_spawn (T fobject,

chqr* pname = 0, sc_spawn_options* opt = 0)

sc_process_handle template <class T> sc_spawn (

typename T::result_type* res, T fobject,

chqr* pname = 0, sc_spawn_options* opt = 0)

sc_spawned_options – contains process options including

spawn_method(), set_sensitivity(), reset_signal_is(),

async_reset_signal_is(), dont_initialize()

115

...

SC_CTHREAD(proc);

...

int ret;

int f(){...};

void proc() {

sc_spawn_options opt;

opt.spawn_method();

opt.set_sensitivity(&sig);

// create process with options

sc_spawn(f, "f1", &opt);

// create process with result value

sc_spawn(&ret, fr, "f2", &opt);

// create several processes with waiting for termination

SC_FORK

sc_spawn(f,…), sc_spawn(g,…)

SC_JOIN

}

116

Process control

sc_process_handle – process descriptor that allows to control process

execution

class sc_process_handle {

...

bool dynamic();

bool terminated();

void suspend(…);

void resume (…);

void disable (…);

void enable (…);

void kill (…);

void reset (…);

sc_event& reset_event();

}

117

sc_process_handle a, b; // Two empty handles

SC_CTHREAD(g, clk.pos());

SC_CTHREAD(f, clk.pos());

a = sc_get_current_process_handle();

...

b = sc_spawn(...);

a.suspend();

wait(10, SC_NS);

a.resume();

b.reset();

wait(10, SC_NS);

b.kill();

118

Design architecture

119

Design architecture

Complex design contains tens to hundreds of modules which should be

organized in modules hierarchy

Module class (inheritor of sc_module) consists

Module

ProcessNProcess1

Logic implementationData fields

Child modules

Por

ts/e

xpo

rts

120

sc_port sc_port<T> – port belongs to the module, provides methods to call from the

module processes

sc_in, sc_out, sc_inout – are particular cases of sc_port template

Port may be bound to

Channel with the same value type T (sc_signal<T>)

Another port in the parent/child module

Another export in a child module

sc_in

sc_outChild

module

Parent module

sc_in

sc_out

sc_in

sc_out

sc_in sc_out

sc_signalChild module A

Child module B

121

Port bound to a channel translates method calls to the channel instance

class A : public sc_module {

sc_in<T> port_in;

void proc() {

T var = port_in.read(); // Call sig.read()

}}

class B : public sc_module {

sc_out<T> port_out;

void proc() {

port_out.write(val); // Call sig.write()

}}

class parent : public sc_module {

A a; B b;

sc_signal<T> sig;

parent() : a(“a”), b(“b”) {

a.port_in(sig);

b.port_out(sig);

}}

122

Port bound to a port of parent module instance in parent constructor

class A : public sc_module {

sc_in<T> port_in;

void proc() {

T var = port_in.read(); // Call parent port_in.read()

}}

class parent : public sc_module {

A a;

sc_in<T> port_in;

parent() : a(“a”) {

a.port_in(port_in);

}}

What method is called from parent port_in.read()?

Is it possible to bind sc_in to sc_out directly, without channel?

123

sc_port with user defied interface sc_port is template class with interface parameter

template <class IF> class sc_port_b : public sc_port_base {

IF* operator->();

sc_interface* get_interface();

...}

class myIF : public sc_interface {int func(int);} is user defined and may

contain arbitrary methods

sc_port<myIF> myPort;

myPort->func(val);

sc_in, sc_out, sc_inout have predefined interface

template <class T> class sc_in : public sc_port<sc_signal_in_if<T>,1>

{...}

Module with sc_port or its inheritors may calls methods of the interface from

the processes

124

sc_export sc_export – export belongs to a module provides methods to call from

outside of this module

template<class IF> sc_export {...}

Providing interface via export is an alternative to implements interface

by the module

class myModule : public sc_module, public myIF {...}

class myModule : public sc_module {

sc_export<myIF> export; ...}

125

class myIF : public sc_interface{

int func(int val);

}

class A : public sc_module, private myIF {

sc_export<myIF> exp1;

A(const sc_module_name& name) : sc_module(name), exp1("exp1") {

exp1(*this);

}

int func(int val) {...}

}

class B : public sc_module {

sc_port<myIF> port1;

void proc () {

val = port1->func(1);

}}

A a(“a”); B b(“b”);

b.port1(a.exp1);

126

Hierarchical connections

Port of child modules connected to ports of parents

Must be the same direction

Process inside of most internal module provides sc_out` value

sc_in

sc_out Module

sc_in

sc_out

sc_in

sc_out

Module

Module

127

Internal connections

Processes connected with channels (sc_signals), no port/export required

Child modules connected with channels (sc_signals)

sc_in sc_out

sc_signalChild module A Child module B

sc_in

sc_outsc_signal

sc_signal

128

Bad connection examples

C++ allows to create some tricky things which are correct but hard to

understand and may lead to synthesis issues

Child module A Child module B

sc_signalprocess process

sc_signal

129

Interface method call

Call a method from a process of another module

Usually called method is declared in module or export interface, that looses

modules implementation

Allow accessing the module fields, including signals

In synthesis such modules are joined together

Child module A Child module B

process

sc_signal

process

IF

Call of IF method

130

Connection delay

Channel (sc_signal) update time is one delta cycle

Chain of channels connected with SC_METHOD logic may have arbitrary delay in

delta cycles

How this delay should be considered? Is different delay on signals correct?

A

sc_signal

Process 1

Method process

sc_signal

Process 2

sc_signalB

A+B

131

Design partitioning

Module may contain

processes and child modules

child modules only

Balanced module size

Linked logic placed in one module or in several modules instantiated in

common top module

Module reuse and design easy reconfiguration strategies

Large module may be connected with an intra-chip buses

Taking into account synthesis tool recommendations

132

SystemC under hood

133

sc_object

sc_object – base class for most SC classes including sc_module,

sc_process, sc_port, sc_prim_channel

sc_event, sc_processs_handle, sc_time are not child of sc_object

class sc_object {

sc_object();

sc_object(const char*);

const char* kind(); // Get object type string, for example “sc_module”

void print( std::ostream& = std::cout ); // Print name

void dump( std::ostream& = std::cout ); // Print name and kind

const char* name(); // dot-separated hierarchical name

const char* basename(); // object name

std::vector<sc_object*>& get_child_objects();

std::vector<sc_event*>& get_child_events();

sc_object* get_parent_object();

trace(sc_trace_file*) // Puts object values into VCD-file

}

134

name and basename

SC_MODULE(Module) {

sc_signal s;

Module() : s(“signal”)

}

SC_MODULE(TopModule) {

Module m;

sc_in_clk clk;

TopModule() : m(“mod”), clk(“clock”)

}

TopModule t(“top”);

...

cout << s.name() << s.basename(); // Puts “top.mod.signal” and “signal”

135

Trace functions

Value change dump (VCD) file, contains time-ordered sequence of values

class sc_trace_file {

void set_time_unit( double , sc_time_unit );

}

sc_trace_file* sc_create_vcd_trace_file( const char* name );

void sc_close_vcd_trace_file( sc_trace_file* tf );

void sc_trace(...); // Trace value passed in second argument to file passed

// in first argument with identifier in third argument

// There are several overloaded version for various parameter types

void sc_trace( sc_trace_file* , sc_dt::sc_uint_base& , const std::string& );

void sc_trace( sc_trace_file* , const bool& , const std::string& );

...

sc_object method trace() uses sc_trace to output values

136

Trace functions

Trace method is implemented for channels (sc_signal/sc_fifo)

Implemented in update() method

Is deprecated

Need to define DEBUG_SYSTEMC before #include “systemc.h”

VCD signal diagram viewers

GTKWave (GNU license)

Commercial tools like VCS, Insicive, …

137

Trace example

SC_MODULE(Module) {

sc_signal<bool> B;

sc_signal<sc_uint<4> > C;

sc_trace_file* tf;

SC_CTOR(Module) : clk("clk"), B("B"), C("C")

{

tf = sc_create_vcd_trace_file("trace1");

B.trace(tf);

C.trace(tf);

}

~ModA() {sc_close_vcd_trace_file(tf);};

Makefile:

$(CXX) ... -DDEBUG_SYSTEMC ...

138

Object hierarchy exploration

SC_MODULE(Module) {

sc_event e;

Module() : e(“event”);

...

events = get_child_events(); // e

parent = get_parent_object(); // t

}

SC_MODULE(TopModule) {

Module m;

sc_in_clk clk;

TopModule() : m(“mod”), clk(“clock”)

...

objs = get_child_objects(); // m, clk

}

TopModule t(“top”);

139

System functions

Simulation control functions

sc_start(), sc_start(int)

sc_stop()

sc_pause()

sc_time_stamp() – simulation time

sc_delta_count() – delta cycle in current simulation time

sc_get_status () – returns current simulation phase and simulatior state

(SC_ELABORATION, SC_RUNNING, SC_PAUSED, SC_STOPPED, …)

void set_stack_size( size_t ) – sets the stack size of an unspawned

process instance during initialization

SC_DEFAULT_STACK_SIZE = 0x20000 (0x50000)

140

Assertions

C++ assert (assert.h)

sc_report and sc_report_handler allow flexibility reporting an issue and

processing report with predefined actions

SC_REPORT_INFO( msg_type , msg )

Info: msg_type : msg

SC_REPORT_WARNING( msg_type , msg )

Warning: msg_type : msg

In file: main.cpp:23

In process: mod_a:proc @ 40ns

SC_REPORT_ERROR( msg_type , msg )

Like warning but stops simulation

SC_REPORT_FATAL( msg_type , msg )

Like warning but terminates application

sc_assert, sc_interrupt_here, sc_stop_here

141

Design verification

142

Verification techniques

Dynamic methods – simulation design with testbench and control results in

some design points

Static methods – design code analysis to detect design structure defects,

verify constraints and assertions, find out synchronization errors

143

Static verification methods

Basic approaches

Static analysis

Model checking

Theorem proving

Existing static checkers

Lint – a tool does code analysis to check templates

Synthesis tool built-in checkers

External analysis tools

144

Dynamic verification methods

All dynamic methods requires design simulation, differences are in

Input signal setup

Control points used

Matching simulation result with reference

SystemC simulators

OSCI distribution

Cadence Incisive (ncsim)

Synopsys VCS

ModelSim

145

Dynamic verification

Input signal setup

Reference model

Input vectors

Verification IPs

Testbench that models the environment

Control points used

Design interface

Internal points, may be specified with debug outputs or assertions

Matching simulation result with reference

Reference model output matching, provided by some simulators

Output vectors

Verification IPs

Testbench control results

146

Testbench development

Testbench imitates input signals of the design-under-test (DUT) and match the

results with control values

sc_in

sc_out DUT

Testbench

Processes

sc_in

sc_out DUTTestbench

147

Debug tools and methodology

SystemC design usually developed in a C++ IDE, so using C++ debugger is

one of the common ways

Debug with print and debugger features

Challenge is high parallel design architecture

Efficient to debug an issue localized in processes and long in time

Coarse grained bug localization

Algorithmic issue debug

Signal diagram viewer to debug

Normal way for hardware designs

Required to give object name in constructor, normally the same as a variable name

Efficient to debug an issue localized in time, with a number of parallel processes

Final bug localization

The analyzed diagrams fit one or several screens

Interface issue debug, synchronization issue debug

148

Assertion based verification

Any real design should have some assertion

Assertion used for

Testing internal logic of the design, improve observability

Bug detection with constraining the occurrence of a bug

Assertions of module interface prevent incorrect using the module

Assertion used in simulation and formal verification

There is no SVA analog in SystemC yet

149

Mixed language simulation

Most simulators support Verilog, VHDL, SystemC in mixed design/testbench

simulation

Legacy code and standard components may be developed in some HDL

No difference in simulator reports/diagrams

Typically SystemC design has SystemC testbench, which may be reused for

generated RTL verification

Generated RTL need to be verified as SystemC simulation differ from RTL

Using binary logic instead of 4-value logic, ‘0’ in SystemC, ‘X’ in RTL for non-reset

variables

No UPF support and no power features verification in SystemC

150

SystemC UVM

Universal Verification Methodology (UVM) 1.2, 2014

Analog of Verilog UVM in SystemC

UVM provides library and a methodology for testbench architecture and

implementation

151

High level synthesis

152

High level synthesis

HLS is a procedure of translation SystemC program to another language

Verilog

VHDL

Program transformation is done by most compilers

GCC has several SSA-based representations

LLVM frontends translates input language to IR

HLS specific is the target design in Verilog/VHDL should be

synthesizable into hardware =>

All design elements must be statically determined

153

Statically determined elements

Design elements

Structural elements: modules, ports, channels, fields and variables

Process functions

Structural elements are created at elaboration phase

Element instances and their properties must be statically determined, i.e. be

specified in source code in a form which the HLS tool supported

Process functions

Spawned processes cannot be statically determined in general case, so only

unspawned processes are synthesizable

Function behavior must be statically determined to HLS tool is able to create

equivalent combinational logic and FSM

154

Synthesizable subset standard

SystemC like Verilog/System Verilog includes language statements not

intended for synthesis

HLS tools support different subsets of SystemC

SystemC synthesizable standard intended to hardware designer and HLS tool

developers

Portability SC designs between HLS tools

Define minimal subset, which may be extended HLS tool vendors

SystemC synthesizable standard 1.4.7 is a part of IEEE1666, provided by

Accellera, March 2016

155

Design structure

Multiple translation units supported

Libraries are not supported

Pre-processing directive supported, usage specified by HLS tool

Top level module is not specified, should be specified by HLS tool parameter/script

156

Synthesizable modules Module type should be declared with

SC_MODULE macro

Class or template class inherited from sc_module

Explicit and implicit template instantiation is supported

Full and partial template specialization is supported

Class member fields are supported

Access to non-const variable allowed from one process only

Inter-process communication should use sc_signal`s

Class constructors are supported

Pointer initialization, object allocation with new, port/signal creation and binding

Constant integer field initialization, initialization of other data members is prohibited

Processes creation and sensitivity specification

Copy constructors and assignment are disabled, destructors are ignored

157

Module parametrization

All structural elements including modules are created at elaboration phase

Module parametrization

Field and function types may be specified via template parameters

Array length may be specified as literal, static constant or template parameter

Other module properties may be specified via template parameters and via

constructor

158

Module parametrization exampletemplate <class element_type>

void func(element_type& elem) {

elem.clk(clk); // Bind port to signal

enable(elem.enable); // Bind port to signal

elem.bind_to(this); // Call method

}

template <class elem_type, unsigned N>

class module : public sc_module {

static const unsigned M = N >> 2;

elem_type A[5];

elem_type B[N];

elem_type C[M];

elemt_type* D;

explicit module(sc_module_name& name,

const unsigned K) : sc_module(name) {

D = new D(“D”);

}}

159

Synthesizable processes

Process creation with SC_CTHREAD, SC_METHOD and SC_THREAD

Dynamically created processes (sc_spawn) are not supported

Process control via sc_process_handle is not supported

Process creation may be parametrized with template and constructor

parameters

160

Synthesizable method process

SC_METHOD allowed to describe combinational logic without latches

Sensitive to all signal must be set

All outputs must be signal or ports

Each output must be a function of inputs and nothing more

Each output must be assigned on every execution path

No synchronization like wait/notify

161

Synthesizable thread process

SC_CTHREAD and SC_THREAD are synonyms

Must be sensitive to exactly one clock edge and have at least one reset (at most

one synchronous and at most one asynchronous reset)

Processes in module may have different clocks/resets

Thread body contains reset section and one infinite main loop

Optional reset section finished with wait()

Multiple wait() are possible between reset section and main loop

Main loop may contain wait() and wait(int) only

No event synchronization

Thread process translated to combinational logic and FSM

Each wait() statement add new state in FSM

No execution paths without wait(), normally each main loop iteration should have

one or more wait()

162

Synthesizable processes example

void methodFunc(){

// Some logic without any wait statements

}

void procFunc(){

// Optional reset section, initialization of signals and variables

wait();

// Optional operational behavior

wait();

wait();

// Main loop

while (true) {

// Some logic with wait() and wait(int) calls

wait();

}

}

163

Loop transformation

All loops except thread process main loop must

Be unrolled if loop body has no wait() statement

Have one or more wait() statements

Number of loop iteration must be statically determined

Loop unrolling – create a number of copies of loop body equal with loop

iteration number

Number of logic increased

Partial loop unrolling

Loop breaking – add one or more wait statement into loop body

Loop with wait statements may be pipelined

Loop pipelining – for loop with several states, which separates processing stages,

provide parallel execution of processing stages

164

Loop pipelining example

sc_in<T> a, b;

T c, d;

for (int i = 0; i < N; i++) {

c = a + b;

wait();

d = c << M;

wait();

}

sc_in<T> a, b;

T c, d;

c = a + b;

wait();

for (int i = 0; i < N; i++) {

d = c << M;

c = a + b;

wait();

}

• Manual loop pipelining

• HLS tools usually support loop pipelining without code modification

• Initiation interval and latency interval

165

Loop pipelining example

c = a + b d = c << M

c = a + b d = c << M

Clock ticks / Loop iteration

0

10 2 3

1

c = a + b d = c << M

c = a + b d = c << M

Clock ticks / Loop iteration

0

10 2 3

1

c = a + b d = c << M2

166

Synthesizable channels and ports

sc_signal<T> with one writer (SC_ONE_WRITER) is only supported

Other channels and sc_event are not supported

sc_in<T>, sc_out<T> and sc_inout<T> ports are supported

T should not be sc_logic

167

Synthesizable data types

Native C++ and SystemC types

Fundamental C++ types

Integer types and literals supported

Floating point literals supported only

Compound types have restricted support

Statically determined pointers are supported

References are supported

SystemC types

sc_int, sc_uint, sc_bigint, sc_biguint, sc_fixed, sc_ufixed, sc_bv

sc_logic and sc_lv are supported without X and with Z restricted support

bit() and range() operators are supporteds

concat() and reduction are supported

168

Synthesizable expressions and others

Function calls are supported except recursive functions

Type conversion is mostly supported

sizeof() is not supported

new and delete

new is supported for all C++ types, SC data types and sc_module/

sc_port/sc_signal

delete is not supported

Most functions of standard C/C++ library are not supported

printf, fprintf , cout << are ignored

169

HLS tool demo

mult_0

mult_1

mult_4

dispatchProc

respProc

readyProc

...

soc

170

Transaction Level Modelling

171

TLM Intro

Transaction level modelling provides higher abstraction level, above SystemC

Less code, more functionality

Reuse components for common operations

Speed up simulation process

The most low level details are required for process interaction description

TLM suggests to describe process interaction with interface function calls

172

TLM Intro

TLM = Methodology + coding guidelines + library classes

Transaction level modelling (TLM)

Is a part of SystemC standard

TLM 1.0

TLM 2.0

TLM is synthesizable with some limitation

173

TLM function call

sc_port<IF> port;

void process1() {

...

// Bad code style

module2.send_data(...);

// TLM style

this->port.send_data(...);

}

sc_export<IF> port;

sc_signal<int> data;

void send_data(int val) {

data.write(val);

}

void process2() {

...

int a = data.read();

}

Process 1

FunctionCall

Process 2

FunctionCall

Module1 Module2

exp

ort

por

t

174

TLM interface

class IF = public virtual sc_interface {

void func1(int);

int func2(bool, unsigned);

}

class module2 : public sc_module, public IF {

// There must be implementation of func1() and func2()

}

class module2 : public sc_module {

sc_export<IF> export;

module() {

// There must be binding export to an object implemented

// func1() and func2()

export.bind(...); // to this module or to child module

}

}

IF is a parent of sc_interface - contains function declarations

175

Reset in TLM

class IF = public virtual sc_interface {

void reset();

...

}

class module2 : public sc_module, protected IF {

sc_export<IF> export;

sc_signal<int> data;

module() {

export.bind(this);

}

void reset() {

data = 0;

}

}

To initialize variables and signals by reset special function should be used

Several reset function

176

TLM function call

sc_export<IF_A> export;

sc_port<IF_B> port;

// IF_A function in channel

void send_data(int val){

data.write(val);

};

// Process in channel

void channel_process() {

B_send_data(val);

}

Process 1

FunctionCall

Process 2

FunctionCallChannel

Module1 Module2

exp

ort

por

t

exp

ort

por

t

IF_A IF_B

177

TLM channel

class IF_A = public virtual sc_interface {

void send_data(int);

}

class IF_B = public virtual sc_interface {

void send_data(int);

}

// sc_channel is typedef of sc_module

class channel : public sc_channel, public IF, protected IF_A {

sc_export<IF_A> export;

sc_port<IF_B> port;

channel() {

export.bind(*this);

SC_METHOD(channel_proc); sensitive << data;

}

// IF_A function in channel

void send_data(int val){data.write(val);}

// Process in channel

void channel_proc(){

port.send_data(data);

}}

178

TLM 1.0

TLM 1.0 provides several common way interfaces

Blocking – operation is blocked until required data/slot is ready

Non-blocking – operation return false if required data/slot is not ready

TLM 1.0 operates with

sc_interface

sc_port, sc_export

sc_channel

179

TLM 1.0 blocking interfaces

template < typename T > class tlm_blocking_put_if: public virtual sc_interface {

virtual void put( const T &t ) = 0;

}

template < typename T > class tlm_blocking_get_if: public virtual sc_interface {

virtual T get( tlm_tag<T> *t = 0 ) = 0;

virtual void get( T &t ) { t = get(); }

};

template < typename T > class tlm_blocking_peek_if: public virtual sc_interface {

virtual T peek( tlm_tag<T> *t = 0 ) const = 0;

virtual void peek( T &t ) const { t = peek(); }

}

180

TLM 1.0 non-blocking interfaces

template < typename T > class tlm_nonblocking_put_if: public virtual sc_interface {

virtual bool nb_put( const T &t ) = 0;

virtual bool nb_can_put( tlm_tag<T> *t = 0 ) const = 0;

virtual const sc_core::sc_event &ok_to_put( tlm_tag<T> *t = 0 ) const = 0;

};

template < typename T > class tlm_nonblocking_get_if: public virtual sc_interface {

virtual bool nb_get( T &t ) = 0;

vitual bool nb_can_get( tlm_tag<T> *t = 0 ) const = 0;

virtual const sc_core::sc_event &ok_to_get( tlm_tag<T> *t = 0 ) const = 0;

};

template < typename T > class tlm_nonblocking_peek_if: public virtual sc_interface{

virtual bool nb_peek( T &t ) const = 0;

virtual bool nb_can_peek( tlm_tag<T> *t = 0 ) const = 0;

virtual const sc_core::sc_event &ok_to_peek( tlm_tag<T> *t = 0 ) const = 0;

};

181

TLM 1.0 synthesis TLM 1.0 is synthesizable with the following restrictions

A channel must derive from class sc_module (sc_channel)

Synthesis does not support asynchronous communication; therefore, methods that

return sc_event references are not supported.

Custom ports (classes derived from sc_port/sc_export) are not supported

Number of processes access to sc_port/sc_export is restricted by one at delta

cycle

182

TLM 2.0 Transport interfaces

TLM 2.0 includes TLM 1.0

http://www.cl.cam.ac.uk/research/srg/han/ACS-

P35/documents/TLM_2_0_presentation.pdf

183

SystemC vs SystemVerilog

SystemC and System Verilog synthesizable subsets are discussed

SystemC advantages

Power of C++

Reference algorithms usually are in C/C++

Libraries may be used for TB

More flexibility in design configuration and component reuse

Higher level of abstraction, that leads to more compact and clear* code

SystemC most important features

Multiple wait processes

Module inheritance

Template class

Template function – passing arbitrary object as function argument

Class as template parameter – parametrizing with module type

Functor as template parameter – parametrizing with functionality

184

Resume

SystemC and HLS is quite new and promising methodology, which evolution

is slow down because of conservative hardware designer community

SystemC has lots of lacks

No explicit memory description

No power specification support

No synthesizable subset commonly adopted standard

Anyway we need more efficient HDL than there are, SystemC is one

of such attempts

top related