Documente Academic
Documente Profesional
Documente Cultură
© 2000 Author: Martin Wang 3 Days SystemCTM training based on SystemC Ver. 1.0
Author: Martin Wang of SLD
Workshop Prerequisites
2
Ver 1.4
1
Workshop Target Audience
System Architects
HW Engineers responsible for board, ASIC and
FPGA design
Test/Verification Engineers
Programmers, software developers
SystemCTM
3
Ver 1.4
Workshop Goal
4
Ver 1.4
2
Workshop Measurable Objectives
By the end of this workshop, you should be able to:
5
Ver 1.4
2 SystemCTM - Introduction
6
Ver 1.4
3
Agenda: Day One
DAY
1
Unit Topic Lab
7
Ver 1.4
8
Ver 1.4
4
Agenda: Day Three
DAY
3
Unit Topic Lab
16 Refinement
17 Functional I/F
18 Hardware/Software Co-verification
9
Ver 1.4
19 System-on-a-Chip
20 Workshop Summary
10
Ver 1.4
5
Agenda: Structured Labs & Exercises
DAY
Lab Topic Lab
1 Getting Started
5 Multiple-Cycle RAM
Agenda: Labs
DAY
Lab Topic Lab
7 Image Smoother
Labs & exercises will challenge your understanding of the concepts taught
Additional experimentation labs are provided for those who might finish the required labs early
12
Ver 1.4
6
Icons Used in this Workshop
Icon What it Means Icon What it Means
Question Note
13
Ver 1.4
Acronym Meaning
Hardware Description
HDL
Language
Synopsys On-Line
SOLD
Documentation
14
Ver 1.4
7
Agenda: Day One
DAY
1
Unit Topic Lab
2 SystemCTM - Introduction
15
Ver 1.4
Today’s Market
5 10 15
16
Ver 1.4
8
Designers Challenges
Design Complexity is becoming greater
Design Complexity is still increasing
System on a Chip
High level
Design Complexity Behavioral Synthesis
Cycle-Based Simulation
Design Reuse
Deep Submicron
Gates
Logic
Synthesis
Transistors
IC Development Software
The Verification Process
Hardware Code development
Implementation RTOS details
Decisions
Done mainly in
$$ Done mainly in C/C++
Verilog/VHDL Emulation /
Prototyping
EDA Environment C/C++ Environment
Productivity Gaps
18
Ver 1.4
9
IC Development Process
The current design flow
Same flow for RTL, schematic, polygons, etc
Design done then captured in an EDA environment
Very little, if any, “what-if” exploration
Designers can end up focussing more on “data management”
than “design”
Library-based SystemDesign Methodology
19
Ver 1.4
1. Conceptualize
2. Simulate in C++ 5. Understand
3. Write specification 6. (Re)Implement in HDL
document 7. (Re)Verify
8. Synthesize from HDL
20
Ver 1.4
10
C++ Based Flow
C/C++
C/C++
1. Conceptualize
2. Simulate in C++
3. Write specification
document
4. Hand over
• Executable specification
• Testbench
• Written specification
5. Understand
6. Refine in C++
7. Verify reusing testbenches
8. Synthesize from C++
Testbench re-use
C/C++
System
Architect SoC Marketing
& Sales
Software Hardware
Designer Designer
22
Ver 1.4
11
Existing Approaches are limited ...
Sub-optimal QoR
23
Ver 1.4
24
Ver 1.4
12
Summary
25
Ver 1.4
2 SystemCTM - Introduction
26
Ver 1.4
13
C++ powered by SystemCTM
Purely Algorithm
/Software in C++
What is SystemC ?
SystemC is a C++ Class library
HW/SW partitioning Include any C++ programs, libraries, encapsulation
... a methodology for modeling SoC designs consisting DSPs, ASICs, IP-
Cores, Interfaces, ...
High Level Abstract
Hardware Model in SystemC also enables
SystemC
Modeling at high level of abstraction e.g. communication protocols
C++ Software Model Refinement to hardware
Software modeling - interrupts, exception handling
System wide verification
Hardware/Software co-verification
IP exchange
Behavioral Level
SystemC provides all the advantages of Verilog and VHDL
Hardware Model in
SystemC Concurrent processes e.g. methods, threads, clocked threads
Concept of a clock
C++ Software Model Wide variety of bit-true data types
SystemC IS NOT
Another C++ dialect -> it is C++
Just for hardware modeling only -> you can model hardware AND
Register Transfer software in C++ with SystemC
Level Hardware
Model in SystemC
C++ Programs 27
Ver 1.4
HDL constructs
• Source Code
• User Guide
• Reference Manual
• Discussion Forum
• All available from http://www.SystemC.org
28
Ver 1.4
14
Getting Started with SystemC
Compiler
gcc
native compiler Visual C++, SUN cc
Debugger
gdb, ddd
lint, profiler, memory access checking
quantify, purify
www.gnu.org
29
Ver 1.4
First example
Compiler version
which gcc, gcc -v
which architecture is used
autoconf helps installation
./configure; gmake
Makefiles control what is included
compile directives
libraries
include files
30
Ver 1.4
15
Books/Training
31
Ver 1.4
libraries
linker ASIC
32
Ver 1.4
16
A SystemCTM System
System consists of a set of concurrent processes
Process
describes functionality
Processes communicate with each other through
signals and channels
Processes can be combined into modules to create
hierarchy
System
Process 3
Process 4
signals
Process 1 Process 5
Process 2
channel Module 1
33
Ver 1.4
Simple Example - 1
clk
main.cpp out
34
Ver 1.4
17
Simple Example - 2
// top level routine/level
#include “systemc.h”
#include “adder.h”
main.cc
#include “stimgen.h”
#include “monitor.h” a1 in1
Stimulus Response
Adder out re
int sc_main(int ac, char *av[ ]){ Generator Monitor
a2 in2
// Create signals to tie modules
sc_signal<int> s1; clk
sc_signal<int> s2;
sc_signal<int> s3;
// Create clock
sc_clock clock(“CLOCK”, 10, 0.5); stimgen.cpp adder.cpp monitor.cpp
// Simulate
sc_start(200);
return(0); // since sc_main have
// type of int, return 0
// means no error.
}
35
Ver 1.4
Simple Example - 3
main.cc
// header file adder.h a1 in1
struct adder : public sc_module { Stimulus Response
Adder out re
// Input ports Generator Monitor
sc_in_clk CLK; a2 in2
sc_in<int> in1;
sc_in<int> in2; clk
// Output ports
sc_out<int> out;
// Constructor
adder (const char * NAME)
: sc_module(NAME) { stimgen.cpp adder.cpp monitor.cpp
sc_sync_tprocess(handle1,”ADDER”,
adder, entry, CLK.pos()) stimgen.h adder.h monitor.h
end_module();
}
36
Ver 1.4
18
Simple Example - 4
main.cc
a1 in1
Stimulus Response
// Implementation file adder.cc Adder out re
Generator Monitor
#include “systemc.h”
#include “adder.h” a2 in2
void clk
adder :: entry( )
{
while (true) {
out = in1 + in2;
wait( ); stimgen.cpp adder.cpp monitor.cpp
out = in1 + in2 + 2;
wait( ); stimgen.h adder.h monitor.h
}
}
main.cpp
37
Ver 1.4
// Create clock
sc_clock clock(“clock”, 10, 0.5); // Implementation file mac.cc
#include “mac.h”
// Instantiate Processes void mac :: entry( ){
mac MAC(“MAC_BLOCK”);
int int_var; // internal variables
MAC << clock << s1 << s2 << s3 << s4; while (true) {
// other processes e.g. stimulus generator, monitor rdy = false;
// Simulate int_var = in1 * in2;
sc_start(200); wait( );
return(0); out = out + int_var;
rdy = true;
}
wait( );
}
}
38
Ver 1.4
19
So, How to create a SystemC Model
39
Ver 1.4
Summary
SystemC - Introduction
covered a short history of SystemCTM
covered how to use SystemCTM
covered a basic SystemCTM example
covered how to create a SystemCTM model
40
Ver 1.4
20
Lab 1: Getting Started - 1
Primary Objective:
Understanding A SystemC System
This lab introduces the process of simulating with SystemCTM.
You will simulate a simple counter that counts up to seven, then
wraps around to zero. The counter can be reset at any point.
41
Ver 1.4
2. Run lab1.x You should see the counter counting and being reset
Where:
-o lab1.x The resulting executable file will be called lab1.x
*.o Link together all the object files
-lsystemC-g Link with the library file libsystemC-g.a
-L../lib Look for the previous library in the ../lib dir
-lstdc++ Link with the standard I/O library
42
Ver 1.4
21
Lab 1: Sample Output
43
Ver 1.4
Tip:
To enable source-level debugging, compile
with the -g option in gcc
44
Ver 1.4
22
Lab 1: Debugging with SystemCTM - 2
45
Ver 1.4
46
Ver 1.4
23
Lab 1: Overview of ddd - Free Graphical C++ Debugger
http://www.gnu.org/software/ddd/
47
Ver 1.4
Open lab1.x
48
Ver 1.4
24
lab 1: Debugging with ddd - 2
49
Ver 1.4
Outputs window
50
Ver 1.4
25
Lab 1: Debugging with ddd - 4
51
Ver 1.4
52
Ver 1.4
26
Lab 1: Debugging with ddd - 6
53
Ver 1.4
54
Ver 1.4
27
Case Study: Digital Video Camera Design Project
Subsequent labs will be based on the following design specification. By
modeling different modules using different abstraction levels we will learn
the capabilities of SystemCTM
Challenge
Need to prove the concept -> ask for design
funding FAST from management.
Complete design as fast as possible.
IP Reuse, minimum changes to IP.
Need to quickly explore different architectures
before actual implementation.
Easy and quick validation/debug.
Need a golden C++ model.
Need a system model for software development
before hardware design complete.
Quick to Prototyping.
55
Ver 1.4
• HW or SW Implementation:
ation ation ³ Optimized VLSI architecture
that executes algorithms
efficiently and rapidly
• Integration/Verification:
System Integration and Verification ³ Functional correctness of
(System Test) the implementation of the
SYSTEM
56
Ver 1.4
28
Case Study: Digital Video Camera System View
DSP ASIC
CPU Core Application Software,
Device Driver… in C++
Reg Decode DSP Core FFT
from Company X While (…) {
BUS ...
Fetch
Assembly code/
Machine Code
DMA Network
Memory Add R1, R2, R3 0000 0110110010110101
1000 0111100001010101
Interface mul R2, R4. R5
0100 0011111010101011
1100 0010101011111001
0010 1101010111010101
1010 0000000011010101
bnz loop1 0110 0111111110010111
SystemCTM models
C++ models
57
Ver 1.4
29
Agenda: Day One
DAY
1
Unit Topic Lab
2 SystemCTM - Introduction
59
Ver 1.4
Comments
Single line comments:
• Begin with "//" and end with a carriage return
• May begin anywhere on the line.
Multiple line comments:
• Begin with "/*" and end with a "*/"
• May begin and end anywhere on the line
• Everything in between is commented out
60
Ver 1.4
30
Strings
61
Ver 1.4
If and if-else
syntax:
if (expression) statement;
If the expression evaluates to true then execute the statement (or
statement group)
if (expression) statement1;
else statement2;
If the expression evaluates to true then execute statement1,
If false, then execute statement2 (or corresponding statement groups).
if (Sel_A == 1){
Data_D 0 Data_Out = Data_A;
}
else if (Sel_B == 1) {
Data_C 1
Data_Out = Data_B;
Sel_C 0
}
else if (Sel_C == 1) {
0
Data_Out = Data_C;
Data_B 1 Data_Out
}
1 else
Sel_B
Data_A Data_Out = Data_D;
Sel_A }
62
Ver 1.4
31
Case statement
syntax:
switch (expression){
case_item_1: statement or statement_group
break;
case_item_2: break; REMEMBER TO PUT BREAK!
case_item_3: statement or statement_group
break;
case_item_n: statement or statement_group A 00
break; B 01
default: statement or statement_group D_Out
C 10
break; D 11
}
Sel(1 downto 0)
63
Ver 1.4
64
Ver 1.4
32
SystemCTM Modeling Constructs
SystemC Modeling
Modules
Clocks Operations
Loop Exits/
I/O Variables Continues
65
Ver 1.4
Example:
struct RandNum
{ Function can be a data member
unsigned long seed;
unsigned short getRand();
}
Bad idea to allow users of an object to directly use and manipulate internal data
Better to provide a public interface
66
Ver 1.4
33
C++ Classes and Data Abstraction
C++ provides modifiers to control access to data:
public (default) IP
private
protected
In C++, a class default is private. Struct default is public
Member access specifier
Example:
class Time{
private:
int hour;
int minute;
int second;
public:
Time();
void setTime(int, int, int);
void printMilitary();
void printStandard();
}
67
Ver 1.4
Example:
rv.hour = 12;
68
Ver 1.4
34
Data Initialization
C++: A special member function (constructor) is automatically called
by the compiler.
Constructor has same name as the class or struct, with no return
type
Example: You can have more than
class Time{
private: one constructor, so you
int hour, minute, second; can initialize your data in
public:
Time(); different ways
void setTime(int, int, int);
void printMilitary();
void printStandard();
}
// constructor initialize each data members Don’t forget class name and :: !
Time::Time() { hour = minute = second = 0;}
void Time::setTime (int h, int m, int s) {
hour = ..
}
void Time::printMilitary() {
cout << (hour < 10 ? …
}
69
Ver 1.4
35
Operator & Function Overloading
C: Multiple functions with unique names
C++: Functions with the same name, different arguments
C++: Define how operators interpret data, as if built into the
language.
C++ is strongly typed
Need more flexible, generic object e.g. Instances differ only in type
71
Ver 1.4
Inheritance
72
Ver 1.4
36
References vs. Pointers
73
Ver 1.4
int main() {
const float PI = static_cast<float>(::PI);
Global value = 3.14159265358..
cout<<setprecision(20)
<<“Local value of PI= “<<PI
<<“Global value of PI= “<<::PI<<endl;
return 0;
}
74
Ver 1.4
37
I/O in C++
C++ simplifies I/O considerably
Standard variables: cout, cin, cerr
Operators: << for writing, >> for reading
Formatting manipulators
endl Output end-of-line (\n)
setw(int) Set the width of the output
hex Output numbers in hexadecimal format
setprecision(int) Sets floating-point output precision
Streams
file, network
memory buffer
Example:
#include <iostream.h>
#include <iomanip.h>
main() { Output:
int i = 12; 1234567890
float r = 12.34; 12
cout << “1234567890” << endl; c
cout << i << endl; 12.34
cout << hex << setw(4) << i << endl; 12.3
cout << r << endl;
cout << setprecision(1) << r << endl;
}
75
Ver 1.4
76
Ver 1.4
38
Why Objects for hardware?
struct cmult : sc_module {
sc_in_clk clk;
sc_in<bool> new_data;
sc_in<sc_int<8> > data_in;
sc_out<sc_int<8> > data_out;
sc_int<8> a;
void entry() {
sc_int<8> b, c, d;
while(true) {
wait_until(new_data.delayed() == true);
a = data_in.read();
#if DEBUG
dump();
#endif
wait();
…
data_out.write(a*c-a*d);
}
};
void dump() {
cout << “Information : cmult new data item “ << a << endl;
};
SC_CTOR(cmult) {
SC_METHOD(entry, clk.pos());
}
}
77
Ver 1.4
Summary
78
Ver 1.4
39
Agenda: Day One
DAY
1
Unit Topic Lab
2 SystemCTM - Introduction
79
Ver 1.4
Data Types
C++ built in data types may be used but are not
adequate to model Hardware.
long, int, short, char, unsigned long, unsigned
int, unsigned short, unsigned char, float,
double, long double, and bool.
80
Ver 1.4
40
Table of SystemC Datatypes
81
Ver 1.4
Hint: One very interesting option for simulation speed is using profiling tools
like quantify, which tells you the time spent in each function call and how
often functions are executed
82
Ver 1.4
41
sc_int<>, sc_uint<>
Unsigned integer
sc_int<length>, sc_uint<length>
Used for performing arithmetic on signed and unsigned integers of
less than or equal to 64 bits (on a 32-bit machine)
Not optimal for bit vector manipulation.
A two's-complement representation is used for signed integers.
An array of bits
Can address an individual bit
Interpreted as an integer for arithmetic operations
Simulate faster than the arbitrary precision data types
NOTE: C++ language defines the int type to be 32 bits wide. SystemC
provides both fixed precision and arbitrary precision types when you need
integers of a different bit width than 32.
83
Ver 1.4
sc_bigint<>, sc_biguint<>
Unsigned integer
sc_bigint<length>, sc_biguint<length>
Used when more than 64 bits of precision are required
Not optimal for bit vector manipulation
A two's-complement representation is used for signed integers
An array of bits
Can address an individual bit
Interpreted as an integer for arithmetic operations
84
Ver 1.4
42
sc_int, sc_uint, sc_bigint, sc_biguint Syntax
Syntax:
sc_int<length> variable_name ;
sc_uint<length> variable_name ;
sc_bigint<length> variable_name ;
sc_biguint<length> variable_name ;
length:
Specifies the number of elements in the array
Must be greater than 0
Must be compile time constant
Use [] to bit select and range() to part select.
Rightmost is LSB(0), Leftmost is MSB (n-1)
85
Ver 1.4
sc_logic
sc_logic
Interpreted as a single-bit variable representing multiple-valued
logic
Values:
0 logical zero or false (equivalent to bool false)
1 logical one or true (equivalent to bool true)
Z high impedance
X unknown
Use only when necessary to model tri-state buses and their
drivers.
Remember: Simulation & Synthesis interpret “X” differently;
Simulation - unknown, Synthesis - don’t care
Try to limit assignments of X to internal variables, not the output
nodes of your module.
86
Ver 1.4
43
sc_bit
sc_bit
Interpreted as a single-bit variable representing two-valued logic
Values:
0 logical zero or false (equivalent to bool false)
1 logical one or true (equivalent to bool true)
Syntax:
sc_bit variable_name, variable_name, … ;
Example:
sc_bit a, b; // declares variables ‘a’ and ‘b’ as type sc_bit
87
Ver 1.4
sc_logic Syntax
Syntax:
sc_logic variable_name, variable_name, … ;
Example:
sc_logic a, b; // declares variables ‘a’ and ‘b’ as type sc_logic
88
Ver 1.4
44
Summary
89
Ver 1.4
DAY
1
Unit Topic Lab
2 SystemCTM - Introduction
90
Ver 1.4
45
Introduction to Signals
Processes communicate with each other through signals or
channels
91
Ver 1.4
Reading Signals
46
Reading Signal Using read()
Example:
i = count.read(); //Read signal ’count’ and store
// value in variable ’i’
Examples:
i = count; // Equivalent to i = count.read()
if (count < 7) {…} // Equivalent to if (count.read() < 7) {…}
93
Ver 1.4
Writing Signal - 1
A write to a signal overwrites the value.
47
Writing Signal - 2
95
Ver 1.4
Syntax:
sc_signal<type> signal_name ;
type:
Built in C++ types
sc_logic There is a space in between
96
Ver 1.4
48
Other Signal types
97
Ver 1.4
Summary
98
Ver 1.4
49
Lab 2: Simple Arithmetic Pipeline Design - 1
Primary Objective:
Understanding how to write interface file
This lab introduces the process communication using
SystemCTM signals. You will simulate a simple 3 stage
pipelined arithmetic operation. You need to provide the
correct signal type (by modifying Stage1-3.h file) for
inter-pipestage /process communication.
Numgen.h and display.h contains the stimulus and control process declaration
Numgen.cc and display.cc contains the stimulus and control functionality
main.cpp contains the main entry point and instantiates all processes
main.cc
99
Ver 1.4
Powr
Tips : Make sure you have sc_signal for your signals in your
interface file.
! 100
Ver 1.4
50
Lab 2: Sample Output
Sample output:
101
Ver 1.4
DAY
1
Unit Topic Lab
102
Ver 1.4
51
Ports
Ports of a module are external interface that pass information to
and from a module, and trigger actions within the modules
Signals
A signal sc_signal<type> connects the port of a module to the
port of another module
The signal transfer data from one port to another as if the ports
were connected directly
When a port is written, the new value will be written to the signal
when the process performing the write operation has finished
execution or has been suspended.
Preventing some processes seeing the old value while other processes sees
the new value during execution.
All processes executing during a timestamp will see the old value of the
signal
These signal semantics are the same as VHDL signal operation and Verilog
deferred assignment behavior.
104
Ver 1.4
52
Ports and Signals
105
Ver 1.4
Example:
106
Ver 1.4
53
Clocks - A special port and signal
Time is determined by transitions of special signals called
clocks
No smaller granularity of time than a clock cycle
Master Clock
Out-of-Phase
Clock
Clock Syntax
A clock is a C++ class - sc_clock
Example:
sc_clock variable_name (name, period, duty_cycle, start_time, positive_first ) ;
name: clock name type: char * default value: none
period: clock periodtype: double default value: 1
duty_cycle: clock duty cycle type: double default value: 0.5
start_time: time of first edge type: doubledefault value: 0
positive_first: first edge positive type: bool default value: true
10 edge
ime sitive
g e at t t edge po
t ed Firs
Firs
clk2
0 10 20 30 40 50 60
period
108
Ver 1.4
54
Clocks in general
A clock is a general ordering mechanism. It does not have to
be associated with the real system clock.
At a high level of abstraction, a clock cycle can be thought of as
a step of computation and a way of ordering communication
0 10 20 30 40 50
Hint: Good practice is to have the variable_name and the clock
name the same . Only one clock per process.
109
Ver 1.4
Each clock has two edges - each edge of a clock is also a C++
class
sc_clock_edge
Clock edges are used to trigger synchronous processes
Clock edges are used only by synchronous processes
Clock edges are not explicitly defined, but are derived from a
clock using the pos() and neg() methods
Example:
given: sc_clock clk(“clk”, 10, 0.5);
110
Ver 1.4
55
Clocks - Other Information
Example:
given signal clk2 was defined as follows:
sc_clock clk2(“clk2”, 20.0, 0.5, 10, 1);
111
Ver 1.4
+1
Count
Combin. TMS
Enable
circuit Clock
Reset
112
Ver 1.4
56
Power : Growing ASIC/IC Driver
Battery life
Power-Driven
Portables
Cellular
Pagers Packaging Cost
Medical
Consumer
Reliability Peripheral
Cooling Costs Hi-Volume
Military
Telecom
Area-Driven (cost)
Green PC
Workstations Packaging Costs
PCs
Performance-Driven
113
Ver 1.4
Costs
Impact on clock tree synthesis and balancing
Impact on testability
If small bus widths, possible increase in gate count
114
Ver 1.4
57
Clock Gating
Enable F
F
S Enable
Clock
S Clock
M Latch
M
115
Ver 1.4
58
Summary
117
Ver 1.4
DAY
1
Unit Topic Lab
118
Ver 1.4
59
Functionality Description - 1
Functionality is described in processes.
Some processes execute when called and return control to the calling
function (behave like a function).
Some processes are called once, and then can suspend themselves and
resume execution later (behave like threads).
119
Ver 1.4
Functionality Description - 2
120
Ver 1.4
60
So What process SystemCTM supported?
SystemCTM supports three different process types:
Asynchronous Function Asynchronous Thread Synchronous Thread
Process Process Process
121
Ver 1.4
SystemCTM Processes
♦sc_sync_tprocess(SC_CTHREAD)
♦execution is suspended on wait() until next active clock edge
♦process contains internal “FSM”
♦synthesis has to find the correct FSM based on the code
♦within one process can be only registers sensitive to one clock edge
♦sc_async_fprocess(SC_METHOD)
♦process executes everything and wakes up at next event
♦no automatic FSM generation necessary
♦synchronous logic is sensitive to clock edge
♦sc_async_tprocess(SC_THREAD)
♦execution is suspended on wait() until next event
122
Ver 1.4
61
Asynchronous Processes : Function and Thread
Type 1: Asynchronous Function Processes
Asynchronous Processes
Type 2: Asynchronous Thread Process
123
Ver 1.4
void example::entry() {
2 int InternalState = 0;
if (reset) {
…
1 } else {
…
Clock }
data1
A 3
C D //Implementation File
data2
//sensitive to data1 data2
4 #include “systemc.h”
#include “interface.h”
void example::entry() {
5 int InternalState = 0;
if (reset) {
…
} else {
…
}
124
Ver 1.4
62
Asynchronous Function Process Characteristics - 1
125
Ver 1.4
126
Ver 1.4
63
Example: Simple Instruction Set Simulator
fetch.cpp Exec decode.cpp
fetch.h Exec-decode.h
Illustrates event (instruction) driven ISS
127
Ver 1.4
fetch.h Exec-decode.h
main.cpp
128
Ver 1.4
64
Example : ISS - Interface File Declaration Rules
Asynchronous Function Process must be declared as a
structure that publicly derives from SystemC library class.
struct fetch : public sc_async_fprocess
An Asynchronous Function Process consists of the following
member variables and functions:
Input ports
Declared as variables
const-qualified reference to a signal
Output ports (same for INOUT ports)
Declared as variables
Reference to a signal fetch.cpp Exec decode.cpp
Member variables
fetch.h Exec-decode.h
Internal to process
e.g. state_variable ;
Generic constants
main.cpp
const-qualified variables
e.g. const int bit_width;
129
Ver 1.4
130
Ver 1.4
65
Example: ISS - Interface File fetch.h (Ver 0.91)
struct fetch : public sc_module { // INSTRUCTION FETCH UNIT
sc_in<unsigned> program_counter;
sc_out<unsigned> instruction;
unsigned *prog_mem; // The program memory
sensitive(program_counter);
FILE *fp = fopen("progmem", "r"); // Initialize the program memory from file progmem
if (fp == (FILE *) 0) return; // No prog mem file to read
// First field in this file is the size of program memory desired
int size;
fscanf(fp, "%d", &size);
prog_mem = new unsigned[size];
if (prog_mem == (unsigned *) 0) { printf("Not enough memory left\n"); return; }
unsigned mem_word;
size = 0;
while (fscanf(fp, "%x", &mem_word) != EOF) {
prog_mem[size++] = mem_word;
}
end_module();
}
// Functionality
void entry();
};
131
Ver 1.4
Name of thechar
fetch(const block
* NAME) Public inheritance
: sc_module (NAME) {
sc_async_fprocess(handle1,”FETCH”,fetch,entry);
(keyword public
can be left out)
sensitive(program_counter);
FILE *fp = fopen("progmem", "r"); // Initialize the program memory from file progmem
if (fp == (FILE *) 0) return; // No prog mem file to read
// First field in this file is the size of program memory desired
int size;
fscanf(fp, "%d", &size);
prog_mem = new unsigned[size];
if (prog_mem == (unsigned *) 0) { printf("Not enough memory left\n"); return; }
unsigned mem_word;
size = 0;
while (fscanf(fp, "%x", &mem_word) != EOF) {
prog_mem[size++] = mem_word;
}
132
Ver 1.4
66
Example: ISS - Input/Output Port Declaration
Name of port
(A port is a
struct fetch : public sc_module { // INSTRUCTION FETCH UNIT
sc_in<unsigned> program_counter; data member
sc_out<unsigned> instruction; of the class)
unsigned *prog_mem; // The program memory
sensitive(program_counter);
FILE *fp = fopen("progmem", "r"); // Initialize the program memory from file progmem
if (fp == (FILE *) 0) return; // No prog mem file to read
sc_out<T> is defined as output port in SystemCTM
// First field in this file is the size of program memory desired
int size;
fscanf(fp, "%d", &size);
prog_mem = new unsigned[size];
if (prog_mem == (unsigned *) 0) { printf("Not enough memory left\n"); return; }
unsigned mem_word;
size = 0;
while (fscanf(fp, "%x", &mem_word) != EOF) {
prog_mem[size++] = mem_word;
}
end_module();
}
// Functionality
void entry();
};
133
Ver 1.4
sensitive(program_counter);
Initialize the FILE *fp = fopen("progmem", "r"); // Initialize the program memory from file progmem
if (fp == (FILE *) 0) return; // No prog mem file to read
Name of Thread Process (functionality)
module // First
int size;
field in this file is the size of program memory desired
134
Ver 1.4
67
C++ Constructor
What is a C++ constructor?
It is a function defined in the class that is used to initialize a
class.
This function is called whenever a variable of that class is
instantiated.
The function has the same name as that of the class.
A constructor can take several arguments, but is not allowed to
have a return type.
#include "systemc.h"
#include ”fetch.h”
void fetch::entry()
{
unsigned pc, instr;
pc = program_counter.read();
instr = prog_mem[pc];
instruction.write(instr);
}
136
Ver 1.4
68
Example: ISS EXEC_DECODE Interface file - 1
struct exec_decode : public sc_async { //
const sc_signal<unsigned>& instruction;
sc_signal<unsigned>& program_counter;
SystemCTM Version 0.9
137
Ver 1.4
69
Example: ISS EXEC_DECODE Implementation file
void exec_decode::entry() { case 0x2: // Load
unsigned instr; REMEMBER: native
regnum1 = (instrC++ datatypes
& 0x1f000000) run
>> 24; faster!reg
// Extract
unsigned opcode; addr = (instr & 0x00ffffff); // Extract address
unsigned regnum1, regnum2, regnum3; printf("Load: R[%d] = Memory[0x%x]\n", regnum1, addr);
unsigned addr; cpu_reg[regnum1] = data_mem[addr];
pc = pc + 1;
int i; program_counter.write(pc);
instr = instruction.read(); break;
opcode = (instr & 0xe0000000) >> 29; // Extract case 0x3: // Add
//opcode regnum1 = (instr & 0x1f000000) >> 24; // Extract
switch(opcode) { //register number
case 0x0: // Halt regnum2 = (instr & 0x00f80000) >> 19; // Extract
printf("CPU Halted\n"); //register number
printf("\tPC = 0x%x\n", pc); regnum3 = (instr & 0x0007c000) >> 14; // Extract
for (i = 0; i < 32; i++) //register number
printf("\tR[%d] = %x\n", i, cpu_reg[i]); cpu_reg[regnum3] = cpu_reg[regnum1] + cpu_reg[regnum2];
// Don't write pc and execution will stop pc = pc + 1;
break; program_counter.write(pc);
case 0x1: // Store
regnum1 = (instr & 0x1f000000) >> 24; // Extract break;
// register number case 0x7: // JNZ
addr = (instr & 0x00ffffff); // Extract address regnum1 = (instr & 0x1f000000) >> 24; // Extract
printf("Store: Memory[0x%x] = R[%d]\n", addr, addr = (instr & 0x00ffffff); // Extract address
regnum1); printf("JNZ R[%d] 0x%x\n", regnum1, addr);
data_mem[addr] = cpu_reg[regnum1]; if (cpu_reg[regnum1] == 0x0) pc = pc + 1;
pc = pc + 1; else pc = addr;
program_counter.write(pc); program_counter.write(pc);
break; break;
default: // Bad opcode
pc = pc + 1;
program_counter.write(pc);
break;
}
139
Ver 1.4
140
Ver 1.4
70
Summary
141
Ver 1.4
sc_uint<8>
a_wen
opcode
rd_wen
reset mem_control
wd_wen
inca
state
nextstate
state_t
state_t
142
Ver 1.4
71
Lab 3: Simple Memory Controller - 2
For your reference, here is the top level design of the memory
controller including the testbench and SRAM memory
8 8
into data data
addr 8
TestBench addr
8 sm_seq
outof rd rd SRAM
wr wr
reset
nextstate
wd_wen
opcode
rd_wen
state
a_wen
inca
reset
mem_control
143
Ver 1.4
RDBLK WTBLK
READ_WORD a_wen WRITE_WORD a_wen
READ_BLOCK2
rd_wen WRITE_BLOCK2 wd_wen
inca
wd_wen
READ_BLOCK5 rd_wen WRITE_BLOCK5 inca
144
Ver 1.4
72
Lab 3: States, Commands (opcodes), and Outputs
#ifndef _FSM_TYPES_
#define _FSM_TYPES_
enum state_t{ // states
IDLE,
READ_WORD,
READ_WORD2, Control outputs:
READ_BLOCK, a_wen assert: high(true) address write enable
READ_BLOCK2, rd_wen assert: high(true) read data write enable
READ_BLOCK3,
wd_wen assert: high(true) write data write enable
READ_BLOCK4,
READ_BLOCK5, inca assert: high(true) increment address
WRITE_WORD,
WRITE_WORD2,
WRITE_BLOCK,
WRITE_BLOCK2,
WRITE_BLOCK3,
WRITE_BLOCK4,
WRITE_BLOCK5 Interface signal:
}; a_wen address write enable
rd_wen memory read enable
enum command_t { //opcodes wd_wen memory write enable
NOP,
inca increment address
RDWD,
RDBLK,
WTWD,
WTBLK
};
#endif
145
Ver 1.4
Lab 3 : sm_seq
into address addr
+
data
outof rdata
wr
rd
reset
nextstate
wd_wen
rd_wen
state
a_wen
inreg
inca
146
Ver 1.4
73
Lab 3: Sample Instruction Flow
For your reference, here is the instruction flow.
in_reg
wt_blk rd_wd wt_wd
op op op 31
code code code
Data Data Data Data Addr Get Addr Data Addr
data
0
addr+3
addr+1
addr+2
Time
addr
147
Ver 1.4
148
Ver 1.4
74
Agenda: Day One
DAY
1
Unit Topic Lab
149
Ver 1.4
150
Ver 1.4
75
Asynchronous Thread Process - Basic Idea
Asynchronous Thread Process: Once the process is invoked,
instructions are executed infinitely fast and in order UNTIL wait()
statement is reached
Behaves like a thread.
//Implementation File
//sensitive to data1 data2
#include “systemc.h”
#include “interface.h”
Local variable NOT REDEFINED
void example::entry() {
int InternalState = 0;
data2
C D 1 …
//do something here
printf(“here is what you do in
this invocation !”);
wait();
2
//do something else
printf(“here is what you do in
another invocation !”);
wait();
151
Ver 1.4
combinational combinational
logic logic
clock
152
Ver 1.4
76
Timing Control Statements
Timing control statements are used to implement
synchronization and writing of signals in processes.
wait()
suspends execution of the process until the process is
invoked again.
wait_until() (more later)
Suspends execution of the process until an
expression becomes true.
153
Ver 1.4
wait() Function
wait() may be used in both asynchronous and synchronous
thread processes but NOT in an asynchronous function
process (block).
Examples:
wait() ; // waits 1 cycle in synchronous process
wait(4); // waits 4 cycles in synchronous process
wait(4) ; //ERROR!! in Asynchronous process
154
Ver 1.4
77
SystemCTM (Ver 0.9 ONLY) Constructor Conventions
155
Ver 1.4
78
Asynchronous Thread Process Characteristics - 2
157
Ver 1.4
Display
158
Ver 1.4
79
Example : Asynchronous Thread Process - 2
Advantages of Using SystemC
If the design goals suddenly change, SystemC
allows designer to start the design at a high level and
refine the design down to hardware implementation
level without the disconnect that occurs between the C
model and the VHDL/Verilog models.
Timer
Display
159
Ver 1.4
160
Ver 1.4
80
Example : Asyn Thread Process - Transmit
#include "transmit.h" #include "systemc.h"
int transmit::get_data_fromApp() { #include "packet.h"
int result;
result = rand(); struct transmit : sc_module {
cout <<"Generate:Sending Data Value = "<<result << "\n"; sc_in<packet_type> tpackin;
return result; sc_in<bool> timeout;
} sc_in<bool> clock;
sc_out<packet_type> tpackout;
void transmit::send_data() { sc_out<bool> start_timer;
while (true) {
if (tpackin.event()) { int buffer;
packin = tpackin; int framenum;
if (packin.seq == framenum) { packet_type packin;
buffer = get_data_fromApp(); packet_type s;
framenum++; int retry;
retry = 0; bool start;
}
} void send_data();
int get_data_fromApp();
if (clock == true) {
s.info = buffer; transmit(const char *name) : sc_module(name) {
s.seq = framenum; sc_async_tprocess(handle, "send_data", transmit, send_data);
s.retry = retry; sensitive <<tpackin<<timeout;
retry++; sensitive_pos <<clock;
tpackout = s; framenum = 1;
start = !start; retry = 0;
start_timer = start; start = false;
cout <<"Transmit:Sending packet no. "<<s.seq << "\n"; buffer = get_data_fromApp();
} end_module();
wait(); }
}
};
}
161
Ver 1.4
162
Ver 1.4
81
Example : Asyn Thread Process - Receiver
#include "receiver.h" #include "systemc.h"
void receiver::receive_data(){ #include "packet.h"
while (true) {
packin = rpackin; struct receiver : sc_module {
cout <<"Receiver: got packet no. = sc_in<packet_type> rpackin;
"<<packin.seq << "\n"; sc_out<packet_type> rpackout;
if (packin.seq == framenum) { sc_out<long> dout;
dout = packin.info;
framenum++; int framenum;
} packet_type packin;
s.seq = framenum -1; packet_type s;
rpackout = s;
wait(); void receive_data();
}
} receiver(const char *name) : sc_module(name)
{
sc_async_tprocess(handle, "receive_data",
receiver, receive_data);
sensitive <<rpackin;
framenum = 1;
end_module();
}
};
163
Ver 1.4
extern
void sc_trace(sc_trace_file *tf, const packet_type& v,
const sc_string& NAME);
164
Ver 1.4
82
Asynchronous Evaluate-Update Cycle
Evaluationphase:
Allasynchronous objects with events at their inputs are executed
Output are not updated
Update phase:
Once all asynchronous objects are executed,
signals with new values are updated
Execution order does not effect final signal values or process state.
165
Ver 1.4
166
Ver 1.4
83
Special Signal Methods - posedge() & negedge()
The posedge() and negedge()method are:
Only used with Asynchronous blocks and processes.
Supported signals of type boolean.
For posedge()
Returns true only if there is an event on a signal and the
transition on the signal is from 0-to-1. False if not.
For negedge()
Returns true only if there is an event on a signal and the
transition on the signal is from 1-to-0. False if not.
167
Ver 1.4
Summary
168
Ver 1.4
84
Summary for Day One
Day One
covered the motivation behind SystemC for SoC
design
briefly discussed about C++ languages
introduced SystemCTM datatypes for modeling
introduced signals for communication between
processes
introduced the concept of time
introduced Asynchronous Function Process
(sc_async_fprocess)
introduced Asynchronous Thread Processes
(sc_async_tprocess)
169
Ver 1.4
Backbone
X
Dedicated Segment Switch
...
LAN
170
Ver 1.4
85
Lab 4: 4x4 MULTICAST HELIX PACKET SWITCH - 2
The switch allows for higher bandwidth. Terminals are hooked up to
hubs which are hooked up to the switch, which is connected to the
backbone. Hubs are cheap, but they don’t filter data.
The switch addresses collisions and contentions when communicating
between two local terminals. A 4-port switch can handle 4 simultaneous
conversations.
The switch has a buffering scheme so it can handle burst data. As soon
as a port is free, it un-queues data out of buffer and sends it to the
network.
switching
Ports
171
Ver 1.4
Main.cc
sender0 sender2
receiver0 receiver2
Switch
sender3
sender1
receiver3
receiver1
172
Ver 1.4
86
Lab 4: 4x4 MULTICAST HELIX PACKET SWITCH - 4
Here is the interface of switch block
RO R2
Shift reg
ring
R1 R3
173
Ver 1.4
The switch uses a self routing ring of shift registers to transfer cells
from one port to another in a pipelined fashion, resolving output
contention and efficiently handling multicast cells. Input and output
ports have FIFO buffers of depth four each.
174
Ver 1.4
87
Lab 4: 4x4 MULTICAST HELIX PACKET SWITCH - 6
175
Ver 1.4
176
Ver 1.4
88
Lab 4: Switch Question?
Similarly:
using aggregate data types, you can model ATM traffic policing block
µp Interface
VC Map Policing
UPC
Parameters GCRA
Table
177
Ver 1.4
RAM Verdict
VC Number parameters
addr data
to Cell
from VC Map out
Header
Processing
UPC
Policing Verdict
Parameters
Algorithm Logic
Table
data
in GCRA
updated parameters
178
Ver 1.4
89
Lab 4: Switch Question?
ATM Cell
HEC
CLP
CLP
VCI
VCI
VPI
VPI
PTI
PTI
payload
from Input
VPI-VCI
to VC Map
Extract
ATM
VPI & VCI Cell
Discarded Cell
Trash
179
Ver 1.4
DAY
2
Unit Topic Lab
180
Ver 1.4
90
Synchronous Thread Processes Characteristics - 1
Synchronous process sc_sync_tprocess:
Sensitive only to one edge of one and only one clock
Cannot use multiple clocks with a synchronous process
This edge is called the active edge
At the active edge, the process is invoked only after all the
asynchronous blocks and processes have executed
This models behavior at the inputs of unregistered inputs
Inputs sampled here
Outputs produced here
sc_sync_tprocess
Clock
Active edge
181
Ver 1.4
Local variables defined in entry() function are saved each time the
process is suspended.
State of process is implicitly saved.
182
Ver 1.4
91
Synchronous Thread Processes Characteristics - 3
Synchronous process:
On write of output signal the
Value is not immediately visible
Value is available at next active edge (like registered outputs)
a2
a1 a3
sc_sync sc_async
183
Ver 1.4
What is wait_until() ?
Wait_until(argument) is an expression involving:
Signals of type sc_signal<bool>
== and != operators
Boolean connectives && and ||
Examples:
wait_until(aa.delayed() == 1 && bb.delayed() == 0);
// suspends execution until both aa is 1 and bb is 0
184
Ver 1.4
92
Edge Detection
at_posedge(), at_negedge()
SystemCTM functions to implement behavior of waiting for
a positive edge or negative edge.
Single argument of type sc_signal<bool>
Suspends execution of process until next active edge
where the signal makes the appropriate transition.
185
Ver 1.4
Delay-evaluated Expressions
wait_until() and watching() (defined later):
take an expression as an argument
Evaluate expression at next active edges of the process.
Expression not evaluated immediately.
Called a delay-evaluated expression
Argument must be a delay-evaluated expression.
Equivalent
b_tmp = b.read();
wait_until(a == b.read()); wait_until(a == b_tmp);
Use
do {
wait_until(data_ready.delayed()==1); wait();
} while (data_ready.read() != 1);
186
Ver 1.4
93
Synchronous Thread Process : I/O Timing
clock
in1 1 35
in2 13 18
out 14 53
187
Ver 1.4
sc_sync sc_sync
Process 1 Process 2
clock
A1 AAAA BBBB CCCC
A2 AAAA BBBB CCCC
A2 sampled by Process2 AAAA BBBB CCCC
A3 AAAA BBBB
188
Ver 1.4
94
Yes, We can modeling Half-Clock cycle Behavior
Case 2: Process 1 : synchronous process
Process 2 : asynchronous block
sc_sync sc_async
A1 while (true) { A2 A3
A2 = A1; A3 = A2;
wait( );
}
Process 1 Process 2
clock
A1 AAAA BBBB CCCC
A2 AAAA BBBB CCCC
A2 sampled by Process2 AAAA BBBB CCCC
A3 AAAA BBBB CCCC
189
Ver 1.4
in1 in2
15
25 critical timing for
clock period
15
* multiplier
95
Example Interface File special_adder.h
Name of the Module Public inheritance
(keyword public
struct special_adder : public sc_module {
can be left out)
// Input ports
sc_in_clk CLK;
Name of port
sc_in<int> in1;
sc_in<int> in2; (A port is a
data member
// Output ports of the class)
sc_out<int> out;
+ sum
in1
Timing control statement special_adderout
in2
192
Ver 1.4
96
Special_adder functionality
void special_adder :: entry( )
{
while (true) {
out = in1 + in2;
wait( );
out = in1 + in2 + 2;
wait( );
}
}
Clock
in1 5 2 65
in2 4 3 18
out unknown 9 7 83
in1
special_adderout
in2
193
Ver 1.4
Illustrates:
Internal variables main.cpp
handshake
Process Process found Process
Stimgen Recognizer Counter
stream
194
Ver 1.4
97
fsmr.h Interface File
/* Filename fsmr.h Interface file for FSM Recognizer Process */
struct fsm_recognizer : public sc_module {
// Input ports
sc_in_clk CLK;
sc_signal<char> input_char; stimgen.cpp fsmr.cpp pcntr.cpp
sc_in<bool> data_ready;
stimgen.h fsmr.h pcntr.h
// Output ports
sc_out<bool> found;
// The constructor
fsm_recognizer(const char* NAME)
: sc_module(NAME) {
sc_sync_tprocess(….. ..CLK.pos());
pattern[0] = ’W’;
pattern[1] = ’A’; Internal variables
pattern[2] = ’N’;
Initialization of internal variables
pattern[3] = ’G’;
end_module();
}
// The functionality of the process
void entry();
};
handshake
Process Process found Process
Stimgen Recognizer Counter
stream
195
Ver 1.4
void fsm_recognizer::entry()
{
handshake
char c; Process Process found Process
int state = 0;
bool out;
Stimgen Recognizer Counter
stream
while (true) {
wait_until(data_ready.delayed() == true);
c = input_char.read();
printf("%c", c); // for debugging
switch (state) {
case 0:
if (c == pattern[0]) state = 1;
else state = 0;
out = false; S1
S0 Finite State
break;
case 1:
S2 machine
if (c == pattern[1]) state = 2;
else if (c != pattern[0]) state = 0;
out = false;
break; …...
196
Ver 1.4
98
Example: Positive-edge trigger DFF
/* Positive-edge triggered DFF */
#include "systemc.h"
// process definition
struct dff_pos : public sc_module {
sc_in_clk CLK; sc_sync
sc_in<bool> in_data;
sc_out<bool> out_q;
Clock
dff_pos (const char *NAME)
: sc_module (NAME) {
sc_sync_tprocess(handle1, “DP”, diff_pos, entry, CLK.pos());
end_module();
}
void entry();
// process entry
};
void dff_pos::entry()
{
while (true) {
out_q = in_data;
wait();
}
}
197
Ver 1.4
Example: D Latch
#include "systemc.h"
void entry();
};
void d_latch::entry()
{
if (clock)
out_q = in_data;
}
198
Ver 1.4
99
Observation: One Size Does Not Fit All
SW
Speed
Behav
Mixed
Gate
RTL Detail
Flexibility &
Interactivity
199
Ver 1.4
Asynchronous function processes are useful for modeling at the RTL level
they are used for faster simulation as they are not thread-based
200
Ver 1.4
100
Summary
201
Ver 1.4
202
Ver 1.4
101
Lab 5: Multiple-Cycle RAM
2. Understand how many wait() statements are needed for programmable
latency.
203
Ver 1.4
int
datain dataout
chip_select cs
Main.cc
204
Ver 1.4
102
Lab 5: Multiple-Cycle SRAM Question?
Question. Do you know how to model this?
CLK
DATAO
Row a
Row a
Row a+1
Row a+2
205
Ver 1.4
206
Ver 1.4
103
Lab 5: Digital Designers' Perspective of Chip Select
207
Ver 1.4
208
Ver 1.4
104
Agenda: Day Two
DAY
2
Unit Topic Lab
209
Ver 1.4
out input
Synchronous Asynchronous
Process A object
in result
210
Ver 1.4
105
Process Execution Order - 2
For every transition of the clock signal:
3. As a result of step 2, asynchronous objects may have new values on
their inputs.
If so then the actions of step 1 are repeated.
One of the signals with new values may be a clock signal.
Step 2 is repeated.
Steps 2 and 3 are repeated until no more signals change value.
4. All synchronous thread processes that have this edge as the active
edge:
Execute until their next timing control statement suspends execution.
Includes execution of wait_until()and watching().
There is no fixed order of execution for synchronous processes.
out input
Synchronous Asynchronous
Process A object
in result
211
Ver 1.4
out input
Synchronous Asynchronous
Process A object
in result
212
Ver 1.4
106
Time & Event Queues
Event Queues time
t
t+1
t+2
t+3
213
Ver 1.4
• example:
a= b;
no wait(); statement in Asynchronous/Synchronous thread process
t+1
214
Ver 1.4
107
"Deadlocks"
215
Ver 1.4
Body:
... out input Body:
out.write(100); i = input.read();
wait(); Synchronous Asynchronous j = i + 20;
res = in.read(); Process A Function Pro. B result.write(j);
... in result
Ans: 120
216
Ver 1.4
108
Summary
217
Ver 1.4
218
Ver 1.4
109
Top Level Routine - sc_main
stimgen.cpp adder.cpp monitor.cpp
The argc and argv provided to a main routine for
parameters’ passing in C++ are also provided to sc_main
e.g. simulation period sc_start(n) where n is number of
time units
Top level is called sc_main instead of main because main is
defined in SystemCTM
Initialization of simulation kernel is performed before
sc_main is called.
File name is main.cpp or main.cc (depends on Makefile)
219
Ver 1.4
sc_main Outline
Tips: Make sure you put return(0); at the end of your sc_main!
220
Ver 1.4
110
Automatic Clock Generation
sc_clock clk2(“CLK2”, 20.0, 0.5, 10, 1); clock
period = 20 time units
sc_start(argument) function
Argument is a variable or a constant of type double
Specifies the number of time units to simulate
-1: simulation continues infinitely
sc_stop() function
No arguments
Stops simulation
Causes sc_start() to return control to sc_main routine
sc_time_stamp() function
No argument
Returns the current simulation time as a double precision floating point
value.
For synchronous processes - time of last active edge.
Example sc_main
#include “adder.h”
#include “stimgen.h” stimgen.cpp adder.cpp monitor.cpp
#include “monitor.h”
stimgen.h adder.h monitor.h
int sc_main(int argc, char *argv[ ]){
// Create signals
sc_signal<int> s1;
sc_signal<int> s2; main.cpp
sc_signal<int> s3;
// Create clock
sc_clock clock(“clock”, 10, 0.5);
Mapping 1: by order
// Instantiate Processes using “<<“ symbol
adder ADD(“ADD_BLOCK”);
ADD << clock << s1 << s2 << s3; Mapping 2: by position
stimgen STIM(“STIM_BLOCK”);
STIM (clock, s1, s2);
monitor MON(“MON_BLOCK”); Mapping 3: explicit
MON.clk(clock); mapping one by one
MON.input(s3); (order independent)
// Simulate
sc_start(200);
return (0);
222
Ver 1.4 }
111
Example sc_main - includes & arguments
Include interface files for all
#include “adder.h” processes to be instantiated
#include “stimgen.h”
#include “monitor.h”
int sc_main(int argc, char *argv[ ]){ ac and av are the same arguments
// Create signals
sc_signal<int> s1; that are passed to main() in C/C++
sc_signal<int> s2;
sc_signal<int> s3;
// Create clock
sc_clock clock(“clock”, 10, 0.5);
// Instantiate Processes
adder ADD(“ADD_BLOCK”);
ADD << clock << s1 << s2 << s3;
stimgen STIM(“STIM_BLOCK”);
STIM (clock, s1, s2);
monitor MON(“MON_BLOCK”);
OR programmable simulation duration
MON.clk(clock); if (argc==2) n = atoi(argv[1]);
MON.input(s3); sc_start(n);
// Simulate
sc_start(200);
return (0);
}
223
Ver 1.4
// Simulate
sc_start(200);
return (0);
}
224
Ver 1.4
112
Example sc_main - Clocks
#include “adder.h”
#include “stimgen.h”
#include “monitor.h”
int sc_main(int argc, char *argv[ ]){
// Create signals Creation of clocks
sc_signal<int> s1;
sc_signal<int> s2;
sc_signal<int> s3; Clock of period 10 time
// Create clock
sc_clock clock(“clock”, 10, 0.5); units and 50% duty
// Instantiate Processes cycle
adder ADD(“ADD_BLOCK”);
ADD << clock << s1 << s2 << s3;
stimgen STIM(“STIM_BLOCK”);
STIM (clock, s1, s2);
monitor MON(“MON_BLOCK”);
MON.clk(clock);
MON.input(s3);
225
Ver 1.4
113
Process Instantiation
227
Ver 1.4
Function sc_start ()
Automatic clock generator
Takes a double as an argument
Specifies the number of time units to run
-1 for argument - simulation runs forever.
Simulation is
started by
calling this
// Simulate Duration of the
function sc_start(200);
provided in return (0);
simulation
SystemCTM }
Note that code following this is
not executed until after function returns
228
Ver 1.4
114
Compiling and Running the Program
After the implementation and header files are written:
Implementation files are compiled individually
Linked together with SystemCTM
Compilation requires header files from SystemCTM
Current Compilers
Gnu g++ version 2.95.2 or later (Free!)
http://www.gnu.org/software/gcc/gcc.html
Borland C++ 4.0 or later
Microsoft Visual C++ 6.0 or later
Current Platforms
Sun Solaris
Windows NT 4.0
Linux
Program Profiling
Use Quantify to profile your simulation.
230
Ver 1.4
115
System Profiling
Statement
Execution
Write to RAM Checksum
// bus_controller.h header file Order
Wait Interrupt Re-Initialize RAM Get
For Make Decision Read Accumulate Test Result Transfer Data
Next // signal declaration
Input Input
Set Flag struct bus_controller : public sc_module{
Process Data Output Result Update Status sc_in<sc_biguint<256> > databus;
…}
256 bits databus ...
// bus_controller.cc Implementation file..
// reset behavior
if(reset.read()==true) {
state = reset_s;
}
S1
S0 Finite State
Profile BUS utilization ...
12%
while (true) {
S2 machine
7% Memory read
reset_loop : loop
43% Block transfer
8
%
interrupt opcode = instruction.read();
Idle
switch (state) {
Memory write
30%
case reset_s : …..; break;
case WRITE: ……; break;
case READ: …….; break.;
cout << SOME PROFILE
STATISTICS
...
}
231
Ver 1.4
Project Management
use SNIFF+ for project management
232
Ver 1.4
116
Common Makefile Definitions
Location
# --------------- Common macro definitions of SystemC library
----------------------
# C++ Compiler
CC = g++
SYSTEMC = ../../..
INCDIR = -I. -I.. -I$(SYSTEMC)/include
LIBDIR = -L. -L.. -L$(SYSTEMC)/lib-$(TARGET_ARCH)
CFLAGS = -Wall -pedantic $(D_OPT) $(INCDIR) $(LIBDIR) -fexceptions
LIBS = -lsystemc$(D_OPT) -lnumeric_bit$(D_OPT) -lstdc++ \
-lqt -lm $(EXTRA_LIBS)
include Makefile.deps
234
Ver 1.4
117
Local makefile for a project
# MODULE is the prefix of the executable file. The actual
# executable file will have a ".x" appended to it
MODULE = run
# Set this D_OPT flag to -g for debug and -O for optimized code
D_OPT = -g
235
Ver 1.4
Testbench
DUT
Selected Block
Testbench
236
Ver 1.4
118
Summary
237
Ver 1.4
238
Ver 1.4
119
Lab 6: Simple RISC CPU - 1
Primary Objective:
Basic: Learn how to write a main.cc
to instantiate multiple processes for different modules
Advanced: implement some of the functionality using synchronous
processes.
239
Ver 1.4
BIOS
DECODE EXEC
FETCH
PIC
MMXU
DCACHE
Main.cc
240
Ver 1.4
120
Lab 6: Sample Output
Sample output:
241
Ver 1.4
Level of abstraction
The data types used
The process types used
The process sensitivity list
The quality of the user code
242
Ver 1.4
121
Level of Abstraction
243
Ver 1.4
244
Ver 1.4
122
Speed of Datatypes for Logical Operations
245
Ver 1.4
246
Ver 1.4
123
Choosing the Right Datatype - II
247
Ver 1.4
SystemC Processes
248
Ver 1.4
124
Process switching times
249
Ver 1.4
250
Ver 1.4
125
Use of SC_METHOD and SC_THREAD
EXPLICIT IMPLICIT
int temp; void behavior() {
int state; while (true) {
int cmd; temp = 0;
wait();
void datapath() { temp = temp + in;
if (cmd) wait();
temp = temp + in; temp = temp + in;
} wait();
out = temp;
void fsm() { wait();
switch(state) { }
case 0: temp = 0; cmd = 0; state = 1; }
break;
case 1: state = 2; cmd = 1; break;
case 2: state = 3; cmd = 1; break;
case 3: state = 0; cmd = 0; out = temp;
break;
} 251
Ver 1.4
}
Process Sensitivity
252
Ver 1.4
126
Avoiding False Process Executions
void my_method()
{
if (clock.posedge())
out = a * b - c * d;
}
a
SC_CTOR(my_process) {
b SC_METHOD(my_method);
out sensitive << a;
c
sensitive << b;
d sensitive << c;
sensitive << d;
sensitive_pos << clock;
clock }
253
Ver 1.4
DAY
2
Unit Topic Lab
254
Ver 1.4
127
Channels - Introduction
A channel is a special type of signal processes may use for
communication.
Capabilities different from those of signals ( sc_signal ).
Built in protocol allows modeling of communication without I/O
protocols (handshaking etc.)
Useful at higher levels of abstraction
System
Architectural
Process 3
Process 4
signals
Behavioral
RTL
Process 1 Process 2 Process 5
channel
RTL
Module 1
Gate
Process 1 Process 2
255
Ver 1.4
Channel Characteristics
Process 1 Process 2
256
Ver 1.4
128
Channel Read
Same read semantics as signals until buffers are empty
If data is available:
read completes instantaneously.
If no data is available:
Reader (destination) process blocks for some number of
cycles until data are available.
data_available may be used to determine if data is
available in the buffer. Returns true or false
If channel is specified with zero buffers:
Reader (destination) process blocks until the writer
(source) process writes to the channel.
Process 1 Process 2
257
Ver 1.4
Channel Write
Same write semantics as signals until no buffers available
If buffers are full:
channel blocks (integral number of clock cycles) the writing
(source) process until buffers become available.
If buffers are available:
write takes one clock cycle
A write to a channel incorporates a wait()
space_available may be used to determine if space is
available in the buffer. Returns true or false
If channel is specified with zero buffers:
Writer (source) blocked until reader (destination) performs a
read on the channel.
Process 1 Process 2
258
Ver 1.4
129
Scalar Channels
A channel is a C++ class - sc_channel
Syntax:
sc_channel <type> variable_name ;
sc_channel <type> variable_name (int BufferSize ) ;
sc_channel <type> variable_name (char *Name , int BufferSize ) ;
EXAMPLE:
// c is a channel of type int with a buffer of size 10 (given name is ’I’)
sc_channel<int> c("I", 10);
Process 1 Process 2
259
Ver 1.4
Channel Arrays
A channel array is a C++ class - sc_channel_array
Whole array is read or write.
Syntax:
sc_channel _array <type> variable_name (int ArraySize) ;
sc_channel _array <type> variable_name (int ArraySize int BufferSize ) ;
sc_channel _array <type> variable_name (char *Name , int ArraySize, int
Buffersize ) ;
type: channel type: C++ built in, aggregate types, SystemCTM types
ArraySize: size of the array
BufferSize(optional): number of buffers, refers to number of buffers in each element
of the array default value: 0
Name (optional): channel name
EXAMPLE:
// a is a channel array of type int containing 10 elements (0 buffers)
sc_channel_array<sc_array<int> > a(10);
Process 1 Process 2
260
Ver 1.4
130
Channel read () method
read() method is provided to read the values from
the channel
For scalar channels:
returns a value of the type of the channel
For array channels:
returns an array of the type of the channel
If data is available:
value returned instantaneously
data is removed from the channel
If no data is available:
execution of the reading process blocks until data becomes
available.
execution blocked for an integral number of clock cycles.
If channel is specified with zero buffers:
reader (destination) process blocks until the writer (source)
process writes to the channel
261
Ver 1.4
262
Ver 1.4
131
Channel Read Gotcha - 1
Example
Given: sc_channel<int> chn;
if (chn < 7 || chn > 12)
or
if (chn.read() < 7 || chn.read() > 12)
263
Ver 1.4
Example
Given: sc_channel<int> chn;
264
Ver 1.4
132
Channel Example
Structure model
Library
Channel1 System1
Terminal
TerminalA TerminalB
Channel2
Channel
System2
Application Layer Terminal
Tester Terminal
TerminalA
Tester
265
Ver 1.4
Summary
266
Ver 1.4
133
Lab 7: Image Smoother - 1
Primary Objective:
Understanding how to use channel
Input: a raw picture
Output: a smooth (average pixel values) picture
267
Ver 1.4
Secondary Objective:
View the before and after pictures
Performance analysis:
you can change number for pixels to be average for optimal results
Run lab7.sh ( a C-Shell script in UNIX environment)
268
Ver 1.4
134
Lab 7: Image Smoother - 3
Smoothing Algorithm using:
pix_reader' reads the input image in raster order.
It reads the greyscale value of a pixel and its 3 X 3 pixel neighborhood
and transmits it to the `pix_smoother' process.
The pix_smoother process computes the average greyscale value over
the 3 X 3 pixel nbd. and
sends it to the `pix_writer' process which then writes it to the output
image.
Unsigned char
pix_in
Unsigned char
pix_nbd_cnt pix_smoother pix_out
Unsigned char
pix_nbd
Unsigned char
269
Ver 1.4
270
Ver 1.4
135
Lab 7: Image Smoother Interface -2
pix_smoother Interface :
1. Each pixel greyvalue can be represented in 8 bits (0-255). So the channel type is
unsigned char.
2. `pix_in' is an input channel port that is the greyvalue of the input pixel
3. `pix_nbd' is an input channel port with 9 buffers. We need 9 buffers because we
implement a 3 X 3 pixel neighborhood. pix_nbd stores the greyvalues of the pixels in the 3
X 3 nbd. of `pix_in'.
4. `pix_nbd_cnt' is a count of the number of nbd. pixels. Note that the pixels on the border
have a partial 3 X 3 neighborhoods and we use this count while computing the average of
the nbd. pixels.
5. `pix_out' is a greyvalue of the output pixel i.e. greyvalue computed after averaging the
nbd pixels greyvalues.
Unsigned char
pix_in
Unsigned char
pix_nbd_cnt pix_smoother pix_out
Unsigned char
pix_nbd
Unsigned char
271
Ver 1.4
DAY
2
Unit Topic Lab
272
Ver 1.4
136
Why Partition ?
Why partition a design?
Functionality
Generate regular data-path architectures
Good partitioning strategy results in:
Shorter run times, easier to debug
Less memory requirements
Improved quality of results (QOR)
RISC_CORE
PRGRM_CNT CONTROL
ALU
20 k gates 40 k gates
Glue
DATA_PATH 5k
100 k gates
data_bus
32
How would you partition this design?
30 k gates
273
Ver 1.4
What is a Module?
Module Features:
Module Well-defined I/O ports
Name Specific logic function
DATA_MORPH:
IN[15] OUT[15]
External *
...
...
+
I/O Ports
IN[0] OUT[0]
Internal
Function
Module Complexity:
Typically, a functional block
As big as a multi-chip system
The basic building block
As small as a single gate
in any SystemC/HDL description!
274
Ver 1.4
137
Structure of a Module Description
Source-Code
File
/**************************************/
Comment
/* SystemC Generic Module */
Block
/**************************************/
Struct data_morph: sc_module {
sc_out_bv<8> OUT;
Declarative
sc_in_bv<8> IN;
Portion
sc_in_clk CLK;
<other_declarations and constructor>
Void data_morph::entry() {
Executable <executable_statement>
Portion <executable_statement>
• • •
Module Characteristics - 1
p
Mymod
clk1 clk2
276
Ver 1.4
138
Module Characteristics - 2
A module has:
input and output ports
Ports connected directly to ports of constituent
processes
Not specified as data members
Constituent processes as data members
Processes
Constituent modules as data members
Constituent signals as data members
Constructor m sig_int n
a c e g
Process1 Process2
Output
Input Ports
b d f
Port
p
Mymod
clk1 clk2
m sig_int n
a c e g
Process1 Process2
b d f
p
Mymod
clk1 clk2
278
Ver 1.4
139
Example - Process 1 Interface File
#include “systemc.h”
struct process1 : public sc_module { m sig_int n
// Inputs a c e g
sc_in<bool> a;
sc_in<bool> b; Process1 Process2
// Outputs b d f
sc_out<bool> c;
sc_out<bool> d; p
sc_in_clk CLK; Mymod
clk1 clk2
Process2.cpp
// Constructor Process1.cpp
process1(const char *NAME) Process2.h
Process1.h
: sc_module (NAME) {
sc_sync_tprocess(handle1,”PROC1”,
process1, entry, CLK.pos());
end_module();
}
module.h
void entry( );
};
main.cpp
279
Ver 1.4
void entry( )
module.h
};
main.cpp
280
Ver 1.4
140
Example - module.h
#include “process1.h”
#include “process2.h”
struct mymod : public sc_module { m sig_int n
sc_in<bool> m;
sc_out<bool> n; a c e g
sc_out<bool> p; Process1 Process2
sc_in_clk CLK1;
sc_in_clk CLK2; b d f
p
// Internal signals Mymod
clk1 clk2
sc_signal<bool> sig_int;
Process2.cpp
Process1.cpp
// Component processes
process1 P1; Process1.h
Process2.h
process2 P2;
// Constructor
mymod(sc_module_name NAME)
: P1(“PROC1”), P2(“PROC2”) {
module.h
P1(M, M, sig_int, P, CLK1);
P2(sig_int, P, N, CLK2);
}
};
main.cpp
281
Ver 1.4
Name //
of the module processes
Component
process1 P1;
process2 P2;
// Constructor
mymod(sc_module_name NAME)
: P1(“PROC1”), P2(“PROC2”) {
P1(M, M, sig_int, P, CLK1);
P2(sig_int, P, N, CLK2);
}
};
282
Ver 1.4
141
module.h - Data Members
#include “process1.h”
#include “process2.h”
struct mymod : public sc_module {
sc_in<bool> m;
sc_out<bool> n;
Not a reference, but sc_out<bool> p;
an actual signal sc_in_clk CLK1;
sc_in_clk CLK2;
module.h - Constructor
#include “process1.h”
#include “process2.h”
struct mymod : public sc_module {
sc_in<bool> m;
sc_out<bool> n; Port e of P2 gets connected to sig_int, port f
sc_out<bool> p; of P2 to the port P of the module and port g of
sc_in_clk CLK1; P2 to port N of the module
sc_in_clk CLK2;
// Internal signals
sc_signal<bool> sig_int;
Constructor has the same Clock of P1
name as the module// Component processes comes from
process1 P1; port CLK1
process2 P2;
// Constructor
mymod(sc_module_name NAME)
: P1(“PROC1”), P2(“PROC2”) {
P1(M, M, sig_int, P, CLK1);
P2(sig_int, P, N, CLK2);
Initialize module
} Process constructors -
};
process instantiation
is completed here
284
Ver 1.4
142
Module Instantiation
Example:
sc_signal<bool> sig1;
sc_signal<bool> sig2;
sc_signal<bool> sig3;
sc_clock clk1(“Clock1”, 10, 0.5);
sc_clock clk2(“Clock2”, 10, 0.8);
285
Ver 1.4
Basic Information:
•This controller contains a speedometer, two odometers
(total and partial distance), a clock, and the pulse
generator.
•The pulses are generated by the sensors placed around
one of the wheel shafts.
•The rate of pulse generation is determined by the speed
of the car, which is constant at 120 km/h.
•The clock represents the real time. The signals in this
program are traced.
•The simulation is stopped by the odometers module.
286
Ver 1.4
143
Example Lab 8b: Dashboard Controller 2
read filter
Driver
(stimulus generator)
Pulse
KANBAO 88
Sensor #2 Sensor #4
287
Ver 1.4
};
288
Ver 1.4
144
Example Lab 8b: Dashboard Controller 4
struct driver_mod : sc_module {
Version Dash1
// Input ports:
sc_in_clk clk; // Clock for the actions of the driver.
sc_in<double> speed;
sc_in<double> angle;
sc_in<double> total; purpose (in terms of changes to dash0's purpose) -- environment
sc_in<double> partial;
module (driver); multiple clocks.
// Output ports:
sc_out<bool> reset; // Set if the driver wants to reset the partial
// distance odometer.
sc_out<int> speed_set; // Speed of the car as set by the driver.
sc_out<bool> start; // Set if the driver starts the car. 2 process in this module.
// Driver's actions.
void driver_out_proc();
void driver_in_proc(); sc_async_tprocess: Asynchronous Thread Process
sc_async_fprocess: Asynchronous Function Process
driver_mod(const char *NAME) : sc_module(NAME) {
sc_sync_tprocess: Synchronous Thread Process
sc_async_tprocess(handle1, “DRIVER_OUT_PROC”, driver_mod, driver_out_proc);
sensitive_pos << clk;
end_module();
}
};
289
Ver 1.4
// Driver's actions.
void driver_out_proc();
void driver_in_proc(); sc_async_tprocess: Asynchronous Thread Process
sc_async_fprocess: Asynchronous Function Process
driver_mod(sc_module_name NAME) {
sc_sync_tprocess: Synchronous Thread Process
sc_async_tprocess(handle1, “DRIVER_OUT_PROC”, driver_mod, driver_out_proc);
sensitive_pos << clk;
}
};
290
Ver 1.4
145
Example Lab 8b: Dashboard Controller 6
struct driver_mod : sc_module {
Version Dash4
// Input ports:
sc_in_clk clk; // Clock for the actions of the driver.
sc_in<double> speed;
sc_in<double> angle;
sc_in<double> total; purpose (in terms of changes to dash3's purpose) -- new style of
sc_in<double> partial;
declaring modules and processes (i.e., via the use of
// Output ports: module_name).
sc_out<bool> reset; // Set if the driver wants to reset the partial
// distance odometer.
sc_out<int> speed_set; // Speed of the car as set by the driver.
sc_out<bool> start; // Set if the driver starts the car. 2 process in this module.
// Driver's actions.
void driver_out_proc();
void driver_in_proc(); sc_async_tprocess: Asynchronous Thread Process
sc_async_fprocess: Asynchronous Function Process
driver_mod(sc_module_name NAME) {
sc_sync_tprocess: Synchronous Thread Process
sc_async_tprocess(handle1, “DRIVER_OUT_PROC”, driver_mod, driver_out_proc);
sensitive_pos << clk;
}
};
291
Ver 1.4
Summary
292
Ver 1.4
146
Summary for Day Two
Day Two
covered Synchronous processes
covered process execution order
covered main.cc and how to connect all
processes together
covered channels for high level abstraction
protocol
covered hierarchical design methodology
293
Ver 1.4
Remember:
Numgen.h and display.h contains the stimulus and control process declaration
Numgen.cc and display.cc contains the stimulus and control functionality
main.cc contains the main entry point and instantiates the all processes
294
Ver 1.4
147
Lab 8: Simple Arithmetic Pipeline Design II - 2
Stage2.cc Stage3.cc display.cc
Stage1.cc numgen.cc
Stage2.h display.h
Stage1.h Stage3.h numgen.h
Stage1_2.h Testbench.h
Pipeline.h
main.cc
295
Ver 1.4
Powr
Stage1 Stage1_2
Stage 2 Stage3
a^b
<double>
Tips : Make sure you have sc_signal in your module interface file.
! 296
Ver 1.4
148
Lab 8: Sample Output
Sample output:
297
Ver 1.4
DAY
3
Unit Topic Lab
16 Refinement
17 Functional I/F
18 Hardware/Software Co-verification
298
Ver 1.4
149
Modeling Real-Time Systems
environment
Real-Time
inputs System outputs
(state)
299
Ver 1.4
Modeling Reactivity
A reactive system is in constant interaction
with its environment
Reading inputs and producing outputs in response
to these inputs
Responding to exceptions like interrupts and resets
Responding to exceptions
Exceptions are interrupts, resets, etc.
Responding to an exception requires aborting the
execution of the process and execution of an
exception handler
Global or local
300
Ver 1.4
150
Watching
Mechanism for handling exceptions.
Check for exception conditions at every clock edge.
void
adder :: entry( )
{
while (true) {
out = in1 + in2;
wait( );
if (reset = = 1) { /* do something */ };
out = in1 + in2 + 2;
wait( );
if (reset = = 1) { /* do something */ };
}
}
301
Ver 1.4
Watching - What it is
SystemC mechanism is watching for an event
An event is watched in a particular region. Control flow is diverted
from its normal path whenever that event occurs
Exception Handler
Exception Handler
302
Ver 1.4
151
Watching Characteristics - Syntax
A watched event is specified as an expression
involving signals
Syntax:
watching ( expression );
expression: Signals of type sc_signal<bool>
and operators: ==, !=, &&, ||
delayed() method is
used to indicate that
signal should be read
at every cycle
Example:
watching (reset.delayed() == 1);
303
Ver 1.4
Watching Characteristics
304
Ver 1.4
152
Global Watching
305
Ver 1.4
306
Ver 1.4
153
Global Watching Characteristics - 1
watching() function
Must be invoked inside the constructor of the
process
Registers the globally watched event
There can be multiple watching() functions
reset_add +
delayed() method is used (more later). sum
Accumulator
Globally watched events are permanently registered. number
*
Watched throughout execution of the process
Accumulator prod
Cannot be disabled at any time reset_mult
307
Ver 1.4
154
entry () function Structure
The entry() function for watching begins with a check for the watched
conditions
executes code for handling these conditions if true
Ends with infinite loop
Body of the process
Statements are executed until watched conditions become true, then
Control is diverted to the beginning of the entry() function
Code for handling watched condition is executed
void process_name::entry()
{
// Put all local variable declarations here
int a;
char b;
// Put the code for handling watched signals here
check for if (reset.read() == 1) {
watched condition(s) // Code for handling reset
a = 0;
}
// Infinite loop that contains normal
// functionality of the process
while (true) {
Infinite loop // Normal process functionality
}
}
309
Ver 1.4
155
Example entry () function notes - 1
Explicit checks for watched conditions are recommended
Important when there are multiple watched conditions and handling
behavior is different.
Otherwise handlers may get executed the first time the entry()
function is executed.
mult_acc = 1;
}
311
Ver 1.4
reset_mult reset_add
asserted asserted
// Code to handle resets
if (reset_add.read() == true){
wait(3); reset_add +
sum_acc = 0; Accumulator sum
number
} *
if (reset_mult.read() == true){ prod
reset_mult Accumulator
wait(5);
mult_acc = 1;
} 312
Ver 1.4
156
Local Watching
313
Ver 1.4
Syntax:
W_BEGIN // Declaration block
watching (event) ;
W_DO // Action block
W_ESCAPE // Escape block
W_END
314
Ver 1.4
157
Example Local Watching
/* Filename accumulator.cc */
#include "systemc.h"
#include "accumulator.h"
void accumulator::entry()
{
int a;
// Code to handle resets
if (reset_add.read() == true) {
sum_acc = 0;
wait(3);
}
while (true) {
W_BEGIN // local watching block for reset_mult
{
watching(reset_mult.delayed() == true);
}
W_DO
{ // Normal functionality
a = number.read();
sum_acc += a;
mult_acc *= a; reset_add +
sum.write(sum_acc);
prod.write(mult_acc); Accumulator sum
wait(); number
} *
W_ESCAPE prod
reset_mult Accumulator
{ // reset_mult handler
mult_acc = 1;
wait(5);
}
W_END
}
} // end of entry function
315
Ver 1.4
316
Ver 1.4
158
Local Watching Characteristics - 2
Events being watched are registered when a local watching
block is entered (reset_mult).
Normally, statements in the action block are executed.
When any event being watched happens:
action block is preempted
control is diverted to escape block
317
Ver 1.4
159
Nested Local Watching - In Action Block
W_BEGIN // Local watching block A - event A is being watched
....
W_DO // Action block of A
....
W_BEGIN // Local watching block B - event B is being watched
....
W_DO // Action block of B
....
W_ESCAPE // Escape block of B
....
W_END // End of local watching block B
....
W_ESCAPE // Escape block of A
....
If event A occurs, control is transferred to escape
W_END // End of local watching block A block of A
Event B is no longer watched and has no effect
If event B occurs:
If local watching block B has not been entered,
then no effect until B is entered
If local watching block B has been entered,
control is transferred to escape block of B
If event A occurs, escape block B is preempted
and control is transferred to escape block of A
If events A and B occur simultaneously, control is
transferred to escape block of A.
319
Ver 1.4
320
Ver 1.4
160
Nested Local Watching - In Escape Block - 2
W_BEGIN // Local watching block A - event A is being watched
....
W_DO // Action block of A
....
W_ESCAPE // Escape block of A
....
W_BEGIN // Local watching block B - event B is being watched
....
W_DO // Action block of B
....
W_ESCAPE // Escape block of B
....
W_END // End of local watching block B
....
W_END // End of local watching block A
If event B occurs:
If only B then no effect.
Then if event A occurs, control is transferred to escape block of A.
At some point local watching block B is entered and condition
for event B may transfer control to escape block of B.
If events A and B occur simultaneously, control is transferred to
escape block of A.
If local watching block B has not been entered, then no effect until
B is entered
321
Ver 1.4
Summary
322
Ver 1.4
161
Agenda: Day Three
DAY
3
Unit Topic Lab
16 Refinement
17 Functional I/F
18 Hardware/Software Co-verification
323
Ver 1.4
sc_bv<>
Essentially an SystemCTM array of type bool
Additional methods for:
Bitwise logical operations
Operations with C++ strings
Operations with arbitrary-precision unsigned and signed
integers
Operations with arbitrary-precision built-in integers
Used whenever a vector of bits is required
Use SystemCTM arithmetic types if the vector of bits to be
interpreted as a number with arithmetic operations performed on
it.
324
Ver 1.4
162
sc_bv<> Syntax
Data Type Syntax:
sc_bv<length> variable_name ;
Signal Syntax:
sc_signal_bv<length> signal_name ;
length:
Specifies the number of elements in the array
Must be greater than 0
Must be compile time constant
Example:
sc_bv<10> a ; //variable “a” is a bool vector of 10 bits
sc_signal_bv<10> asig ; //signal “asig” is a bool vector of 10 bits
325
Ver 1.4
326
Ver 1.4
163
sc_lv<> Syntax
Data Type Syntax:
sc_lv<length> variable_name ;
Signal Syntax:
sc_signal_lv<length> signal_name ;
length:
Specifies the number of elements in the array
Must be greater than 0
Must be compile time constant
Example:
sc_lv<10> a ; //variable “a” is a logic vector of 10 bits
sc_signal_lv<10> asig ; //signal “asig” is a logic vector of 10 bits
327
Ver 1.4
Concatenation of Arrays
Arrays of type sc_bv and sc_lv can be concatenated.
Operator is the comma ( , )
May be used with an array and a scalar if elements same type.
Concatenation of two scalars is illegal
Indexing operator [ ] and range methods are applicable
sc_bv<5> a;
sc_bv<4> b;
bool c = false;
b = "1010";
a = (b, c); // a gets 10100
a = (c, b); // a gets 01010
a = (b.range(3,1), c, b[0]); // a gets 10100
(a, b) = "101110000"; // a gets 10111, b gets 0000
(c, a) = "111001"; // c gets 1, a gets 11001
sc_bv<2> x;
bool m, n;
m = false; n = true;
x = (m, n); // concatenation of two scalars - illegal
328
Ver 1.4
164
Types & bit widths
Objects of compatible types but different bit-widths:
Step 1: Identify maximum precision required for the expression
Size of operand on LHS in the case of assignments
Size of largest operand when not an assignment
Resolved Signals
330
Ver 1.4
165
Resolved Signal DataType: sc_signal_rv<>
Syntax:
sc_signal_rv<length> signal_name ;
331
Ver 1.4
332
Ver 1.4
166
Concatenation Example Use
sc_signal<bool> carry;
sc_signal_bv<16> sum;
sc_int<8> a, b;
sc_int<17> temp;
temp = a + b;
Similar method
(carry, sum).write(temp);
for checking overflow
. . .
sc_signal_bv<8> lsb;
sc_signal_bv<8> msb;
sc_bv<16> bus;
bus = (msb, lsb).read();
333
Ver 1.4
Summary
334
Ver 1.4
167
Lab 9: Master-Slave Bus System - 1
Basic Information:
Assumption: the slaves are always accessible and never
busy for something else
Data bus is used for both read and write and is accessed by
the masters and slaves through resolved signals
Resolved signals are used by the masters to transmit to
targeted addresses ( on a 32 bit address bus) and direction
control signal
Bus Bus Bus
Master Master Arbiter
Bus Bus
Slave Slave
335
Ver 1.4
Bus Bus
Slave Slave
336
Ver 1.4
168
Lab 9: Master-Slave Bus System - 3
Basic Information:
These blocks are all sc_async_fprocess (ver 0.9: sc_async
block) triggered by a clock signal
Master deliver request signals to the arbiter and monitor a
potential grant signal from the arbiter.
Master’s request delivery rule here is set to be random with a
probability of 1/10 to actually ask for the bus
When there is a conflict, a grant signal is randomly granted to
one of the bus master
Bus Bus
Slave Slave
337
Ver 1.4
Bus Bus
Slave Slave
338
Ver 1.4
169
Lab 9: Master-Slave Bus System - 5
Primary Objective:
create an asynchronous function process for the bus Master
(Master.cc) using sc_signal_rv
mRequest
mClock mAddress
mData
Master
mGranted mDirection
sampleDirection
339
Ver 1.4
sc_out<bool> mRequest;
sc_inout_rv<32> mAddress;
sc_inout_rv<256> mData;
sc_inout<sc_logic> mDirection;
sc_in_clk mClock;
sc_in<bool> mGranted;
sc_logic sampledDirection;
void entry();
};
340
Ver 1.4
170
Lab 9: Master-Slave Bus System - 7
State machine for Bus Master
Read sampledDirection
and mCurrentState = mNextstate
mCurrentState = mStart
fireAtRandomRequest() == true
Yes
mCurrentState = mRequesting
mGranted == true
Yes
342
Ver 1.4
171
Lab 9: Master-Slave Bus System - 9
State machine for Bus Master
Read sampledDirection
and mCurrentState = mNextstate
mCurrentState = mTransfering
tmpData = fireAtRandomData();
cout << "master's Data Choice: " << tmpData << endl;
tmpDirection = fireAtRandomDirection();
cout << "master's direction choice: " << tmpDirection << endl;
tmpAddress = fireAtRandomAddress();
cout << "master's Address Choice: " << tmpAddress << endl;
343
Ver 1.4
tmpDirection == 1
Yes
mData.write(tmpData);
mAddress <= tmpAddress
mDirection.write(1);
mData <= “ZZZZ…”
mAddress.write(tmpAddress); mDirection <= 0
mGranted == false
Yes
344
Ver 1.4
172
Lab 9: Master-Slave Bus System - 11
Provided Routine in Master.cc
bool Master::fireAtRandomRequest() const {
if ( ((double(rand()))/RAND_MAX) > 0.9 ) return true;
else return false;
};
345
Ver 1.4
346
Ver 1.4
173
Lab 9: Additional Topics - 1
Can you model PCI CONFIGURATION ?
PROCESSOR
CACHE
BRIDGE / MEMORY
CONTROLLER
DRAM MOTION
AUDIO VIDEO
PCI BUS
174
Lab 9: Additional Topics - 3
PCI COMPLIANT *** Target *** DEVICE SIGNALS
AD[31:0]
Address/Data C/BE#[3:0]
64-Bit
and Command
Extension
PAR
FRAME#
TRDY#
Atomic Accesses
CLKRUN#
Interface
IRDY# PCI Clock Control
SBO#
STOP#
Control Compliant SDONE Snoop Result
DEVSEL#
Target TDI
IDSEL TDO JTAG
TCK Boundary
Scan
TMS IEEE 1149.1
TRST#
CLK
INTA#
System RST#
INTB#
PERR# Interrupt
Error INTC# Request
SERR#
Reporting INTD#
349
Ver 1.4
16 Refinement
17 Functional I/F
18 Hardware/Software Co-verification
350
Ver 1.4
175
Refinement
System Specification
Refine Structure
• Partition into blocks that will be
independently synthesized/refined (HW/SW)
and resource sharing
• Refine interfaces for communication
System Implementation
351
Ver 1.4
BUS
Controller
DMA
Cache
in_real out_real
352
Ver 1.4
176
Example: FFT Testbench
Processes:
Unit Level Validation - requires stimulus generation process and
result monitoring process.
There are 3 synchronous processes:
in_imag out_imag
data_req data_valid
source.h, source.cc fft.h, fft.cc sink.h, sink.cc
data_ready data_ack
353
Ver 1.4
Example: Verification
Two Primary methods of verification
Create a local testbench to verify the design
sc_main (main.cc)
DSP CPU
FFT DMA RTOS
Routine Model
sc_main (main.cc)
354
Ver 1.4
177
Example: FFT Floating Point Version
sc_module {
void fft::entry() sc_in<float> in_real;
{ float sample[16][2]; sc_in<float> in_imag;
unsigned int index; sc_in<bool> data_valid;
sc_in<bool> data_ack; Use of native Data Types
while(true) sc_out<float> out_real;
{ data_req.write(false); sc_out<float> out_imag;
data_ready.write(false); sc_out<bool> data_req;
index = 0; sc_out<bool> data_ready;
//Reading in the Samples sc_in_clk CLK;
cout << endl << "Reading in the samples..." . . .
<< endl;
while( index < 16 )
{
data_req.write(true);
wait_until(data_valid.delayed() == true);
sample[index][0] = in_real.read();
sample[index][1] = in_imag.read();
index++;
data_req.write(false);
wait();
}
index = 0;
….
355
Ver 1.4
178
Arithmetic Operation
Use fixed-point datatypes like sc_int/sc_uint instead
of unnecessary full integer range for modeling
less than 32 bits data
Multiplying an INTEGER by 2 ** N will shift its bit
level equivalent N places to the left
Shifted bits on the right will be zero filled
USE bitwise shift operator will speed up the simulation
Dividing an INTEGER by 2 ** N will shift its bit level
equivalent N places to the right
Shifted bits on the left will be sign extended
USE bitwise shift operator will speed up the simulation
357
Ver 1.4
358
Ver 1.4
179
Architectural Trade-Offs : Additions
Designer Makes Architecture Tradeoffs
Example: Serial vs. Parallel
Shared
X0 X1 X2 X3
Parallel
SEL
X X0 X1 X2 X3
RST
+
Z1 +
Z Z
Y= D + E + F
= 945 + 446 + 715 = 2106
360
Ver 1.4
180
Modeling Optimal Arithmetic
+ a
csa
+
b b
c
c
+ + d
csa
+
Y
d e csa csa Y
e f
+
f
Carrysave arithmetic
is the most effective
datapath technique
361
Ver 1.4
+ + csa csa 4 9
5 13
6 19
7 28
8 42
+
Carry delay 9 63
incurred CSA csa
10 94
three times Transformation
Level 1
(for carry-look-ahead Arch.) y
csa
Input w/o csa w/csa improvement
width area area area
8 965 438 44%
+
16 2310 897 61% Carry delay
32 5617 1957 65% incurred
delay delay delay once
8 4.02 3.77 6%
16 4.90 4.14 16% y
32 5.83 4.37 25% 362
Ver 1.4
181
Ripple Carry Adder - Review
A B CI A B CI A B CI A B CI
CO S CO S CO S CO S
363
Ver 1.4
A3 B3 A2 B2 A1 B1 A0 B0
CLA Logic
C4 C3 C2 C1
364
Ver 1.4
182
Carry Select Adder - Example
Y = A[9:0] + B[9:0]
4 bit ripple adder 3 bit ripple adder 2 bit ripple adder 1 bit ripple adder
A[9:6] B[9:6] A[5:3] B[5:3] A[2:1] B[2:1] A[0] B[0]
FA FA FA FA 0 FA FA FA 0 FA FA 0 FA 0
0 0 0 0
Cout
1 A[9:6] B[9:6] 1 A[5:3] B[5:3] 1 A[2:1] B[2:1] 1 A[0] B[0]
FA FA FA FA 1 FA FA FA 1 FA FA 1 FA 1
Cin
0 1 0 1 0 1 0 1
365
Ver 1.4
183
Subtraction in 2’s Complement
a b
Example:
a b 8 8 y = a+b-c-d
8 8 = a+b+(~c)+(~d) +2
c d
+ - Logic1
free!
- A B a b
8 + Cin
CSA
Cin
Logic1
8
y
Logic1
y CSA
Cin
y = a - b
+ Cin
y = a + (~b) + 1 Logic0
Two’s
Complement
of b
367
Ver 1.4
BITREV
Conceptual
View
BITREV
OUT OUT
Parallel Serial
Y
Σ
AxB
Conceptual
Y Σ
AxB U
View Σ
AxB
V
U
Σ
AxB
V
[RGB] [C1]
[RGB] [C1]
[C0] [C2]
[C0] [C2]
368
Ver 1.4
184
Architectural Trade-Offs : Complex Multiply
* Imag
c * +
Imag
sum = a + b;
SystemC
Code
d
*Real = a*c - b*d;
diff = c-d;
ad = a*d;
bc = b*c;
Imag = b*c + a*d; Real = (sum * diff) + ad - bc;
Imag = bc + ad;
369
Ver 1.4
R1 S1 S2
add_1
* +
S3
R2
FSM R3
state
reg Decode
Logic
370
Ver 1.4
185
Finite State Machine Overview
Two general types of Finite State Machines
Implicit FSM descriptions Explicit FSM descriptions
• Suited for “structured” • Easier to write with many
sequential systems state transitions or
• Easier to read & debug “unstructured” systems
371
Ver 1.4
}
A
372
Ver 1.4
186
Explicit FSM style
Inputs Output
Next state Logic Outputs
logic cloud State cloud
Vector
clk
clock
reset
374
Ver 1.4
187
Synchronous Moore Machine Overview
clock
reset
375
Ver 1.4
•Combinational:
•OR
•Combinational logic is separated from the next state register
assignments
188
Alternative Coding Styles for Synchronous FSMs
One process only
Handles both state transitions and outputs
Two processes
A synchronous process for updating the state register
A combinational process for conditionally deriving the next
machine state and updating the outputs
Three processes
A synchronous process for updating the state register
A combinational process for conditionally deriving the next
machine state
A combinational process for conditionally deriving the outputs
377
Ver 1.4
Here we will use a simple RISC core and show you how to
convert it from Verilog to SystemC code easily.
SystemC
378
Ver 1.4
189
A Simple Verilog RISC Core - 1
// //
module RISC; OP_A_MINUS_ONE = 6'b000110,
OP_A_AND_NOT_B = 6'b010100,
parameter OP_A_XOR_B = 6'b010110,
RWIDTH = 16, OP_A_OR_B = 6'b010111,
IWIDTH = 32, OP_NOT_B = 6'b011100,
ZERO = 0, OP_A_OR_NOT_B = 6'b011101,
NEG = 1, OP_NAND = 6'b011110,
CARRY = 2; OP_JTRUE = 6'b100000,
OP_JFALSE = 6'b100010,
parameter OP_HALT = 6'b111111,
OP_ADD = 6'b000000, OP_CALL= 6'b010000,
OP_ADD_PLUS_ONE = 6'b000001, OP_RET = 6'b001000,
OP_A = 6'b000010,
OP_A_PLUS_ONE = 6'b000011, ALU_NEG = 8'b00000000,
OP_AND = 6'b010001, ALU_ZERO = 8'b00000001,
OP_NOT_A_AND_B = 6'b010010, ALU_CARRY = 8'b00000010,
OP_B = 6'b010011, ALU_NEG_ZERO = 8'b00000011,
OP_NOT_A_AND_NOT_B = 6'b011000, BOOL_SHIFT_ZERO = 8'b00000100,
OP_A_XNOR_B = 6'b011001,
OP_NOT_A = 6'b011010, ALU_TRUE = 8'b00111111;
OP_NOT_A_OR_B = 6'b011011,
OP_SUB_MINUS_ONE = 6'b000100,
OP_SUB = 6'b000101,
379
Ver 1.4
// //
reg [31:0] instr_mem[0:255]; function [2:0] check_result ;
reg [IWIDTH-1:0] instruction; input [RWIDTH-1 :0] result;
reg [15:0] pc; //Program Counter input [RWIDTH-1 :0] op1;
reg [15:0] regfile[0:127]; input [RWIDTH-1 :0] op2;
reg [7:0] ra,rb; //Register address for op1,op2; begin
reg [RWIDTH-1:0] op1,op2;
reg [7:0] wr; //Write address check_result = 0;
reg [RWIDTH-1:0] result; //result of ALU
operation if ( result == 0)
reg [7:0] cond; //Condition check_result[0] = 1'b1;
reg [7:0] ja; //Jump address else
reg [7:0] ssr; //Status register check_result[0] = 1'b0;
reg clk;
reg [7:0] stack_ssr[0:127]; //Stack to store ssr if ( result[RWIDTH-1] == 1 )
info check_result[1] = 1'b1;
reg [15:0] stack_pc[0:127]; //Stack to store pc else
info check_result[1] = 1'b0;
if ( (op1[RWIDTH-1] ^ op2[RWIDTH-1] ) != 0 )
reg instr_type[1:0]; check_result[2] = 1'b0;
reg opcode[5:0]; else if ( ( result[RWIDTH-1] ^ op1[RWIDTH-1]
integer i; //Pointer for stack memory ) ==1 )
check_result[2] = 1'b1;
integer clk_count;
else
check_result[2] = 1'b0;
end
endfunction
380
Ver 1.4
190
A Simple Verilog RISC Core - 3
// //
initial always @( posedge clk)
begin begin
clk = 1; if ( clk_count == 10000000)
pc=0; $finish;
i=0; clk_count = clk_count+1;
ssr=0; instruction=instr_mem[pc];
$readmemh("instruction.hex",instr_mem); // instr_type[1:0]=instruction[31:30];
$readmemh("data.hex",regfile); // opcode[5:0]=instruction[IWIDTH-3:IWIDTH-8];
end
381
Ver 1.4
// //
2'b10 :begin OP_ADD_PLUS_ONE :begin
wr=instruction[IWIDTH-9:IWIDTH-16]; // result = itype_to_signed(op1) + itype_to_signed(op2);
ra=instruction[IWIDTH-17:IWIDTH-24]; result = op1 + op2 + 1;
//regfile[std_logic_vector_to_integer(wr)]=result;
op1=regfile[(ra)];
ssr[2:0] = check_result(result,op1,op2);
//op2=sign_extend(instruction[IWIDTH-25:IWIDTH-32]); //$display("ssr = %d", ssr);
op2 = { 8'b00000000, instruction[IWIDTH-25:IWIDTH- //$display("op1 + op2 + 1 = %b ", result);
32]}; pc = pc + 1;
end end
2'b11 :begin
wr=instruction[IWIDTH-9:IWIDTH-16]; OP_A :begin
//op1=sign_extend(instruction[IWIDTH-17:IWIDTH-29]); result = op1 ;
op1 = { 3'b000, instruction[IWIDTH-17:IWIDTH-29]}; ssr[2:0] = check_result(result, op1, op2) ;
//$display("ssr = %d", ssr);
end
//$display("op1 = %b ", result);
default :; pc = pc + 1;
endcase end
end
382
Ver 1.4
191
A Simple Verilog RISC Core - 5
// //
OP_NOT_A_AND_B :begin OP_A_XNOR_B :begin
result = (~op1) & (op2) ; // result = CONV_SIGNED(SIGNED(not (op1 xor op2)),
ssr[2 : 0] = check_result(result, op1, op2); RWIDTH+1) ;
//$display("ssr = %d", ssr); result = ~ ((op1) ^ (op2)) ;
//$display("(NOT op1) AND op2 = %b ", result); ssr[2 : 0] = check_result(result, op1, op2);
pc = pc + 1; //$display("ssr = %d", ssr);
end //$display("op1 XNOR op2 = %b", result);
pc = pc + 1;
OP_B :begin end
// result = abs(CONV_SIGNED(SIGNED(op2),
RWIDTH+1)) ; OP_NOT_A :begin
result = op2 ; // result = abs ((CONV_SIGNED(SIGNED(not op1),RWIDTH+1)))
ssr[2 : 0] = check_result(result, op1, op2) ; ;
//$display("ssr = %d", ssr); result = ~(op1) ;
//$display("op2 = %b ", result); ssr[2 : 0] = check_result(result, op1, op2);
pc = pc + 1; //$display("ssr = %d", ssr);
end //$display("NOT op1 = %b ",result);
pc = pc + 1;
OP_NOT_A_AND_NOT_B :begin end
result = (~ op1) & (~ op2) ;
ssr[2 : 0] = check_result(result, op1, op2); OP_NOT_A_OR_B :begin
//$display("ssr = %d", ssr); // result = abs (CONV_SIGNED(SIGNED((not op1) OR
//$display("(NOT op1) AND (NOT op2) = %b ", result); (op2)),RWIDTH+1)) ;
pc = pc + 1;
result = (~ op1) | (op2) ;
end
ssr[2 : 0] = check_result(result, op1, op2);
//$display("ssr = %d", ssr);
//$display("(NOT op1) OR op2 %b ", result);
pc = pc + 1;
end
383
Ver 1.4
// //
OP_SUB_MINUS_ONE :begin OP_A_XOR_B :begin
result = op1 - op2 -1; result = op1 ^ op2 ;
ssr[2 : 0] = check_result(result, op1, op2); // result = (CONV_STD_LOGIC_VECTOR(SIGNED(op1),
//$display("ssr = %d", ssr); RWIDTH+1) xor CO
NV_STD_LOGIC_VECTOR(SIGNED(op2), RWIDTH+1)) ;
//$display("op1 - op2 - 1 = %b ",result); ssr[2 : 0] = check_result(result, op1, op2) ;
pc = pc + 1; //$display("ssr = %d", ssr);
end //$display("op1 XOR op2 = %b ", result);
pc = pc + 1;
OP_SUB :begin end
result = op1 - op2 ;
ssr[2 : 0] = check_result(result, op1, op2) ; OP_A_OR_B :begin
//$display("ssr = %d", ssr); result = op1 | op2 ;
//$display("op1 - op2 = %b ", result); // result = (CONV_STD_LOGIC_VECTOR(SIGNED(op1),
pc = pc + 1; RWIDTH+1) or CONV_STD_LOGIC_VECTOR(SIGNED(op2), RWIDTH+1)) ;
end // result = op1 or op2 ;
ssr[2 : 0] = check_result(result, op1, op2) ;
OP_A_MINUS_ONE :begin //$display("ssr = %d", ssr);
result = op1 - 1 ; //$display("op1 OR op2 = %b ", result);
ssr[2 : 0] = check_result(result, op1, op2) ; pc = pc + 1;
//$display("ssr = %d", ssr);
//$display("op1 - 1 = %b ", result); end
pc = pc + 1;
OP_NOT_B :begin
result = ~ op2 ;
end
ssr[2 : 0] = check_result(result, op1, op2) ;
//$display("ssr = %d", ssr);
OP_A_AND_NOT_B :begin
//$display("NOT op2 = %b ",result);
result = (op1) & (~ op2) ;
ssr[2 : 0] = check_result(result, op1, op2) ;
pc = pc + 1;
//$display("ssr = %d", ssr);
//$display("op1 AND (NOT op2) = %b ", result); end
pc = pc + 1;
end
384
Ver 1.4
192
A Simple Verilog RISC Core - 7
// //
OP_JTRUE :begin
OP_A_OR_NOT_B :begin case (cond)
ALU_NEG :begin
result = op1 | (~ op2) ; if (ssr[NEG] ==1)
// result = pc = (ja);
(CONV_STD_LOGIC_VECTOR(SIGNED(op1),RWIDTH+1)) OR else
pc = pc + 1;
// (CONV_STD_LOGIC_VECTOR(SIGNED(not end
op2),RWIDTH+1)) ;
ssr[2 : 0] = check_result(result, op1, op2) ; ALU_ZERO :begin
//$display("ssr = %d", ssr); if (ssr[ZERO] == 1)
//$display("op1 OR (NOT op2) = %b ", result); pc = (ja);
pc = pc + 1; else
end pc = pc + 1;
end
OP_NAND :begin
result = ~(op1 & op2) ; ALU_CARRY :begin
// result = if (ssr[CARRY] == 1)
CONV_STD_LOGIC_VECTOR(SIGNED(op1),RWIDTH+1) NAND pc = (ja);
else
// pc = pc + 1;
CONV_STD_LOGIC_VECTOR(SIGNED(op2),RWIDTH+1) ; end
ssr[2 : 0] = check_result(result, op1, op2) ;
//$display("ssr = %d", ssr); ALU_NEG_ZERO :begin
//$display("op1 NAND op2 = %b ",result); if (ssr[ZERO] == 1 || ssr[NEG] == 1)
pc = pc + 1; pc = (ja);
else
end pc = pc + 1;
end
//BOOL_SHIFT_ZERO :begin
//end
//ALU_TRUE :begin
//end
default :;
385
Ver 1.4
BOOL_SHIFT_ZERO :begin
end
ALU_TRUE :begin
end
default :begin
end
endcase
end 386
Ver 1.4
193
A Simple Verilog RISC Core - sc_async Integer - 1
//risc.h //risc.h
#include <stdio.h> #define OP_NOT_B 28
#include <stdlib.h> #define OP_A_OR_NOT_B 29
#include "systemc.h" #define OP_NAND 30
#define OP_JTRUE 32
#define OP_JFALSE 34
#define OP_HALT 63
#define OP_ADD 0 #define OP_CALL 16
#define OP_ADD_PLUS_ONE 1 #define OP_RET 8
#define OP_A 2
#define OP_A_PLUS_ONE 3
#define OP_AND 17 #define ALU_NEG 0
#define OP_NOT_A_AND_B 18 #define ALU_ZERO 1
#define OP_B 19 #define ALU_CARRY 2
#define OP_NOT_A_AND_NOT_B 24 #define ALU_NEG_ZERO 3
#define OP_A_XNOR_B 25 #define BOOL_SHIFT_ZERO 4
#define OP_NOT_A 26 #define ALU_TRUE 63
#define OP_NOT_A_OR_B 27
#define OP_SUB_MINUS_ONE 4 #define ZERO 0
#define OP_SUB 5 #define NEG 1
#define OP_A_MINUS_ONE 6
#define OP_A_AND_NOT_B 20 #define CARRY 2
#define OP_A_XOR_B 22
#define OP_A_OR_B 23
387
Ver 1.4
388
Ver 1.4 };
194
A Simple Verilog RISC Core - sc_async Integer - 3
//risc.cc //risc.cc
#include<stdio.h> signed result ; // (15,0);
#include "risc.h"
if ( clock_i.posedge())
#define CHECK_RESULT if ( result == 0 ) ssr = {
ssr | 0x01; else ssr = ssr & 0xf instruction = instr_mem[pc];
e; if ( result < 0 ) ssr = ssr | 0x02; else ssr = ssr & instr_type = (instruction ) >> 30 ; //sub(31,30);
0xfd ; if (((op1 >> 15) opcode = (instruction & 0x3fffffff) >> 24; //
^ (op2 >> 15) ) != 0) ssr = ssr & 0xfb; else {if (( sub(29,24)
(result < 0) ^ (op1>>15)) == switch (instr_type)
1) ssr = ssr | 0x04 ; else ssr = ssr &0xfb;} {
case 0 :
cond = (instruction & 0x00ffffff) >> 16;
void risc_nopipe :: entry() ja = (instruction & 0x0000ffff) >> 8;
{ break;
case 1 :
unsigned instruction ; //(31,0); wr = (instruction & 0x00ffffff) >> 16;
unsigned instr_type ; //(1,0); ra = (instruction & 0x0000ffff) >> 8;
unsigned opcode ; //(5,0); rb = (instruction & 0x000000ff );
unsigned cond ; // (7,0); op1 = reg_file[ra];
unsigned ja ; // (7,0); op2 = reg_file[rb];
unsigned ra ; // (7,0); break;
unsigned rb ; // (7,0); case 2 :
unsigned wr ; //(7,0);
unsigned op1 ; //(15,0); wr = (instruction & 0x00ffffff) >> 16;
//risc.cc //risc.cc
ra = (instruction & 0x0000ffff) >> 8;
op1 = reg_file[ra]; CHECK_RESULT;
op2 = instruction & 0x000000ff; //printf(" ssr = %d\n", ssr);
break; //printf("op1 + op2 + 1 = %d \n",
case 3 : result);
wr = (instruction & 0x00ffffff) >> 16; pc = pc + 1;
op1 = (instruction &0x0000ffff) >> 3; break;
break;
default : case OP_A : result = op1;
pc = pc + 1; CHECK_RESULT;
break; //printf(" ssr = %d\n", ssr);
} //printf(" op1 = %d \n", op1);
pc = pc + 1;
break;
switch ( opcode)
{ case OP_A_PLUS_ONE :
case OP_ADD : result = op1 + op2; result = op1 + 1;
CHECK_RESULT; CHECK_RESULT;
//printf(" ssr = %d\n", ssr); //printf(" ssr = %d\n", ssr);
//printf("op1 + op2 = %d \n", result); // //printf("op1+ 1 = %d \n", result);
pc = pc + 1; pc = pc + 1;
break; break;
case OP_AND :
case OP_ADD_PLUS_ONE : result = op1 + op2 + 1; result = op1 & op2 ;
CHECK_RESULT;
390
Ver 1.4
195
A Simple Verilog RISC Core - sc_async Integer - 5
//risc.cc //risc.cc
//printf(" ssr = %d\n", ssr); CHECK_RESULT;
//printf(" op1 & op2 = %d \n", //printf(" ssr = %d\n", ssr);
result); //printf(" (NOT OP1) & ( NOT OP2) =
pc = pc + 1; %d \n", result);
break; pc = pc + 1;
break;
case OP_NOT_A_AND_B :
result = ( ~op1) & op2; case OP_A_XNOR_B :
CHECK_RESULT; result = op1 ^ op2;
//printf(" ssr = %d\n", ssr); result = ~ result;
//printf(" OP_NOT_A_AND_B = CHECK_RESULT;
%d\n", result); //printf(" ssr = %d\n", ssr);
pc = pc + 1; //printf( "OP A XNOR B = %d \n",
break; result);
pc = pc + 1;
case OP_B : break;
result = op2;
CHECK_RESULT; case OP_NOT_A :
//printf(" ssr = %d\n", ssr); result = ~op1;
//printf(" op 2 = %d\n", result); CHECK_RESULT;
pc = pc + 1; //printf(" ssr = %d\n", ssr);
break; //printf( " NOT A = %d \n", result);
pc = pc + 1;
case OP_NOT_A_AND_NOT_B :
break;
result = ( ~op1) & ( ~op2);
391
Ver 1.4
//risc.cc //risc.cc
case OP_NOT_A_OR_B : case OP_A_MINUS_ONE :
result = ~op1 | op2; result = op1 - 1;
CHECK_RESULT; CHECK_RESULT;
//printf(" ssr = %d\n", ssr); //printf(" ssr = %d\n", ssr);
//printf(" (NOT A ) or B %d \n" , //printf( " op1 - 1 = %d \n", result);
result); pc = pc + 1;
pc = pc + 1; break;
break; case OP_A_AND_NOT_B :
result = op1 & ( ~op2);
case OP_SUB_MINUS_ONE : CHECK_RESULT;
result = op1 - op2 - 1; //printf(" ssr = %d\n", ssr);
CHECK_RESULT; //printf( " op1 AND ( not op2 ) %d \n",
//printf(" ssr = %d\n", ssr); result);
//printf( " op1 - op2 - 1 = %d \n", pc = pc + 1;
result); break;
pc = pc + 1; case OP_A_XOR_B :
break; result = op1 ^ op2;
case OP_SUB : CHECK_RESULT;
result = op1 - op2; //printf(" ssr = %d\n", ssr);
CHECK_RESULT; //printf( "op1 XOR op2 = %d \n",
//printf(" ssr = %d\n", ssr); result);
//printf(" op1 - op2 = %d\n", result); pc = pc + 1;
pc = pc + 1; break;
case OP_A_OR_B :
break;
result = op1 | op2 ;
392
Ver 1.4
196
A Simple Verilog RISC Core - sc_async Integer - 7
//risc.cc //risc.cc
CHECK_RESULT; //printf(" ssr = %d\n", ssr);
//printf(" ssr = %d\n", ssr); //printf( " op1 NAND op2 = %d \n", result);
//printf( " op1 OR op2 = %d \n", result); pc = pc + 1;
pc = pc + 1; break;
break; case OP_JTRUE :
case OP_NOT_B : switch ( cond)
result = ~op2; {
CHECK_RESULT; case ALU_NEG :
//printf(" ssr = %d\n", ssr); if ( ((ssr & 0x02)>> NEG) == 1)
//printf( " NOT op2 = %d\n", result); pc = ja;
pc = pc + 1; else
break; pc = pc + 1;
case OP_A_OR_NOT_B : break;
result = op1 | ( ~op2); case ALU_ZERO :
CHECK_RESULT; if (( ssr & 0x01) == 1)
//printf(" ssr = %d\n", ssr); pc = ja;
//printf( " op1 OR ( not op2 ) %d \n", else
result); pc = pc + 1;
pc = pc + 1; break;
break; case ALU_CARRY :
case OP_NAND : if ( (ssr & 0x04 ) >>CARRY == 1)
result = op1 & op2 ; pc = ja;
result = ~result;
else
CHECK_RESULT;
393
Ver 1.4
//risc.cc //risc.cc
pc = pc + 1; if (( ssr & 0x01) == 1)
break; pc = ja;
case ALU_NEG_ZERO : else
if ( ((ssr & 0x01 )== 1) && (( (ssr pc = pc + 1;
& 0x02) >> NEG) == 1)) break;
pc = ja; case ALU_CARRY :
else if ( (ssr & 0x04 ) >>CARRY ==
pc = pc + 1; 0)
break; pc = ja;
default : pc = pc + 1; else
break; pc = pc + 1;
} break;
break; case ALU_NEG_ZERO :
case OP_JFALSE : if ( ((ssr & 0x01 )== 0) && (( (ssr
switch ( cond) & 0x02) >> NEG) == 0))
{ pc = ja;
case ALU_NEG : else
if ( ((ssr & 0x02)>> NEG) == 0 ) pc = pc + 1;
pc = ja; break;
else default : pc = pc + 1;
pc = pc + 1; break;
break; }
394
Ver 1.4
197
A Simple Verilog RISC Core - sc_async Integer - 9
//risc.cc
case OP_CALL :
pc = pc + 1;
stack_ssr[stack_top] = ssr;
stack_pc[stack_top] = pc;
stack_top = stack_top + 1;
pc = ja;
break;
case OP_RET :
stack_top = stack_top - 1;
ssr = stack_ssr[stack_top];
pc = stack_pc[stack_top];
break;
default :
pc = pc + 1;
break;
}
}
395
Ver 1.4
//risc.cc //risc.cc
396
Ver 1.4
198
Proverb for Effective Refinement
e coding
The mor ues
d techniq
tricks an ow
kn
that you
ier your
the happ life will be
nt
refineme
397
Ver 1.4
Summary
Refinement
covered how to refine a model taking bit-width into
consideration
and FSM
398
Ver 1.4
199
Agenda: Day Three
DAY
3
Unit Topic Lab
16 Refinement
17 Functional I/F
18 Hardware/Software Co-verification
399
Ver 1.4
ASIC
Data µP
DSP
Random 5000
Shift in Design Method
µP DSP ASIC
Path Logic
Program
Data- 4500
RAM
Ram memory FPGA path ROM
4000
3500 Annual Revenue
3000
2500
2000
1500
1000
500
0
1991 19921993 19941995 1996 19971998 19992000
ASIC * Source: IBS
ASSP/Custom
On-Chip System
400
Ver 1.4
200
Systems Require Multiple IP Sources
Cisco
Micron AMD SUN
Cisco
AMD SUN
NEC
NEC
Motorola
ASIC
401
Ver 1.4
• System performance
• Component interaction
• HW / SW debug
ASIC
402
Ver 1.4
201
Verification Becomes the Challenge
403
Ver 1.4
Must-Have:
Hardware Architecture
❏ Common verification environment Design (RTL)
404
Ver 1.4
202
Designing with Pre-verified Blocks
• Functionally verified
• Abstracted timing
• Accurately modeled
• Protected IP
• Transportable at physical level
405
Ver 1.4
Classes of Verification
Specification Validation
Validate this is what I want to build
Specification Remove ambiguity from spec
Validation
Fast
Functional High performance Functional Verification
Simulation Verify that the implementation captures the
desired functionality
Implementation
Verification
Implementation Verification
Physical Verify final design equals the
Verification RTL golden spec
Streamlined paths to signoff
406
Ver 1.4
203
Cycle-Accurate Verification Using SystemC
407
Ver 1.4
IP Challenges
Authoring Protecting
the IP? the IP?
Integrating
the IP?
Evaluating
the IP?
Implementing
the IP? Delivering
the IP?
Configuring
the IP?
Validating
the IP?
408
Ver 1.4
204
IP Protection Problems?
409
Ver 1.4
410
Ver 1.4
205
Process1 - Functional I/F
Function f_process1
Takes exactly the same arguments as the constructor for
process1
Must have a return type of void
SC_NEW()
SystemCTM function
Creates process process1 and makes the process object
persistent
411
Ver 1.4
// Filename f_process1.h
// Functional interface file for process
process1
extern void f_process1 (const char *NAME,
sc_clock_edge& CLK,
const sc_signal<bool>& A,
const sc_signal<bool>& B,
sc_signal<bool>& C,
sc_signal<bool>& D) ;
extern declaration indicates
that the function is defined in
some other file.
412
Ver 1.4
206
Functional I/F & Functional Interface File
// Filename f_process2.h
// Functional interface file for process process2
extern void f_process2 (const char *NAME,
sc_clock_edge& CLK,
const sc_signal<bool>& E,
const sc_signal<bool>& F,
const sc_signal<bool>& G) ;
413
Ver 1.4
414
Ver 1.4
207
Example: Simple Arithmetic Pipeline Design - 1
Stage2.cc Stage3.cc display.cc
Stage1.cc numgen.cc
Stage2.h display.h
Stage1.h Stage3.h numgen.h
Stage1_2.h Testbench.h
Pipeline.h
main.cc
415
Ver 1.4
416
Ver 1.4
208
Example: Simple Arithmetic Pipeline Design - 3
Similarly for the process called stage2,3 and create a new function
417
Ver 1.4
/* Filename f_stage1.h */
/* This is the functional interface file for synchronous process `stage1' */
418
Ver 1.4
209
Example: Simple Arithmetic Pipeline Design - 5
Functional interface can be used in module declaration too.
Instantiation through
function calls can coexist
with instantiation through
variable definition
Note the module stage1_2 does not have a functional interface, therefore
S1_2 is declared as data member (line10). On the other hand, functional
interface for stage3 is used, so f_stage3 is called in line 21.
420
Ver 1.4
210
Example: Simple Arithmetic Pipeline Design - 7
Let use now use the functional interface f_pipeline in the
definition of the pipeline module
421
Ver 1.4
422
Ver 1.4
211
Lab 10: Simple FIR Filter IP
Primary Objectives:
understand SystemC’s functional Interface usage
your task is to update fir.cc and fir.h using functional interface
Background
• A simple FIR filter which reads in samples with each
input_valid signal and writing out the result when
output_data_ready is high.
•The filter is a 16 tap FIR filter(fir.cc).
•The test bench feeds simply ascending values into the
FIR(stimulus.cc) and the
•Output is sampled(display.cc) and displayed with print
statements.
423
Ver 1.4
Z −1 Z −1 .... Z −1
C1 C2 C N −1 CN
424
Ver 1.4
212
Lab 10: Simple FIR Filter IP
426
Ver 1.4
213
Summary
FunctionalI/F
covered Functional I/F which is useful for IP
exchange
427
Ver 1.4
16 Refinement
17 Functional I/F
18 Hardware/Software Co-verification
428
Ver 1.4
214
It is Silicon and Software!
✍
application-specific processor
µP
programmable DSP/µ
architecture exploration
µP code
DSP/µ handcrafted
behavioral synthesis generation µP code
DSP/µ
compilers
✍
✍
FSM generators
µP code integration
DSP/µ
logic synthesis
✍ µP
ROM-coded DSP/µ
standard cells FPGA
Log scale
1G 256M
64M
100 M
16M
P7
10 M 4M P6
IBM gate array
Pentium
1M Mitsubishi
gate array
1M 256K 80486TMS320C80
80386 68040
64K 68020 LSI Logic gate array
100 K 80286 TMS320C240 Memory (DRAM)
16K
68000
4K 8086 TMS320C30 Microprocessor/
10 K Logic
1K 8085 TMS320C15 DSP
8080
1K 4044
70 74 78 82 86 90 94 98
430
Ver 1.4
215
Algorithms
An algorithm is a sequence of computational steps that
transform the input into the output
Demodulation, Parameter Estimation,
& Symbol Detection
Modulation &
Pulse-shaping Source Coding
Channel Coding &
Interleaving
431
Ver 1.4
HARDWARE/SOFTWARE CO-VERIFICATION
Hardware
Window Is the ASIC
hardware working
correctly with the
µp Controller or
µP?
Is the application
software working
Software correctly with the
Window ASIC hardware?
432
Ver 1.4
216
C/C++ Based HW/SW Co-Design Motivations
433
Ver 1.4
Functional Specification
validate algorithm and functionality
processes can be mapped to SW or HW
no timing
Architectural specification
processes are mapped to specific HW blocks (e.g. processor,
memory, DSP…)
test interfaces: e.g. memory map, interrupts…
bus functional model (BFM) for processors
abstract behavioral model for hardware
timing: e.g. number of cycles, buffer size
use BFM + ISS (instruction set simulator) for proccessors
refined RTL description for hardware
434
Ver 1.4
217
Architectural Level: Untimed
Bus Functional model (BFM)
model transactions on processor bus
untimed software execution
Software Hardware
435
Ver 1.4
Software Hardware
436
Ver 1.4
218
Speeding up Simulation
Reduce activity on memory bus
95% of traffic on memory, bus comes from instructions and data transfer
bus functional model (BFM) integration after testing memory interface
instruction memory
part of data memory ( definition of memory map)
turn off clocks on modules
bus functional model (BFM) generate clock signal on when devices
are “active”.
BFM
Memory Bus
Controller
Clock
437
Ver 1.4
Hardware/software partition
Hardware/software partition / co-verification
e.g. implement FFT in software and run it through ISS and
compare result with FFT hardware model
then determine whether to implement FFT in software or
hardware
co-verify each other for accuracy
ISS
Memory Bus
CPUCore
Clock
438
Ver 1.4
219
Types of Simulation Models
Hardware
models
Full Functional Hardware Modeler
models
Model Vendor
Model Vendor
User Defined
439
Ver 1.4
uP
System
440
Ver 1.4
220
Bus Functional Models
User
ASIC
441
Ver 1.4
User
ASIC
442
Ver 1.4
221
Hardware Models
Device
486
486
K62
Ethernet
Timing Workstation running
Files Device(s) LM-family hardware simulator
mounted on model server
an adapter
443
Ver 1.4
Software Models
444
Ver 1.4
222
Hardware/software Co-design
Software
Hardware
RTOS
C/C++ CPU
SystemC Bus
memory
VHDL
Verilog
SystemC
ASM
OMI
C/C++
445
Ver 1.4
Summary
446
Ver 1.4
223
Agenda: Day Three
DAY
3
Unit Topic Lab
19 System-on-a-Chip
20 Workshop Summary
447
Ver 1.4
SOC
Standard
Memory
µp
Graphic New
Chip Set Subsystem Block
Reused
Block
Comm. Multimedia
Subsystem Subsystem
Host
Processor
448
Ver 1.4
224
System Design Market Forces
Semiconductor
Technology
Market Needs
Systems Systems
on Boards on Chips
449
Ver 1.4
Semiconductor
ROI Concerns
IP Protection &
Ownership Issues
Design Transportability
Systems Systems
on Boards on Chips
450
Ver 1.4
225
What is Inside a Module?
degree of
uP/DSPD/A RAM
resource
core A/D
uP core
sharing P->S ROM
S->P
bus based
multiplexer-based ALU
register
operation
pipeline proc/ multiplexor
parallel HW
452
Ver 1.4
226
HW/SW/Time/Cost
Effect of HW Resource Constraints on HW/SW System Prototyping Costs
454
Ver 1.4
227
New SoC Design Flows
C, C++, Fortran
Algorithm
Design
Design
HARDWARE Partitioning SOFTWARE
Hardware Software
Behavioral HDL,
RTL HDL VHDL, Verilog, assembly C, assembly-code
C++ with SystemC code
DSP processor
behavioral models
Hardware Models
455
Ver 1.4
2000
SILICON INVERSION
begin
Err <= HiAddr xor LoAddr;
process begin
1980 wait until CLOCK'event
and CLOCK = '1';
Flag <= (Err = "0000000");
end process;
end;
1970
456
Ver 1.4
228
SystemC Solve the Verification Bottleneck
A/D
A/D DP
DP Memory
Memory
‘1’ ’0’
“001011”
D/A
D/A µPP Mega
Mega
‘1’ ’0’ S/P
S/P µCC Cells
Cells
“001011”
‘1’ ’0’ P/S
P/S
“001011” Control
Control Logic
Logic
DMA
DMA
Gate-level simulation
457
Ver 1.4
Verilog DES model event, real, int, inertial, concurrent, components timing &
(gate level) no, weak typing immediate, initial, always, functionality
high priority task, cont. assig
preemptive
VHDL DES model user defined preemptive sequential, components delayed
guarded assignments
Esterel Reactive int, bool, triv atomic nested actions modules perfect
models abstract reaction synchrony
SystemC Synch. HW/SW data next cycle Synchronized, Hierarchical Delayed
Syn, RTL types next delta cycle asynchronized wProcesses assignments
458
Ver 1.4
229
Integrated Design Flow for SOC with SystemC
FSM / Protocol COSSAP SystemC/
a=1 Verilog /
int int VHDL process begin
wait until not
a=0 CLOCK'stable
and CLOCK=1;
b super
if(ENABLE='1') then
TOGGLE<= not
TOGGLE;
459
Ver 1.4
460
Ver 1.4
230
Roles of Models in SOC Verification
SystemC Bus
Legacy Functional
Arb Models
Source
Standard Bus
Models CPU
Interface
RAM Bridge • Popular buses
Peripherals
Bus
Kit
• Fast,
Peripherals
On-Chip Bus
• Memory and programmable
Std Logic Local Bus device BFMs
• VHDL/Verilog • Link to
Source DMAC Instruction Set
uP
• Customizable uP STD Simulators
Core
Core PROD SmartModel
IP vendor BFM Library
Cmds On-Chip
DSP User
HW/SystemC Bus Kit • Binary, ASIC
Core Defined
Models Logic
vendor
• Full- System compliant
ISA Sim On-Chip
functional; Bus Kit Models • All popular HDL
“accurate as simulators.
the silicon!”
• Guarantee of System ASIC
availability System ASIC Testbench
• COSSAP models of
real-world. DSP-Specific
• Verify standards Models 461
Ver 1.4
RTL Simulation
Bus Functional Model Co-sim Test Extraction
462
Ver 1.4
231
Behavioral Modeling
Abstraction Levels
Characteristics
System • Interfaces between Major Models are mixed clock/event
driven
• Balance of design is event driven behavioral code
• Behaviorally accurate
Behavioral Purpose
• Integrated System Model
• Fastest simulating code
RTL Challenges
• Behavioral design is new: guidelines, models etc. are
scarce
Gate
Transistor
463
Ver 1.4
CPU
Clk
Event driven
driven Bus IF
Clk
Event driven I/O Board Disk
driven Bus IF
Clk Clk
driven Event driven Event
Memory Bus IF driven Bus IF driven
Clk
Bus driven
Arbiter Bus IF
464
Ver 1.4
232
Simple Example : System Code
System Level Code
Concise
Easy to write
Functionally accurate
index = 0;
...
while( index < 16 )
{
D_diff = data_A * data_B - data_C * data_D;
D_out = (D_diff + Accum);
} ...
465
Ver 1.4
Bus
State
Machine
In Out
Q Q Memory Event code for rest of module:
Event wait_until(in_q_not_empty);
Memory Control read_queue(in_q, data_reg, addr_reg);
233
Modeling Behavioral Building Blocks Overview
Determine the tasks, in order,
you wish to model
Concept
Basic Code
Write the code
467
Ver 1.4
Determine Tasks
Determine the tasks required to fulfill functionality Step 1
Indicate Ready
468
Ver 1.4
234
Behavioral Building Blocks
How is a task executed? Step 2
One-time execution
469
Ver 1.4
IF
Read RAM Wait for Send Output all data
Wait for
Begin Input End
Read Input Accumulate Update RAM
IF Indicate Ready
470
Ver 1.4
235
Write the Code
Begin
Loop
The Code Wait for Input
IF if
Falls naturally from the task Write to RAM
diagram Update Checksum
else if
Rotate the task diagram Read RAM
Write to RAM Update Checksum Wait for Send
IF Output all data
Read RAM Wait for Send Output all data
Wait for else if
Begin Input End
Read Input Accumulate Update RAM Read Input
IF Indicate Ready Accumulate
Process RAM Data Output Result Update Status IF if
Update RAM
else
Indicate Ready
end if
else
Process RAM Data
In 3 steps, we now have an Output Result
overview of a behavioral Update Status
description end if
End Loop
End
471
Ver 1.4
Specify a clock
index = 0;
...
//Read in the Sample values
Add Input and Output while( index < 16 )
ports accesses {
data_A = Port1.read;
data_B = Port2.read;
data_C = Port3.read;
data_D = Port4.read;
D_diff = data_A * data_B - data_C * data_D;
D_out.write(D_diff + Accum);
Add a clock
wait();
} ...
472
Ver 1.4
236
Coding in Behavioral Style and Tips - 1
473
Ver 1.4
Gate
think about latency impact; using
memories means latency(wait statements)
internal bit width have to be adjusted so
Transistor that the error rate is not violated
474
Ver 1.4
237
Coding in Behavioral Style and Tips - 3
475
Ver 1.4
Gate
Transistor
476
Ver 1.4
238
RTL Architecture
Control FSM
RTL Architecture
Ext
Logic
State
Optional
Data
input
0000 0110110010110101
1000 0111100001010101
0100 0011111010101011
input 1100 0010101011111001
0010 1101010111010101
1010 0000000011010101
0110 0111111110010111
CLK
output
Memory
Datapath
477
Ver 1.4
Abstraction Levels
Characteristics
System
• Fully clock driven RTL code with some behavioral
constructs
• Contains complete functional description
Behavioral • Cycle accurate
Purpose
• Input for Synthesis tools
RTL • Validation model for structural code
• Full functionality
Challenges
• Textual entry
Gate
• Synthesis coding style
Transistor
478
Ver 1.4
239
RTL Level Modeling - 2
Abstraction Levels
At the RT Level, language issues blur somewhat:
System Are we modeling a design for simulation?
Are we describing the design to a synthesis tool?
Gate
Transistor
479
Ver 1.4
+
if (index < 16) { data_A = Port1.read;
index++; data_B = Port2.read;
enable = true; data_C = Port3.read;
} else { data_D = Port4.read;
index = 0; D_diff = data_A * data_B - data_C * data_D;
enable = false; D_out.write(D_diff + Accum);
} }
} }
} }
480
Ver 1.4
240
Gate Level Modeling
Abstraction Levels
Characteristics
System
• Fully clock driven Structural code (gate level)
• ASIC's, PLD's, Glue logic
• Synthesized representation
Behavioral • Schematic representation
Purpose
• Representation for Physical design
RTL Challenges
• More simulator events, so slower simulation
Gate
Transistor
481
Ver 1.4
482
Ver 1.4
241
Methodology Note
483
Ver 1.4
Summary
System-on-a-Chip
covered issues involving System Level Design
484
Ver 1.4
242
Lab 11: RSA Public-Key Crypto-System -1
Primary Objectives:
understand SystemC’s role in Software development
understand the use of sc_biguint<> and sc_bigint<>
Background
RSA is a public-key cryptosystem that can be used to encrypt message sent
between 2 communicating parties
RSA also enable “digital signature” to the end of the electronic message
which is the electronic version of a handwritten signature on a paper document
It is based on the dramatic difference between the ease of finding large prime
numbers and the difficulty of factoring the product of 2 large prime numbers.
485
Ver 1.4
486
Ver 1.4
243
Lab 11: RSA Public-Key Crypto-System -3
Lab Assignment:
Learn how to write a software model using sc_bigint<> and
sc_biguint<>
CLK1
487
Ver 1.4
488
Ver 1.4
244
Agenda: Day Three
DAY
3
Unit Topic Lab
19 System-on-a-Chip
20 Workshop Summary
489
Ver 1.4
Application Architecture
• Using C/C++
• Using C/C++
490
Ver 1.4
245
The Open SystemC™ Initiative (OSCI)
Launched on 9/27/99
Technical collaborators:
CoWare
Frontier Design
ARM
Endorsed by over 55 systems(dated
09/27/1999),
semiconductor
IP
embedded software and EDA companies
491
Ver 1.4
µC core
S/P control protocol
demod
Logic
A digital
and Viterbi
Analog SH
D
downconv
sync Eqls.
SAW FILTER
speech
voice
quality
recognition
enhancement
RF 900Mhz
70Mhz IF 10.7Mhz 40Ms/sec - 540ks/sec
DSP core
de-intl RPE-LTP
270.8ks/sec BB & speech
decoder decoder
High-speed
datapath compiler Behavioral
Compiler COSSAP
492
Ver 1.4
246
System Level Co-Design Continuum
+ a.out
2) "I have an IP core, and I want to test whether my algorithm fits with it or not, but I don't want to spend 4
months writing the RTL code and then find out that it doesn’t. Is there a faster way to prove to my
management that my algorithm is worth using?" This is fast proof of concept problem.
3) "I found out that there is a bug in my chip after tape-out, I have an idea how to fix it, but I want to verify it
first before asking the RTL designer to change the code?" This is a verification problem.
4) "I want to improve my chip's performance, but I don't want to write the whole RTL. I just want to do some
experiments to explore the performance improvement. What should I do?" This is architectural exploration
problem.
5) "We got a CPU C model from company X, and we would like to add other designs to it as a System on a
Chip. But our company's C model language is different from their's. We are all using our company's
internal proprietary language. Is there a way out?" This is a IP problem.
6) "We wanted to move to C++ modeling, but many architects and designers are still not comfortable
programming in C++. They are very good at C. Is there a C++ modeling language that is easy to use for C
programmers?" This is a programming problem.
247
Summary for Day Three
Day Three
covered global and local watching
covered hardware modeling especially bus
modeling
covered refinement for more details
covered functional I/F
covered hardware/software co-verification
briefly covered system-on-a-chip
495
Ver 1.4
Connecting Designers
HW/SW
496
Ver 1.4
248
SystemCTM Community
http://www.systemc.org
497
Ver 1.4
TTM Complexity
Synthesize?
Test?
Simulate?
Floorplan?
???
498
Ver 1.4
249
Synopsys can HELP you SUCCEED!
DESIGN CYCLE
System-Level
Debugging
Software Development
C
R
I T
T I Customer Feedback Loop
I M
C E
A
L
Customer Response Product Presentation
Product Sale
Appendix A - Tracing
250
Appendix A: Tracing - 1
Each tracing function has additional arguments that specify how the
variable is traced.
All have default so only need to specify the first 3 arguments
501
Ver 1.4
Appendix A: Tracing - 2
Tracing functions:
// For tracing unsigned char
void sc_trace(sc_trace_file *tf, const unsigned char& v,
const sc_string& NAME,
const int width = 8 * sizeof(char));
// For tracing unsigned short
void sc_trace(sc_trace_file *tf, const unsigned short& v,
const sc_string& NAME,
const int width = 8 * sizeof(short));
// For tracing unsigned long
void sc_trace(sc_trace_file *tf, const unsigned long& v,
const sc_string& NAME,
const int width = 8 * sizeof(long));
// For tracing unsigned int
void sc_trace(sc_trace_file *tf, const unsigned int & v,
const sc_string& NAME,
const int width = 8 * sizeof(int));
502
Ver 1.4
251
Appendix A: Tracing - 3
Tracing functions:
// For tracing char
void sc_trace(sc_trace_file *tf, const char& v,
const sc_string& NAME,
const int width = 8 * sizeof(char));
// For tracing short
void sc_trace(sc_trace_file *tf, const short& v,
const sc_string& NAME,
const int width = 8 * sizeof(short));
// For tracing long
void sc_trace(sc_trace_file *tf, const long& v,
const sc_string& NAME,
const int width = 8 * sizeof(long));
// For tracing int
void sc_trace(sc_trace_file *tf, const int & v,
const sc_string& NAME,
const int width = 8 * sizeof(int));
// For tracing float
void sc_trace(sc_trace_file *tf, const float& v,
const sc_string& NAME);
503
Ver 1.4
Appendix A: Tracing - 4
Tracing functions:
// For tracing double
void sc_trace(sc_trace_file *tf, const double& v,
const sc_string& NAME);
// For tracing bool
void sc_trace(sc_trace_file *tf, const bool& v, const sc_string& NAME);
// For tracing sc_logic
void sc_trace(sc_trace_file *tf, const sc_logic& v,
const sc_string& NAME);
252
Appendix A: Tracing - 5
Tracing functions:
// For tracing sc_signal<int>
void sc_trace(sc_trace_file *tf, const sc_signal<int>& v,
const sc_string& NAME, const int width);
// For tracing sc_signal<long>
void sc_trace(sc_trace_file *tf, const sc_signal<long>& v,
const sc_string& NAME, const int width);
// For tracing sc_signal<short>
void sc_trace(sc_trace_file *tf, const sc_signal<short>& v,
const sc_string& NAME, const int width);
// For tracing sc_signal<char>
void sc_trace(sc_trace_file *tf, const sc_signal<char>& v,
const sc_string& NAME, const int width);
505
Ver 1.4
253
Appendix A: Tracing aggregate type
Given:
struct bus {
unsigned address;
bool read_write;
unsigned data;
507
Ver 1.4
508
Ver 1.4
254
Appendix A: Tracing Variable, signal & channel
arrays - 2
Tracing function example for sc_signal_array<sc_array<int> > :
void sc_trace(sc_trace_file *tf,
const sc_signal_array<sc_array<int> >& v,
const sc_string& NAME, const int width = 8 * sizeof(int))
{
char stbuf[20];
for (int i = 0; i< v.length(); i++) {
sprintf(stbuf, "[%d]", i);
sc_trace(tf, v[i], NAME + stbuf, width);
}
}
509
Ver 1.4
510
Ver 1.4
255
Appendix B
Data Types
Signed Binary
n −2
V = −bn −1 2 n −1 + ∑ bi 2 i
i =0
512
Ver 1.4
256
Redundant Binary Number Systems
Binary
base is “2” and magnitudes are 20,21,22,23, ……
more than one bit per position
V beyond 0,1 (base is still “2”)
example example
00 0 00 0
01 +1 01 +1
10 0 10 +1
11 -1 11 +2
513
Ver 1.4
257
Appendix B: sc_int, sc_uint Operators - 1
Examples:
sc_int<5> a;
a = 13; // a gets 01101, a[4] = 0, a[3] = 1, …, a[0] = 1
bool b;
b = a[4]; // b gets 0
b = a[3]; // b gets 1
b = a[0]; // b gets 1
sc_int<3> c;
c = a.range(1, 3); // c gets 011 - interpreted as 3
515
Ver 1.4
258
Appendix B: sc_int, sc_uint Operators - 3
Example:
signed char a = -1;
sc_uint b(16), c(16);
b = 5;
c = b + a; // a gets promoted to sc_uint of width 16 and
// gets value 255. Therefore the value of c is 260 and not 4.
517
Ver 1.4
Examples:
unsigned char a = 2;
sc_int<8> b;
sc_int<9> c;
b = 4;
c = b + a; // a gets promoted to sc_int of width 8 and
// gets value 2. Therefore the value of c is 6.
518
Ver 1.4
259
Appendix B: sc_int, sc_uint Operators - 5
519
Ver 1.4
520
Ver 1.4
260
Appendix B: sc_int, sc_uint Type Conversions - 1
Examples:
sc_int<10> a;
sc_uint<10> b;
a = "d28"; // a gets decimal 28 or 0000011100
a = "d-28"; // a gets decimal -28 or 1111100100
b = "o32"; // b gets decimal 26 or 0000011010
b = "o-32"; // b gets decimal 998 or 1111100110
a = "xfff"; // a gets decimal -1 or 1111111111
a = "x-fff"; // a gets decimal 1 or 0000000001
b = "d-2048"; // b gets 0 521
Ver 1.4
LHS shorter
RHS left-most bits truncated
RHS shorter
LHS sc_int then RHS sign extended
LHS sc_uint then RHS zero extended
Examples: Examples:
sc_int<4> a; sc_int<4> a;
sc_int<6> b; sc_int<6> b;
sc_uint<4> x; sc_int<8> c;
sc_uint<6> y; sc_uint<4> m;
a = "1101"; // a gets -3 sc_uint<6> n;
b = "010011"; // b gets 19 sc_uint<8> p;
x = a; // x gets 1101 or 13 b = "101110"; // b gets -18
y = a; // y gets 001101 or 13 a = b; // a gets 1110 or -2
x = b; // x gets 0011 or 3 c = a; // c gets 1111111110 or -2
x = "0011" // x gets 3 n = "100011"; // n gets 35
y = "100101"; // y gets 37 m = n; // m gets 0011 or 3
a = x; // a gets 0011 or 3 p = m; // p gets 0000000011 or 3
b = x; // b gets 000011 or 3
a = y; // a gets 0101 or 5 522
Ver 1.4
261
Appendix B: sc_int, sc_uint Type Conversions - 3
RHS (Cont.):
unsigned int
Assignment is right-aligned
RHS larger, left most bits truncated
RHS smaller, excess bits are assigned value of 0
Examples:
sc_int<4> a;
sc_uint<4> c;
unsigned int b = 6; // 110 in binary
sc_int<40> d;
d = b; // d gets 000…0110 (37 leading zeros)
a = b; // a gets 0110 or 6;
c = b; // c gets 0110 or 6;
b = 31; // 31 decimal = 11111
a = b; // a gets 1111 or -1
c = b; // c gets 1111 or 15
523
Ver 1.4
RHS (Cont.):
signed int
Assignment is right-aligned
RHS larger, left most bits truncated
RHS smaller, excess bits are assigned value of sign bit
Examples:
sc_int x(4);
sc_uint y(4);
int w = -7; // 111…1001 in binary (29 leading 1's)
sc_int<33> m;
sc_uint<33> n;
x = w; // x gets 1001 or -7
y = w; // y gets 1001 or 9
m = w; // m gets 111…1001 (30 leading 1's) = -7
n = w; // n gets 111…1001 (30 leading 1's) = 8589934585
w = -28; // -28 decimal = 11…100100
x = w; // x gets 0100 or 4
y = w; // y gets 0100 or 4
524
Ver 1.4
262
Appendix B: sc_int, sc_uint Type Conversions - 5
sc_logic operators:
& logical AND
| logical OR
^ logical exclusive OR
~ logical NOT
== equality
NOT X 0 1 Z
!= inequality
X 1 0 X
AND X 0 1 Z OR X 0 1 Z XOR X 0 1 Z
X X 0 X X X X X 1 X X X X X X
0 0 0 0 0 0 X 0 1 X 0 X 0 1 X
1 X 0 1 X 1 1 1 1 1 1 X 1 0 X
Z X 0 X X Z X X 1 X Z X X X X
526
Ver 1.4
263
Appendix B: sc_logic Operators - 2
Equality operators
when using the == or != operator, one of the
operands may be a character literal:
‘0’, ‘1’, ‘X’, or ‘z’
527
Ver 1.4
sc_logic a, b, c, d, f, g;
b = ’0’;
c = ’1’;
f = ’1’;
a = b & c; // a gets 0
d = a | f; // d gets 1
g = f ^ d; // g gets 0
a = ~g; // a gets 1
b |= a; // b gets 1
c ^= a; // c gets 0
if (a == b) // condition is true
d = f & (~a); // d gets 0;
if (a == ’X’) // condition is false
d = a & (~f); // not executed in this case 528
Ver 1.4
264
Appendix B: sc_logic Type Conversions
The assignment operator = is used to assign a value to a variable of
type sc_logic.
Example ( given sc_logic a,b; ):
a = b;
The RHS of the assignment operator may be of type:
sc_logic
bool
char
When the RHS is of type char, translation is from textual to logic
value.
Lower case letters are translated to their uppercase
counterparts
values other than ‘0’, ‘1’, ‘x’, ‘z’ translate to unknown (X)
Examples:
sc_bv<3> a;
sc_bv<3> b;
a[2] = true; a[1] = false; a[0] = true; // a = 101
b[2] = true; b[1] = true; b[0] = false; // b = 110
sc_bv<3> c;
c = a & b; // c gets 100, that is c[2] = 1, c[1] = 0, c[0] = 0
c = a | b; // c gets 111
c = a ^ b; // c gets 011
c = ~c; // c gets 100
a &= "110"; // a gets 100, that is a[2] &= 1, a[1] &= 0, a[0] &= 0
b |= "0010"; // b gets 110 - leftmost 0 on C-string ignored 530
Ver 1.4
265
Appendix B: sc_bv Operators - 2
sc_bv operators (cont.):
and_reduce(), or_reduce(), and xor_reduce()
logical reduction of all elements of the vector
==, !=
Bitwise comparison
Variables must be of same size
Examples:
sc_bv<3> a;
sc_bv<3> b;
b |= "0010"; // b gets 110 - leftmost 0 on C-string ignored
a &= "110"; // a gets 100, that is a[2] &= 1, a[1] &= 0, a[0] &= 0
bool d;
d = and_reduce(a); // d gets 0
d = or_reduce(b); // d gets 1
d = xor_reduce(b) & xor_reduce(a); // d gets 0
531
Ver 1.4
532
Ver 1.4
266
Appendix B: sc_lv Type Conversions - 2
RHS variable (Cont.):
unsigned int or sc_uint or sc_int (discussed later)
Assignment is right-aligned.
If number of bits on RHS is greater than LHS then left most
bits are truncated.
For sc_uint if number of bits on LHS is greater than RHS
then excess bits are assigned value of 0.
For sc_int if number of bits on LHS is greater than RHS
then excess bits are assigned value of the sign bit (sign
extend).
533
Ver 1.4
534
Ver 1.4
267
Appendix B: sc_lv Type Conversions - 4
535
Ver 1.4
Conversion (Cont.)
C++ String
to_string() method
returns a C++ string representation.
Usefull for printing out sc_lv value
Example:
sc_lv<10> a;
cout << a; //Prints the value of a using C++ iostream
printf("%s", a.to_string()); //Prints using C stdio
536
Ver 1.4
268
Appendix B: One Dimensional Arrays: sc_array
Syntax:
sc_array<type> array_name (length) ;
type:
Built in C++ type or class that has a default
constructor
length:
Specifies the number of elements in the array
Must be greater than 0
Must be compile time constant
Examples:
sc_array<int> a(10) ; // an array of 10 int’s
sc_array<bool> b(32) ; // an array of 32 bool’s
sc_array<sc_logic> c(4) ; // an array of 4 sc_logic’s
sc_array<double> d(5) ; // an array of 5 double’s
538
Ver 1.4
269
Appendix B: sc_array Operator
sc_array operator:
[ ] used to refer to a particular element
Index ranges from 0 to length - 1
539
Ver 1.4
Examples:
sc_array<int> a(3);
sc_array<int> b(3);
sc_array<int> c(4);
int d[3] = {0, 1, 2}; //d[2] = 2, d[1] = 1, d[0] = 0
int e[5] = {0, 1, 2, 3, 4}; //e[4] = 4, e[3] = 3, …, e[1] = 1, e[0] = 0
a = d; // O.K. a[2] = d[2], a[1] = d[1], a[0] = d[0]
b = a; // O.K. b[2] = a[2], b[1] = a[1], b[0] = a[0]
c = b; // Illegal - array lengths not the same!!
c = d; // Illegal - C++ array smaller than SystemCTM array
c = e; // O.K. c[3] = e[3], c[2] = e[2], c[1] = e[1], c[0] = e[0]
540
Ver 1.4
270
Appendix B: Two Dimensional Arrays - sc_2d
Collection of objects arranged into rows and columns.
Each row is considered a one-dimensional array
Column numbers
4 3 2 1 0
Row 0
Row 1
Row 2
541
Ver 1.4
Syntax:
sc_2d< array_type > 2d_array_name (row_num,
column_num ) ;
Examples:
sc_2d<sc_array<int> > a (3, 7); //note the space between <int> and >
// 3 rows, 7 columns
sc_2d<sc_int<32> > b (5, 10); // 5 rows, 10 columns
542
Ver 1.4
271
Appendix B: sc_2d Operators
sc_2d operators:
[ ] [ ] used to access an individual element
Example:
sc_2d<sc_bool_vector> a(10, 16);
sc_bool_vector c(16);
bool d;
c = a[0];
d = a[7][2];
543
Ver 1.4
Assignment example:
int init_array [] = {
//Column numbers
//0 1 2 3 4 5 6
1, 2, 3, 4, 5, 6, 7, //row 0
11, 12, 13, 14, 15, 16, 17, //row 1
111, 121, 131, 141, 151, 161, 171 //row 2
};
sc_2d<sc_array<int> > actual_array(3, 7,init_array);
// actual_array[0][0] = init_array[0] = 1
// actual_array[0][6] = init_array[6] = 7
// actual_array[1][2] = init_array[9] = 13
// actual_array[2][6] = init_array[20] = 171
544
Ver 1.4
272
Appendix C
Debugging
Tip:
To enable source-level debugging, compile
with the -g option in gcc
546
Ver 1.4
273
Appendix C: Debugging with SystemCTM - 2
547
Ver 1.4
548
Ver 1.4
274
Appendix C: Debugging with gdb
// Trace signals
sc_trace(tf, in_sig, "in_sig");
sc_trace(tf, out_sig, "out_sig");
}
Use a waveform viewing tool such as VSS for WIF waveform file,
wave (GTK wave) for VCD files, or Sim Wave for ISBD files.
550
Ver 1.4
275
Appendix TB
Testbench Issues
Testbench
ASIC 2 Memory ASIC 3
S
t Plug out the model
icro d Behavioral Model
essor P
a
of the ASIC
r
t
S S
t t
d d
552
Ver 1.4
276
Testbench issues
Terminology
Reset Interval
The number of cycles spent in the “reset” tail of a process for
initialization (Ex: initialize a RAM)
Handshake Interval
The number of cycles required by the handshake part of the algorithm
Functional latency
The number of cycles required to schedule the actual functionality
Initialization interval
The number of cycles between successive iterations of an algorithm
loop (including handshake, if any)
testbench Handshake
Interval Functional latency
Reset
Interval entity under test
Initialization output
interval rate
553
Ver 1.4
Testbench issues
Clock
Reset
Input
Output
Latency Handshake
Reset interval
Initialization Interval
554
Ver 1.4
277
Simulation
stimulus response
file file
555
Ver 1.4
data[31:0]
Block with
Fixed
Response ready_for_data
Time
clk
ready_for_data
556
Ver 1.4
278
Two Way Handshake; Respond to Ready
data[31:0]
Take
Block1 new_data Data
rdy4data Block
clk
rdy4data
new_data
557
Ver 1.4
C++
558
Ver 1.4
279
Using C functions in C++ code
Just use your C functions as if you were programming in C:
include header file, and then call the function.
In C++, this will compile without any problem:
#include "stdio.h"
#include "stdlib.h"
char buffer[1];
559
Ver 1.4
...
#ifdef __cplusplus
extern "C" {
#endif
/* C definitions */
#ifdef __cplusplus
}
#endif
...
Ths extern "C" just tells the compiler that following declaration is a
C based declaration. C definitions are after that usable like in C mode.
560
Ver 1.4
280
Function prototypes
You always need to prototype a function before using it. This prototype is defined by the type of the
returned value (or void if none), the name of the function, and the list of parameters' type.
Example: good:
void hello();
int about (int, char);
foo (int); // default return type is int
bad:
void hello();
...
void foo(){
hello (10);
}
this will generate the error: call to undetermined function hello (int) .
Just note that the name of a parameter in the prototype is not needed, only its type is. If the return type is
ommitted, int is used by default. You don't need to use a prototype in a source code if the function is called only
after its definition.
Example:
Overloading functions
The changes in the definition of functions also mean that two functions with the same name are allowed,
provided that their parameters' list is different. Just declare and use them as usual.
Example:
int foo (int a, int b){
return a * b;
}
But there are traps. You can define two functions this way:
int add (int a, int b);
float add (float a, float b);
and then make a call. This is very dangerous. But what about that?
Fortunately, the compiler will reject that, explaining it can't choose between the two foo functions. But be
careful! 562
Ver 1.4
281
Parameters default value
You can specify a default value for the last parameters of a function. If the parameter is omitted in the call,
the compiler will give it the default value.
Example:
int foo (int a, int b = 5);
...
int foo (int a, int b){
return a * b;
}
{
a = foo (2); // Same result as
a = foo (2, 5);
}
Note that it is only true for the last parameters, or the compiler would not know which parameter to
replace...
int func1 (int = 0, char); // Not allowed
void func2 (char, int = 0); // Ok
A default value must be specified in the prototype, and not necessary in the definition of the function. In
fact, you always implicitly define many functions. In the last example, foo (int) and foo (int, int) were
prototyped and implicitly defined. So combined with function overloading there can be forbidden things:
int foo (int a, int b = 5); // Definition with default value for b
int foo (float a); // Other definition
int foo (int a); // Error: conflict with the first one
563
Ver 1.4
Constant Definitions
To declare a variable constant, just add the word "const" before its definition.
When you declare a const variable in C++ files, you can give this variable a different value for each file. It
was not allowed by ANSI C, you had to declare this constant static.
Another difference with C is that C++ compiler calculates constant values when compiling. This means that
such things are now allowed:
564
Ver 1.4
282
Void pointers
In C++ mode, you cannot implicitly convert a void pointer (void *) to a pointer on another type. You
have to explicit it using a cast operator.
Example:
int *p_int;
void *p_void;
In a sense, a void pointer can point on anything, so you affect it any value. But an int pointer for example
can only point on an int value, so you can't affect it any value.
565
Ver 1.4
Inline functions
In C, it was not easy to define macro-functions. The use of the directive #define was not very simple. C++
provides a better way to handle macros.
If you declare a function "inline", then the code will be reproduced wherever you call the function. So you
need to define the code each time you call the function, in order it to be expanded properly. That's the
reason why the code is generaly put in the header file with the declaration.
Using inline functions will probably be more efficient, because most C++ compilers will first replace code,
and then optimise it. But the size of the code can increase dramatically. So it is recommended for small
functions (class constructors and operators are good examples).
Here is a code for those who don't see the difference between inline functions and a #define:
#define SQUARE (x) ((x) * (x))
int a = 2;
int b = SQUARE (a++);
// end: a = 4 and b = 2 * 3 = 6. Surprising ?!
283
References
You can now transmit parameters to a function by reference. It means that when you modify the parameter
inside the function, the variable transmitted will be modified too. To specify that a parameter is going to be
referenced, just put a & between the type and the name of the parameter:
You could compare that to pointers. But it is more powerful. The compiler will optimize it better. The code
is far more easy to write, just add a & to switch between value and reference.
567
Ver 1.4
Namespaces - 1
This concept is the answer to the common problem of multi-definition. Imagine you have two header files
describing two different types, but with the same name. How can you access both of them ?
The answer in C++ is namespaces. You can define types or functions in a namespace and use them
afterwards. Namespaces are defined using the namespace reserved word, followed by an identifier. But
let's have a look at an example...
namespace Geometry
{
struct Vector
{
float x, y;
};
In this example, what is inside the {} is usual C++ code. To use this code, you have to specify to the
compiler that you're going to use geometry namespace. There are two ways of doing this: by specifying
for a single variable its namespace (the syntax is namespace::variable) or by using the reserved
sequence of words using namespace.
568
Ver 1.4
284
Namespaces - 2
// With ::
void Foo1(){
Geometry::Vector v = (1.0, 2.0);
float f = Geometry::Norm (v);
}
// With using keyword
using namespace Geometry;
void Foo2(){
Vector v = (1.0, 2.0);
float f = Norm (v);
}
When you use using namespace sequence, you can get into trouble if many namespaces define the same
type. If there is any ambiguous code, the compiler won't compile it. For example...
namespace Geometry{
struct Vector { using namespace Geometry;
float x, y; using namespace Transport;
};
} void foo()
{
namespace Transport{ Vector v0; // Error ambiguous
struct Vector Geometry::Vector v1; // OK
{ Transport::Vector v2; // OK
float speed; }
};
} A last thing (obvious ?): you cannot use a namespace if it has not been defined...
569
Ver 1.4
The declaration of a class is really simple. The keyword class must be followed by the name of the class
and the declaration of internal variables and methods, as shown in example:
class Complex
{
float r, i;
public:
float GetRe();
float GetIm();
float Modulus();
};
Variables are declared the same way they are in classical C structs.
Functions are also declared as if they were prototypes.
Do not forget the final ";" or the compiler won't like it!
570
Ver 1.4
285
How to declare a class - 2
public is a keyword that indicates that GetRe, GetIm and Modulus functions may be called outside of the
object. There's no keyword before r and i, so they're declared private by default, and not accessible from
the outside.
When you declare a class with the reserved keyword class, every member is "private" by default. You
can also declare a class with the struct keyword, and every member will be "public" by default. That's
the only difference.
class Complex
{
float r, i; // Private by default
};
struct Complex
{
float r, i; // Public by default
};
571
Ver 1.4
Then you have to implement member functions. Just tell the compiler which class the function is part of by
puting the name of the class followed by :: before the name.
float Complex::Modulus()
{
return r*r + i*i; // Note the use of r and i
}
In those functions, you can use every variable or method of the object as if they were globally declared.
Look at the use of r and i to get the idea.
572
Ver 1.4
286
Instantiation of a class as variable
A class can be used like other types of variables. To declare an object belonging to a class, just put the
name of the class followed by the name of the object you want to create.
Complex x, y; // Declaration
Complex vector[10]; // Array of Complex
...
x = y; // Using declared objects
573
Ver 1.4
Dynamic allocation
Pointers on object are declared exactly like in C, with a "*". You can also get the address of an object
with "&".
The C++ call for the malloc() function is the operator new. It allocates the room in memory for an object
and returns a pointer to this area. To free the object, use the operator delete. Everything will be clear
after that:
Note the use of [] to tell the compiler that an array has to be deleted. If you do not specify this, you will
most of the time (depending on the compiler) only free the first object of the array, not the whole memory.
The effect of using delete [] with a single object is also undefined.
You can use new and delete operators anywhere in the code, just as malloc. Do not forget to free an
object when no longer used.
574
Ver 1.4
287
Using members of an object
Once you've declared a new object, you can access its public members as you would do with a C struct.
Just use . separator with a staticaly declared object, and -> with a dynamicaly declared object.
Class foo
{
int a; // private member
int Calc(); // private function
public:
int b;
int GetA();
};
575
Ver 1.4
The solution is the reserved keyword this. this is a pointer of type (object *), and it points on the
current object. It is an implicit member variable, declared as private. Example:
class A
{
int a, b;
public:
void Display();
};
void A::Display()
{
printf ("Object at [%p]: %d, %d.\n", this, a, b);
}
576
Ver 1.4
288
Constructors - 1
A constructor member of a class is a function called when the object is declared or dynamicaly allocated.
Its name must be the same as the class, but there can be many different overloaded constructors, provided
that their list of parameters is different. A constructor has no return value (not even void), it must be left
blank. It cannot be declared static.
Example:
class Complex
{
float i, r;
public:
Complex(); // First simple constructor
Complex (float, float); // Second overloaded constructor
};
Complex::Complex()
{
i = 0;
r = 0;
}
Complex::Complex (float ii, float rr)
{
i = ii;
r = rr;
}
577
Ver 1.4
Constructors - 2
But how can you call a constructor? This depends whether you use the "new" operator or not. Without
"new":
Just place parameters after the name of the variable, and the corresponding constructor will be called.
With the "new" operator, it becomes:
Allocates memory on the stack (static allocation) or on the heap (dynamic allocation).
Initializes the object (copy virtual functions, see inheritance).
Calls the constructor with the right parameters.
If objects are declared outside of any function as global variables, their constructor is called before the
function "main" starts. There are two particular constructors (default and copy) which are described below.
578
Ver 1.4
289
Destructor
After the definition of a constructor, the use of a destructor is obvious: it is called when the object is freed.
Its name is the name of the class preceded by ~. It has no return value (not even void). It takes no
parameters, since the programmer never needs to call it directly.
With a static object, you can not determine when the destructor will be called, because C++ rules don't indicate it.
\You only know that it will theoricaly be called. 579
Ver 1.4
class Complex{
public:
Complex (float, float); // A single constructor is declared
};
After this, the only way to construct a Complex object is to give 2 parameters to the constructor.
With arrays of objects, you should give the arguments for each constructor. That's the reason why an array
can only be declared if the object has a constructor taking no argument, or one argument, but not more,
because of the syntax:
class Complex{
public:
Complex (float = 0, float = 0);
};
290
Copy Constructor - 1
The copy constructor is the other default constructor. It only takes a reference to another object of the
same class as argument. When no copy constructor is declared, a default one only copies each field of the
source object to the destination object. If you declare one, you will have to copy all the fields you want
manually. Note the use of the keyword "const", needed for the compiler to recognize a copy constructor.
class Vector
{
int n;
float *v;
public:
Vector();
Vector (const Vector &);
};
Vector::Vector()
{
v = new float[100];
n = 100;
}
Vector::Vector (const Vector &vector)
{
n = vector.n; // Copy of field n
v = new float[100]; // Create a new array
for (int i = 0; i < 99; i++)
v[i] = vector.v[i]; // Copy array
}
581
Ver 1.4
Copy Constructor - 2
Copy constructor are needed if you make memory allocation inside of an object. This way, you can not
only copy the pointer, but really alloc a part of memory with values that can be different.
This copy constructor is called whenever you declare an object of a class and you assign it a value in the
same instruction.
You can also use the copy constructor with basic types, as int or char:
582
Ver 1.4
291
Including objects in other objects - 1
In this part, the situation is simple. You want to include a class as member of another. The declaration is
quite simple:
class A
{
int a;
public:
A (int);
};
class B
{
int b;
A a_element;
public:
B (int, int);
};
In this example, you include an object of class A in an object of class B. The interesting part is what
happens when you call B constructor. After memory is allocated, the constructor for each object included
is called, and after that the constructor of the child object. Which A constructor will be called (if there are
many), and how to specify it? When you define the B constructor, you must specify which A constructor
will be called, and with which arguments. This looks like:
583
Ver 1.4
Note the use of ":" before the call to A constructor. If many constructors are to be called, just separate
their call with a comma (see below). Another simple way to do this is to use constructors of basic types:
When the default copy constructor for the object containing other objects is called, it will implicitly call the
copy constructor of each object contained. When you overload it, you should call yourself the copy
constructor of each contained object.
584
Ver 1.4
292
Friend Functions
You can't make any access to private members of a class from the outside of the class. But sometimes you
need to. For example, a callback function has a predefined header, and can't be a member of any class. In
those case, you can declare the function as "friend" of the class. You will then be able to access any private
member without error. Let's have a look at an example:
class A{
int a;
public:
A (int aa) : a (aa) {} // Constructor initializing a
friend void foo();
};
void foo()
{ A a_obj (5); // Normal call
a_obj.a = 10; // Wouldn't be allowed in a non-friend function
}
You can place your friend declarations anywhere in the class definition, because a friend function has
nothing to do with public or private. Note that it is the class that chooses which functions will have access
to its private members. After such a declaration, no other prototype is needed for the function.
Friend functions are often used for redefining operators. A friend function cannot access the this pointer.
You can also use a member function of another class as a friend function of a class.
Friend classes - 1
As you did for functions, you can declare friend classes. This is rather simple:
class A
{
int a;
friend class B;
};
class B
{
public:
void foo();
};
B::foo()
{
A a_obj;
a_obj.a = 10; // Not allowed without being friend
}
Also note that this is class A that chooses which classes are allowed to access its private members.
586
Ver 1.4
293
Friend classes - 2
Another consequence of this is that friend classes of friend classes of a class are not friend classes. Let's
look at an example:
class A
{
int a;
friend class B;
};
class B
{
int b;
friend class C;
};
class C
{
int c;
int foo()
{
B b_obj;
b_obj.b = 10; // OK
A a_obj;
a_obj.a = 10; // Refused by compiler. It would have needed
} // a friend class C declaration in A.
};
587
Ver 1.4
Static variables
To declare a static variable, just add static keyword before. After that, a definition in a code file is also
needed. Every instance of the class will reference the same variable.
// A.h
class A
{
static int number;
public:
A() { number++; }
~A() { number--; }
};
// A.C
#include "A.h"
int A::number = 0;
In this example, the internal variable number is used to count the number of objects from class A in
memory. The same protection rules apply. A private member can only be initialized, and public variables
can also be modified.
588
Ver 1.4
294
Static functions
Static functions exist and can be called without any instanciation of the class. Therefore, they can only
modify static members. To declare a static function, just put the keyword static before its declaration.
class A
{
static int number;
public:
A() { number++; }
~A() { number--; }
static int GetNumber();
};
int A::GetNumber()
{
return number;
}
You can then normally call a static function, using an object. But you can also call it without any object.
Just put the name of the class followed by a "::" and the name of the function:
A a_obj;
n = a_obj.GetNumber(); // Normal call
n = A::GetNumber(); // Does not need any object
589
Ver 1.4
Constant functions
Constant functions are member functions of a class that do not modify internal values of variables. They
can therefore be called on a const object. To declare them, just put "const" keyword after the declaration
and the definition of the function:
#include
class A
{
int a;
public:
A (int aa = 1) { a = aa; }
void Display() const;
};
void A::Display() const
{
printf ("%d", a);
}
const A a_obj (2);
int main (int, char **)
{
a_obj.Display(); // Would not be allowed if Display weren't const
}
590
Ver 1.4
295
Class inheritance - 1
Inheritance is a mechanism that allows a class to reproduce every member of a father-class, adding and
modifying things according to its functionnality.
When you want to use every member of a father class without having to declare each one, just declare it in
the header:
class father
{
public:
int a;
};
In this example, the class A will have one public member b, as usual. But as it is declared as son of the
class father, it will also have an implicit member a.
When a class inherits from another, it gets every member of it. This leads to two problems: how will a class
protect its members for its potential sons not to access it, and how can a son class forbid the outside world
access to the part inherited from its father.
591
Ver 1.4
Class inheritance - 2
A class can declare members public. This way, everyone can access them. This is not a object oriented
programmation concept. It is good for debugging for example, but don't use it too much. Instead, use inline
member functions (accessors) which return the value of components, if needed. You then make the
variable read-only in a clean way.
class A{
int a;
public:
int GetA() { return a; }
}
On the contrary, you can declare every member private. No one will be able to use them. This is good
object oriented programming. But you may want that only children of a class be allowed to access some members.
Therefore, there will be no way to access those members from the outside, but inside, everything will be allowed.
class father{
protected:
int a;
};
296
Private, protected or public inheritance - 1
A child of a class can choose what to do of public members of its father. It can keep them public, totally
respecting its father's wishes. Just add word public between ":" and the name of the father class:
class father
{
public:
int a;
};
A son class can also protect the member it inherited from its father, thinking its father is now internal. The
inheritence must then be declared protected (all father's public members will become protected) or private
(public members will become private). The only difference between those two is for children of the child
class.
593
Ver 1.4
Note that you can omit the keyword public, protected or private. It will then be private by
default.
594
Ver 1.4
297
Constructors and destructor
As for member objects, you have to transmit parameters to the constructor of the father class, and it is
called before the construction of the child.
class Father
{
int a;
public:
Father (int aa) { a = aa; }
};
595
Ver 1.4
class Father{
public:
void MakeAThing();
};
class Child : public Father{
public:
void MakeAThing();
};
...
{
Father father;
father.MakeAThing(); // Father's method MakeAThing called
Child child;
child.MakeAThing(); // Child's method MakeAThing called
}
In the new version of the function, you may want to call the father's version of the function, or even a global
function with the same name. That is possible using :: and the name of the class you want to be called.
void MakeAThing();
class Father{
{
public: Father father;
void MakeAThing(); father.MakeAThing(); // Father's method MakeAThing called
};
class Child : public Father{ Child child;
public: child.MakeAThing(); // Child's method MakeAThing called
void MakeAThing() {
Father::MakeAThing(); // Father's method called
MakeAThing(); // Global function called
::MakeAThing(); // Global function called }
}
};
596
Ver 1.4
298
Polymorphism
The main advantage of this is that a child class can always replace its father as argument of a function for
example. The child can be seen as a class with two (or more) identities.
class Father
{
...
};
class Child : public Father
{
...
};
...
void ExampleFunction (Father &);
...
{
Father father;
ExampleFunction (father); // Normal call
Child child;
ExampleFunction (child); // child is considered as a father
}
This is possible with objects, objects' pointers and references. You can then improve a class, and also use
every characteristic and functionnality of its father. This is the main source of success of object oriented
programming.
597
Ver 1.4
Output Streams
The type of an output stream is ostream. For standard types, the operator << is redefined:
stream << "Time is" << hour << ":" << minute << ":" << second;
Standard streams are cout for standard output, cerr for standard error with buffer, and clog for
non-buffered standard error. For example, to write hour, just type:
cout << "Time is" << hour << ":" << minute << ":" << second;
Another way to write into streams is to use the member function put. It is declared as:
and it is a member function of ofstream. You can use it in a very simple way:
598
Ver 1.4
299
Input Streams
{
int hh;
int mm;
cin >> hh >> mm; // get two ints from standard input
}
You can also use the get member function to get a char or a set of chars:
599
Ver 1.4
class Example{
friend operator << (ostream &st, Example &ex);
friend operator >> (ostream &st, Example &ex);
};
class Complex{
float r, i;
300
Connecting a stream to a file - 1
When you want to connect a stream to file, you use fstream, ifstream and ofstream as basic classes.
Constructors look like:
where filename is the name of the file and mode an enumarated type. This enum is declared is the class
ios, and can take the value:
601
Ver 1.4
#include <iostream.h>
#include <fstream.h>
#include <libc.h>
char c;
while (source.get(c))
dest.put (c);
if (!source.eof() || dest.bad())
Fatal ("Reading or writing error.");
} 602
Ver 1.4
301
Declaring an exception handler - 1
This is a powerful way of handling every error occuring in a program in a simple way. You declare an
exception in a class using the keyword class:
throw exception_name();
In C++, you try executing a piece of code, and catch every exception that can occur during the
execution:
try
{
// code
}
catch (class_name::exception_1)
{
// handling of exception
}
603
Ver 1.4
302
Lab Solutions
Appendix : Solution
Lab Solutions
605
Ver 1.4
606
Ver 1.4
303
Sample Solution Lab 2 - stage2.h and stage2.cc
// stage2.h // stage2.cc
/* Filename stage2.h */ /* Filename stage2.cc */
/* This is the interface file for synchronous /* This is the implementation file for
process `stage2' */ synchronous process `stage2' */
//Constructor a = 20.0;
stage2(const char *NAME) b = 5.0;
: sc_module (NAME) { while (true) {
sc_sync_tprocess(handle1, "STAGE2", prod.write(a*b);
stage2, entry, CLK.pos()); quot.write(a/b);
end_module(); wait();
} a = sum.read();
b = diff.read();
// Process functionality in member }
function below } // end of entry function
void entry();
};
607
Ver 1.4
304
Sample Solution Lab 2 -main.cc
//main.cc //main.cc
#include "systemc.h" S1 << in1 << in2 << sum << diff << clk;
#include "stage1.h" stage2 S2("Stage2");
#include "stage2.h" S2 << sum << diff << prod << quot << clk;
#include "stage3.h" stage3 S3("Stage3");
#include "display.h" S3 << prod << quot << powr << clk;
#include "numgen.h"
display D("Display");
int sc_main(int ac, char *av[]) D << powr << clk;
{
sc_signal<double> in1; sc_start(1000);
sc_signal<double> in2; return 0;
sc_signal<double> sum;
}
sc_signal<double> diff;
sc_signal<double> prod;
sc_signal<double> quot;
sc_signal<double> powr;
numgen N("STIMULUS");
N << in1 << in2 << clk;
stage1 S1("Stage1");
609
Ver 1.4
void entry();
};
610
Ver 1.4
305
Sample Solution Lab 3 - mem_control.cpp
// mem_control.cpp default:
#include <iostream.h> next_state = IDLE; case WRITE_BLOCK5:
#include "systemc.h" break; wd_wen.write(true);
#include "fsm_types.h" } // end case inca.write(true);
#include "mem_control.h" break; next_state = IDLE;
case READ_WORD: break;
void mem_control::entry(){ a_wen.write(true); case READ_BLOCK:
sc_uint<8> cmd; next_state = READ_WORD2; a_wen.write(true);
tstate = state; break; next_state = READ_BLOCK2;
a_wen.write(false); case READ_WORD2: break;
rd_wen.write(false); rd_wen.write(true); case READ_BLOCK2:
wd_wen.write(false); next_state = IDLE; rd_wen.write(true);
inca.write(false); break; inca.write(true);
case WRITE_WORD: next_state = READ_BLOCK3;
if (reset) a_wen.write(true); break;
next_state = IDLE; next_state = WRITE_WORD2; case READ_BLOCK3:
else { break; rd_wen.write(true);
switch(state.read()) case WRITE_WORD2: inca.write(true);
{ wd_wen.write(true); next_state = READ_BLOCK4;
case IDLE: next_state = IDLE; break;
cmd = opcode.read(); break; case READ_BLOCK4:
switch (cmd) case WRITE_BLOCK: rd_wen.write(true);
{ a_wen.write(true); inca.write(true);
case NOP: next_state = WRITE_BLOCK2; next_state = READ_BLOCK5;
next_state = IDLE; break; break;
break; case WRITE_BLOCK2: case READ_BLOCK5:
case RDWD: wd_wen.write(true); rd_wen.write(true);
next_state = READ_WORD; next_state = WRITE_BLOCK3; next_state = IDLE;
break; break; break;
case WTWD: case WRITE_BLOCK3: } // end case
next_state = WRITE_WORD; wd_wen.write(true); } // end if
break; inca.write(true);
case WTBLK: next_state = WRITE_BLOCK4; }
next_state = WRITE_BLOCK; break;
break; case WRITE_BLOCK4:
case RDBLK: wd_wen.write(true);
next_state = READ_BLOCK; inca.write(true);
break; next_state = WRITE_BLOCK5;
break; 611
Ver 1.4
end_module();
}
// Process functionality
void entry();
};
612
Ver 1.4
306
Sample Solution Lab 3 - sram.cpp
// sram.cpp
else
#include <iostream.h>
{
#include "systemc.h"
if (rd) // Read
#include "sram.h"
{
address = addr.read();
/* * Reg - functionality */
/* cout << sc_clock::time_stamp() << " " <<
"MEM: Reading " << memory[address] << " from
void sram::entry()
address " << address << endl;
{
*/
int i = 0;
data_tmp = memory[address];
sc_uint<8> address;
data.write(data_tmp);
sc_bool_vector data_tmp(8);
} else
data.write("ZZZZZZZZ");
// Reset behavior
if (wr) // Write
{
if (reset)
address = addr.read();
{
/* cout << sc_clock::time_stamp() << " " <<
for (i = 0; i < depth; i++) memory[i] = 0;
"MEM: Writing " << data << " to address " <<
data.write("ZZZZZZZZ");
address << endl; */
}
memory[address] = data;
}
if (rd && wr)
}
cout << "Can't read and write at the same time!!"
}
<< endl;
613
Ver 1.4
614
Ver 1.4
307
Sample Solution Lab 3- sm_seq.cpp
// sram.cpp if (a_wen)
#include <iostream.h> {
#include "systemc.h" address = inreg;
#include "fsm_types.h" addr.write(address);
#include "sm_seq.h" }
else if (inca)
void sm_seq::entry() {
{ address++;
sc_bool_vector tmp_inreg(8); addr.write(address);
}
if (reset.read() == true)
{ if (wd_wen)
data.write("ZZZZZZZZ"); {
inreg.write(0); mem_wr.write(true);
outof.write(0); tmp_inreg = inreg.read();
mem_wr.write(false); data.write(tmp_inreg);
rdata = 0; idata = inreg.read();
address = 0; }
state.write(IDLE); else
wait(); {
} mem_wr.write(false);
data.write("ZZZZZZZZ");
while (true) }
{ if (rd_wen)
{
inreg.write(into); wait();
rdata = data;
outof.write(rdata); idata = data;;
state.write(next_state); }
wait();
} 615
Ver 1.4 }
308
Sample Solution Lab 4- switch.h, pkt.h
// switch.h // pkt.h
struct mcast_pkt_switch : sc_module { #include "systemc.h"
sc_in<bool> switch_cntrl; struct pkt {
sc_in<pkt> in0; sc_int<8> data;
sc_in<pkt> in1; sc_int<4> id;
sc_in<pkt> in2; bool dest0;
sc_in<pkt> in3; bool dest1;
bool dest2;
sc_out<pkt> out0; bool dest3;
sc_out<pkt> out1;
sc_out<pkt> out2; inline bool operator == (const pkt& rhs) const
sc_out<pkt> out3; {
return (rhs.data == data && rhs.id == id &&
mcast_pkt_switch(char* NAME ) rhs.dest0 == dest0 && rhs.dest1
: sc_module(NAME) { == dest1 && rhs.dest2 == dest2 && rhs.dest3 ==
sc_async_tprocess(handle1, dest3);
"SWITCH", mcast_pkt_switch, entry); }
sensitive(in0);
sensitive(in1);
};
sensitive(in2);
sensitive(in3);
sensitive(switch_cntrl);
end_module();
}
void entry();
};
617
Ver 1.4
618
Ver 1.4
309
Sample Solution Lab 4- switch.cc
// switch.cc // switch.cc
q3_out.pntr = 0; R1.free = true;
R2.free = true;
R3.free = true;
q0_in.full = false;
q1_in.full = false; result = fopen("result","w");
q2_in.full = false;
q3_in.full = false; cout << endl;
cout << "--------------------------------------------------------------------------
q0_in.empty = true; ------------" << endl;
cout << endl << " 4x4 Multicast Helix Packet Switch
q1_in.empty = true;
Simulation" <<endl;
q2_in.empty = true; cout << "--------------------------------------------------------------------------
q3_in.empty = true; ------------" << endl;
cout << " This is the simulation of a 4x4 non-blocking multicast
q0_out.full = false; helix packe
q1_out.full = false; t switch. The" << endl;
cout << " switch uses a self-routing ring of shift registers to
q2_out.full = false;
transfer cells from one" << endl;
q3_out.full = false; cout << " port to another in a pipelined fashion, resolving output
contention and handling" << endl;
q0_out.empty = true; cout << " multicast switch efficiently." << endl << endl;
q1_out.empty = true;
q2_out.empty = true;
cout << " Press any key to start the simulation..." << endl << endl;
q3_out.empty = true;
R0.free = true;
619
Ver 1.4
620
Ver 1.4
310
Sample Solution Lab 4- switch.cc
// switch.cc // switch.cc
311
Sample Solution Lab 4- main.cc
// main.cc // main.cc
#include "systemc.h" sc_signal<bool> switch_cntrl;
#include "pkt.h" sc_clock clock1("CLOCK1", 75, 0.5, 0.0);
#include "switch_clk.h" sc_clock clock2("CLOCK2", 30, 0.5, 10.0);
#include "sender.h"
#include "receiver.h" sender sender0("SENDER0");
sender0 << pkt_in0 << id0 << clock1;
#include "switch.h" sender sender1("SENDER1");
sender1 << pkt_in1 << id1 << clock1;
sender sender2("SENDER2");
int sc_main(int argc, char *argv[]) { sender2 << pkt_in2 << id2 << clock1;
sc_signal<pkt> pkt_in0; sender sender3("SENDER3");
sc_signal<pkt> pkt_in1; sender3 << pkt_in3 << id3 << clock1;
sc_signal<pkt> pkt_in2; switch_clk switch_clk1("SWITCH_CLK");
sc_signal<pkt> pkt_in3; switch_clk1 << switch_cntrl << clock2;
sc_signal<pkt> pkt_out0; mcast_pkt_switch switch1("SWITCH");
sc_signal<pkt> pkt_out1; switch1 << switch_cntrl << pkt_in0 << pkt_in1 << pkt_in2 <<
sc_signal<pkt> pkt_out2; pkt_in3 << pkt_out0 << pkt_out1 << pkt_out2 << pkt_out3;
sc_signal<pkt> pkt_out3;
receiver receiver0("RECEIVER0");
sc_signal<sc_int<4> > id0, id1, id2, id3; receiver0 << pkt_out0 << id0;
receiver receiver1("RECEIVER1");
receiver1 << pkt_out1 << id1;
id0.write(0); receiver receiver2("RECEIVER2");
receiver2 << pkt_out2 << id2;
id1.write(1); receiver receiver3("RECEIVER3");
id2.write(2); receiver3 << pkt_out3 << id3;
sc_clock::start(-1);
id3.write(3); return 0; 623
Ver 1.4
}
312
Sample Solution Lab 5- accessor.h, accessor.cc
// accessor.cc
// accessor.h
#include <iostream.h> // For C++ I/O
struct accessor : sc_module { #include <stdio.h> // For C I/O
sc_in<sc_uint<32> > datain; //input #include "systemc.h"
#include "accessor.h"
sc_out<bool> chip_select; //output void accessor::entry() {
sc_out<bool> write_enable; //output int addr;
sc_out<sc_int<32> > address; //output unsigned int datao;
unsigned int datai;
sc_out<sc_uint<32> > dataout; //output addr = 10;
sc_in_clk CLK; datao = 0xdeadbeef;
while (true) {
// Write memory location first
// Parameter chip_select.write(true);
const int memory_latency; write_enable.write(true);
address.write(addr);
dataout.write(datao);
//Constructor printf("Accessor: Data Written = %x at address %x\n", datao, addr);
wait(memory_latency); // To make all the outputs appear at the interface
accessor(const char * NAME, const int // some process functionality not shown here during which chip
MEMORY_LATENCY) // chip select is deasserted and bus is tristated
: sc_module (NAME), chip_select.write(false);
dataout.write(0);
memory_latency(MEMORY_LATENCY) { wait();
sc_sync_tprocess(handle1, "ACCESSOR", // Now read memory location
chip_select.write(true);
accessor, entry, CLK.pos()); write_enable.write(false);
end_module(); address.write(addr);
} wait(memory_latency); // For data to appear
datai = datain.read();
printf("Accessor: Data Read = %x from address %x\n", datai, addr);
// Process functionality in member function chip_select.write(false);
wait();
below addr++;
void entry(); datao++;
}
};
} // end of entry function 625
Ver 1.4
sc_start(1060);
return(0);
626
Ver 1.4
313
Sample Solution Lab 6- main.cc
// main.cc // main.cc
#include "directive.h" // ************************ ICACHE
#include "systemc.h" //***********************************
#include "bios.h" // ICACHE = ram_cs
#include "paging.h" // ICACHE = ram_we
//#include "debugger.h" // ICACHE = addr
// ICACHE = ram_datain
//#include "ebl.h" // ICACHE = ram_dataout
#include "icache.h" // ICACHE = ld_valid = pid_valid
#include "fetch.h" // ICACHE = ld_data = pid_data
#include "decode.h" sc_signal<bool> icache_valid("ICACHE_VALID") ;
#include "exec.h"
#include "mmxu.h" // ************************ BIOS
//***********************************
#include "floating.h" sc_signal<bool> ram_cs("RAM_CS") ;
#include "dcache.h" sc_signal<bool> ram_we("RAM_WE") ;
#include "pic.h" sc_signal<sc_uint<32> > addr("Address") ;
#include <climits> sc_signal<sc_uint<32> > ram_datain("RAM_DATAIN") ;
#include <cstdlib> sc_signal<sc_uint<32> > ram_dataout("RAM_DATAOUT") ;
sc_signal<bool> bios_valid("BIOS_VALID") ;
int sc_main(int ac, char *av[]) const int delay_cycles = 2;
{
// ************************ Paging
//***********************************
// Paging paging_din = ram_datain
627
Ver 1.4
314
Sample Solution Lab 6- main.cc
// main.cc // main.cc
// ************************ Decode
// ************************ DCACHE
***********************************
sc_signal<bool> pred_on("PRED_ON") ;
sc_signal<signed> mmic_datain("MMIC_DATAIN") ; /* DCU: datain */
sc_signal<sc_uint<32> >
sc_signal<unsigned> mmic_statein("MMIC_STATEIN") ;/* DCU: statein */
branch_instruction_address("BR_INSTRUCTION_ADDRE
sc_signal<bool> mmic_cs("MMIC_CS") ; /* DCU: cs */
SS");
sc_signal<bool> mmic_we("MMIC_WE") ; /* DCU: we */
// ID alu_dataout = dout from EXEC
sc_signal<sc_uint<32> > mmic_addr("MMIC_ADDR") ; /* DCU: addr */
sc_signal<signed> dram_dataout("DRAM_DATAOUT") ;
sc_signal<unsigned> mmic_dest("MMIC_DEST") ; /* DCU: dest */
sc_signal<bool> dram_rd_valid("DRAM_RD_VALID") ;
sc_signal<unsigned> mmic_destout("MMIC_DESTOUT") ;/* DCU: destout */
sc_signal<unsigned>
sc_signal<signed> mmic_dataout("MMIC_DATAOUT") ;/* DCU: dataout */
dram_write_src("DRAM_WRITE_SRC");
sc_signal<bool> mmic_out_valid("MMIC_OUT_VALID") ;/* DCU:
// ID next_pc = next_pc
out_valid*/
// ID branch_valid = branch_valid
sc_signal<unsigned> mmic_stateout("MMIC_STATEOUT") ;/* DCU:
// ID branch_target_address = branch_target_address
stateout */
sc_signal<bool> mem_access("MEM_ACCESS") ;
sc_signal<sc_uint<32> >
// ************************ Execute ***********************************
mem_address("MEM_ADDRESS") ;
sc_signal<int> alu_op("ALU_OP") ; // EXEC in_valid = decode_valid
sc_signal<bool> mem_write("MEM_WRITE") ; sc_signal<bool> in_valid("IN_VALID") ;
sc_signal<unsigned> alu_src("ALU_SRC") ; // EXEC opcode = alu_op
sc_signal<bool> reg_write("REG_WRITE") ; sc_signal<bool> negate("NEGATE") ;
sc_signal<signed int> src_A("SRC_A") ;
sc_signal<int> add1("ADD1") ;
sc_signal<signed int> src_B("SRC_B") ;
sc_signal<bool> forward_A("FORWARD_A") ; sc_signal<bool> shift_sel("SHIFT_SEL") ;
sc_signal<bool> forward_B("FORWARD_B") ; // EXEC dina = src_A
// ID stall_fetch = stall_fetch // EXEC dinb = src_B
sc_signal<bool> decode_valid("DECODE_VALID") ; // EXEC dest = alu_src
sc_signal<bool> c("C") ;
sc_signal<bool> float_valid("FLOAT_VALID") ;
sc_signal<bool> v("V") ;
sc_signal<bool> z("Z") ;
sc_signal<bool> mmx_valid("MMX_VALID") ;
sc_signal<signed> dout("DOUT") ;
sc_signal<bool> pid_valid("PID_VALID") ;
sc_signal<bool> out_valid("OUTPUT_VALID") ;
sc_signal<signed> pid_data("PID_DATA") ;
sc_signal<unsigned> destout("DESTOUT") ;
629
Ver 1.4
630
Ver 1.4
315
Sample Solution Lab 6- main.cc
// main.cc // main.cc
sc_clock clk("Clock", 1, 0.5, 0.0); fetch IFU("FETCH_BLOCK", delay_cycles);
IFU << ram_dataout << branch_target_address <<
printf("////////////////////////////////////////////////////////////////////// next_pc << branch_valid << stall_fetch << intreq << vectno <<
///\n"); bios_valid << icache_valid << pred_fetch << pred_branch_address
printf("// This code is written at SYNOPSYS, Inc.\n"); << pred_branch_valid << ram_cs << ram_we << addr <<
printf("////////////////////////////////////////////////////////////////////// ram_datain << instruction << instruction_valid <<program_counter
///\n"); << intack_cpu << branch_clear << pred_fetch_valid << reset << clk;
printf("// Module : main of CPU Model\n");
printf("// Author : Martin Wang\n");
printf("// Company : SYNOPSYS, Inc.\n"); decode IDU("DECODE_BLOCK");
printf("// Purpose : This is a simple CPU modeling using IDU << reset << instruction << pred_instruction <<
SystemC.\n"); instruction_valid << pred_inst_valid << out_valid << destout <<
printf("// Instruction Set Architecure defined by dout << dram_dataout << dram_rd_valid << destout << fdout <<
Martin Wang.\n") fout_valid << fdestout << branch_clear << dsp_data_valid <<
; program_counter << pred_on << branch_instruction_address <<
printf("// \n"); next_pc << branch_valid << branch_target_address << mem_access
printf("// SystemC (TM) Copyright (c) 1988-1999 << mem_address << alu_op << mem_write << alu_src << reg_write
by Synopsys, Inc. \ << src_A << src_B << forward_A << forward_B << stall_fetch <<
n"); decode_valid << float_valid << mmx_valid << pid_valid << pid_data
printf("// \n");
printf("////////////////////////////////////////////////////////////////////// << clk;
///\n");
631
Ver 1.4
316
Sample Solution Lab 7- pix_smoother.h and .cc
// pix_smoother.h // pix_smoother.cc
#ifndef PIX_SMOOTHER_H #include "systemc.h"
#define PIX_SMOOTHER_H #include "pix_smoother.h"
void pix_smoother::entry()
struct pix_smoother : sc_module { {
/* Channel Ports */ unsigned char pix;
unsigned char nbd_pix_cnt;
sc_channel<unsigned char> pix_in;
sc_channel<unsigned char> pix_nbd_cnt; unsigned char pix_array[9];
sc_channel<unsigned char> pix_nbd;
sc_channel<unsigned char> pix_out; while(true){
int sum = 0;
pix_smoother( const char* NAME) pix = pix_in.read(); //do you know why I have this
statemen
: sc_module (NAME) { nbd_pix_cnt = pix_nbd_cnt.read();
sc_async_tprocess(handle1, for(int i=0 ;i < nbd_pix_cnt; i++){
"PIX_SMOOTHER", pix_smoother, entry); pix_array[i] = pix_nbd.read();
sensitive << pix_in << pix_nbd_cnt << sum += pix_array[i];
pix_nbd; }
end_module(); sum /= nbd_pix_cnt; // Average over nbd pixel count
pix_out.write((unsigned char)sum);
}
}
void entry();
};
}
#endif
633
Ver 1.4
};
634
Ver 1.4
317
Sample Solution Lab 8- testbench.h , main.cc
// main.cc
// testbench.h
#include "display.h" #include "systemc.h"
#include "numgen.h" #include "pipeline.h"
#include "testbench.h"
struct testbench : public sc_module {
numgen N; // component int sc_main(int ac, char *av[])
display D; // component
{
//Constructor sc_signal<double> in1;
testbench(const char *NAME, sc_signal<double> in2;
sc_clock_edge& CLK, sc_signal<double> powr;
const sc_signal<double>& IN,
sc_signal<double>& OUT1, sc_clock clk("CLOCK", 20.0, 0.5, 0.0);
sc_signal<double>& OUT2)
: sc_module(NAME),
N("Numgen", CLK, OUT1, OUT2), testbench T("Testbench", clk.pos(), powr, in1, in2);
D("Display", CLK, IN) pipeline P("PIPE");
{ P << in1 << in2 << powr << clk;
end_module();
} sc_start(1000);
}; return(0);
}
635
Ver 1.4
636
Ver 1.4
318
Sample Solution Lab 9- Master.cc
// master.cc
// master.cc
mData.read();
#include "Master.h"
}
#define debugging
if (fireAtRandomRequest()==true) {
mRequest.write(true);
unsigned int Master::masterSeed=1;
mNextState = mRequesting;
}
void Master::entry() {
else mNextState = mStart;
// reaction to a positive edge of the clock
mAddress.write("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
");
sc_logic tmpDirection;
sc_logic_vector tmpAddress(32);
mData.write("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
sc_logic_vector tmpData(256);
ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
if (mClock.posedge()) {
ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
sampledDirection = mDirection.read();
ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
mCurrentState = mNextState;
ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
}
ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ");
mDirection.write('Z');
// master finite state machine
break;
switch (mCurrentState) {
case mRequesting:
case mStart:
if (mGranted.read()==true) {
if (sampledDirection=='0') { mRequest.write(false);
mNextState = mTransfering;
}
else {
mNextState = mRequesting;
}
637
Ver 1.4
if (tmpDirection == 1) { 638
Ver 1.4
D t it (t D t )
319
Sample Solution Lab 9- Master.cc
// master.cc
// master.cc
if ( ((double(rand()))/RAND_MAX) > 0.9 ) return true; return result;
else return false;
};
};
sc_logic_vector Master::fireAtRandomAddress() const {
sc_logic Master::fireAtRandomDirection() const {
unsigned int ui = (unsigned int)floor(
if ( ((double(rand()))/RAND_MAX) > 0.5 ) return '1'; (double(rand())/RAND_MAX) * pow(2.0,32.0)
else return '0'; );
sc_logic_vector result(32);
}; result = ui;
return result;
sc_logic_vector Master::fireAtRandomData() const {
};
unsigned int ui;
double r;
sc_logic_vector result(256);
639
Ver 1.4
#endif
640
Ver 1.4
320
Sample Solution Lab 10- fir.cc
// fir.cc // fir.cc
#include <systemc.h> coefs[4] = -18;
#include "fir.h" coefs[5] = -41;
coefs[6] = 23;
struct fir : sc_module {
coefs[7] = 154;
sc_in<bool> reset; coefs[8] = 222;
sc_in<bool> input_valid; coefs[9] = 154;
sc_in<int> sample; coefs[10] = 23;
sc_out<bool> output_data_ready; coefs[11] = -41;
sc_out<int> result;
coefs[12] = -18;
sc_in_clk CLK;
coefs[13] = 16;
sc_int<9> coefs[16]; coefs[14] = 13;
coefs[15] = -4;
SC_CTOR(fir) }
{
SC_CTHREAD(entry, CLK.pos());
void entry();
set_stack_size(99999);
watching(reset.delayed() == true); };
coefs[0] = -6;
coefs[1] = -4;
coefs[2] = 13;
coefs[3] = 16;
641
Ver 1.4
// main functionality
while(1) {
output_data_ready.write(false);
wait_until(input_valid.delayed() == true);
sample_tmp = sample.read();
acc = sample_tmp*coefs[0];
642
Ver 1.4
321
Sample Solution Lab 10- fir.cc
// fir.cc
void f_fir(const char* name, sc_in<bool> reset, sc_in<bool> input_valid, sc_in<i
/* this would be an unrolled loop */ nt> sample,
sc_out<bool> output_data_ready, sc_out<int> result, sc_in_clk
// pro = shift[i]*coefs[i+1]; CLK) {
// acc += pro; fir* f = (fir*) SC_NEW(fir(name));
acc = mac_func(shift[i], coefs[i+1], acc); (*f)(reset, input_valid, sample, output_data_ready, result, CLK);
}
};
shift[0] = sample_tmp;
// write output values
result.write(acc);
output_data_ready.write(true);
wait();
};
}
643
Ver 1.4
#define NBITS 250 // The num. of bits in n of P // Flip a coin with probability p.
and S below.
#define NBITS2 (NBITS / 2) // The num. of bits in p and
bool
q, the prime factor flip(double p)
s of n. {
#define MSG_NBITS (NBITS - 2) // The num. of bits in if (drand48() < p)
the message to cipher. return true;
else
typedef sc_bigint<NBITS> bigint;
return false;
// Initialize the random number generator. }
long
randomize(long seed)
{ // Randomly generate a bit string with nbits bits.
long in_seed = seed; // str has a length of nbits + 1.
if (in_seed == -1)
void
rand_bitstr(char *str, int nbits)
time(&in_seed); {
str[0] = '0'; // Sign for positive numbers.
644
Ver 1.4
322
Sample Solution Lab 11- rsa.cc
// rsa.cc
for (int i = 1; i < nbits; ++i) ret_pos(const bigint& x, const bigint& n)
str[i] = (flip(0.5) == true ? '1' : '0'); {
if (x < 0)
str[nbits] = '\0'; return x + n;
} return x;
}
str[nbits] = '\0';
} // Compute d, x, and y such that d = gcd(a, b) = ax + by
// x and y can be zero or negative.
void
// Return a positive remainder. euclid(const bigint& a, const bigint& b, bigint& d,
bigint bigint& x, bigint& y)
645
Ver 1.4
646
Ver 1.4
323
Sample Solution Lab 11- rsa.cc
// rsa.cc
x %= n; // Return true iff a is a witness to the compositeness of n,
i.e., a
return ret_pos(x, n); // can be used to prove that n is composite.
} bool
witness(const bigint& a, const bigint& n)
{
// Find a small odd integer a that is relatively bigint d = 1;
prime to b. I do not bigint x;
// know an efficient algorithm to do that. The loop
below usually // Compute d = a^(n-1) % n.
// iterates a few times. for (int i = n.length() - 1; i >= 0; --i)
bigint {
find_rel_prime(const bigint& n) x = ABS_VAL(d);
{
bigint a = 3; d = (d * d) % n;
while (true) {
if (gcd(a, n) == 1) // x is a nontrivial square root of 1 modulo n ==> n is
break; composite.
a += 2; if ((ABS_VAL(d) == 1) && (x != 1) && (x != (n - 1)))
} return true;
647
Ver 1.4
324
Sample Solution Lab 11- rsa.cc
// rsa.cc
// Choose a random number. rand_bitstr(p_str, NBITS2);
rand_bitstr(str, NBITS); p_str[NBITS2 - 1] = '1'; // Force p to be an odd number.
bigint p = p_str;
// Set a to the chosen number.
bigint a = str; // p is randomly determined. Now, we'll look for a prime
in the
// Make sure that a is in [1, n - 1]. // vicinity of p. By the prime number theorem, executing
a = (a % (n - 1)) + 1; the
// following loop approx. ln (2^NBITS) iterations should
// Check to see if a is a witness. find a
if (witness(a, n)) // prime.
return false; // n is definitely composite.
} while (! miller_rabin(p))
p = (p + 2) % r;
return true; // n is almost surely prime. return p;
} }
// Return a prime number. // Encode or cipher the message in msg using the RSA
bigint public key P=(e, n).
find_prime(const bigint& r) bigint
{ cipher(const bigint& msg, const bigint& e, const bigint&
n)
char p_str[NBITS2 + 1]; {
return modular_exp(msg, e, n);
}
649
Ver 1.4
// Initialize the random number generator. cout << "RSA secret key: S=(d, n)" << endl;
cout << "seed = " << randomize(long(-1)) << cout << "d = " << d << endl;
endl;
cout << "n = " << n << endl;
325
Sample Solution Lab 11- rsa.cc
// rsa.cc
cout << endl; int
sc_main(int argc, char *argv[])
// Cipher and decipher a randomly generated {
message msg. rsa();
char msg_str[MSG_NBITS + 1]; return 0;
rand_bitstr(msg_str, MSG_NBITS); }
bigint msg = msg_str;
651
Ver 1.4
652
Ver 1.4
326
What is New?
Introduction of Ports
Similar to VHDL/Verilog, concept of ports is introduced making
writing constructor for the interface file much easier.
i.e.sc_in<input type>, sc_out<output type>, sc_inout<inout type>
Introduction of fast bit-vector (sc_bv) and logic-vector
(sc_lv)
e.g. sc_bv<32> address;
653
Ver 1.4
654
Ver 1.4
327
New SystemC Ver 0.91 Process Naming Convention
655
Ver 1.4
// Input ports:
Input port sc_in<type>
sc_in_clk clk; // Clock for the actions of the driver.
sc_in<double> speed;
sc_in<double> angle;
sc_in<double> total; Output port sc_out<type>
sc_in<double> partial;
// Output ports:
sc_out<bool> reset; // Set if the driver wants to reset the partial
// distance odometer.
sc_out<int> speed_set; // Speed of the car as set by the driver.
sc_out<bool> start; // Set if the driver starts the car. Multiple Processes
// Driver's actions.
void driver_out_proc();
void driver_in_proc();
SC_CTOR(driver_mod) {
SC_CTHREAD(driver_out_proc, clk.pos());
SC_METHOD(driver_in_proc);
sensitive << speed << angle << total << partial;
}
};
656
Ver 1.4
328
Simple Version 1.0 Example
Draft Specification
Simple Example
657
Ver 1.4
658
Ver 1.4
329
Simple SystemC 1.0 Example
//example.cc
//example.cc
a = in1.read(); b = in2.read();
cout << "In1 = " << a << " In2 = " << b << endl; my_module M("MM");
} M << adder_in_1 << adder_in_2 << adder_out_1 <<
adder_out_2 << clock;
testbench(sc_module_name my_name) testbench T("TB");
{ T << adder_out_1 << adder_out_2 << adder_in_1 <<
sc_async_fprocess(handle1, "stim", testbench, adder_in_2 << clock;
stimulus);
sensitive_pos(clock); clock = 0;
adder_in_1.write(0); adder_in_2.write(0);
sc_async_fprocess(handle2, "resp", testbench, sc_initialize();
response); for (int i = 0; i < 10; i ++) {
sensitive << in1 << in2; clock = 1;
sc_cycle(10);
i = j = 0; clock = 0;
} sc_cycle(10);
}; }
return 0;
int sc_main(int ac, char *av[]) }
{
sc_signal<sc_uint<8> > adder_in_1, adder_in_2;
sc_signal<sc_uint<8> > adder_out_1, adder_out_2;
sc_signal<bool> clock;
659
Ver 1.4
660
Ver 1.4
330
SystemC Fixed-Point Datatypes : Syntax
661
Ver 1.4
(1.75)10 = (0001.1100)2
1’s complement of (0001.1100)2 = (1110.0011)2
2’s complement of (0001.1100)2 = (1110.0100)2
my_var
1 1 1 0 0 1 0 0
.
sign bit Integer bits fractional bits
662
Ver 1.4
331
The Open SystemC™ Initiative (OSCI)
The Open SystemC Initiative (OSCI) is a collaborative effort among a
broad range of companies to support and advance SystemC as a de facto
standard for system-level design. OSCI provides an interoperable,
modeling platform to exchange very fast system-level C++ models and
develop seamless tool integration. OSCI also fosters the rapid growth of a
global market for innovative new system-level design solutions.
SystemC is a modeling platform consisting of C++ class libraries and a
simulation kernel for design at the system-behavioral- and register-
transfer-levels. Designers create models using SystemC and standard
ANSI C++. EDA vendors creat tools that are automatically interoperable.
The SystemC community consists of a large and growing number of
system, semiconductor, IP, embedded software companies and EDA
companies. Members click through a web-based license agreeement,
download SystemC source and proceed to use, modify or improve it - at
no cost. Members advance the standard by submitting enhancements to
SystemC's Steering Group.
The Open SystemC Initiative combines the broadest industry support with
the best modeling platform for advanced system design
663
Ver 1.4
664
Ver 1.4
332
SystemC Quick Reference Guide - 1
main.cc SystemCTM model consists of :
main.cc
a1 in1 include systemc.h
Stimulus Response create internal signals linking all modules/processes
Adder out re together
Generator Monitor
create clock
a2 in2
instantiate processes/modules
start simulation
implementation.cc
include systemc.h
Source code include interface.h
entry function
create internal signals/variables
describe functionality
665
Ver 1.4
666
Ver 1.4
333
SystemC Quick Reference Guide - 3
stimgen.cc adder.cc monitor.cc
// header file adder.h
stimgen.h adder.h monitor.h 1 struct adder : public sc_sync {
2 // Input ports
const sc_signal<int>& in1;
const sc_signal<int>& in2;
// Output ports
3 sc_signal<int>& out;
main.cc
4 // Constructor
adder (const char * NAME,
const sc_clock_edge& CLK,
const sc_signal<int>& IN1,
interface.h (header/interface file) const sc_signal<int>& IN2,
1 declare the type of the process sc_signal<int>& OUT)
2 create reference to a input signal : sc_sync(NAME, CLK), in1(IN1),
in2(IN2), out(OUT)
3 create reference to a inout/output { /* watching or sensitivity
signal list */
4 constructor for initialization
}
5 global watching
7 // Functionality of the process
6 sensitivity lists (sc_async, void entry();
sc_aproc ONLY) };
7
void entry(); function 5 Watching(reset.delayed() == true);
667
Ver 1.4
5 describe functionality
334
SystemC Quick Reference Guide - 5
stimgen.cc adder.cc monitor.cc
// interface file testbench.h
stimgen.h adder.h monitor.h #include ”stimgen.h"
1
#include ”monitor.h"
//Constructor
5 testbench(const char *NAME,
sc_clock_edge& CLK,
const sc_signal<int>& RE,
main.cc 6 sc_signal<int>& A1,
sc_signal<int>& A2)
: sc_module(NAME),
STIM(”STIM", CLK, A1, A2),
module.h (for modular design) MON(”MON", CLK, RE)
1 include component’s header file {
7 end_module();
2 declare the type as sc_module }
3 instantiate components };
4 internal signals connecting modules
Human Sources:
Training
Synopsys ACE Program
Support Center
Application Consultants
Consultants
670
Ver 1.4
335