ipblock design in GEZEL Patrick Schaumont Virginia Tech Dept. of Electrical and Computer Engineering September 2010
Jan 29, 2016
ipblock design in GEZEL
Patrick Schaumont
Virginia TechDept. of Electrical and Computer Engineering
September 2010
2
What are ipblock?
• An ipblock is a black-box simulation entity for GEZEL
ipblock M(in address : ns(5); in wr,rd : ns(1); in idata : ns(8); out odata : ns(8)) { iptype "ram"; ipparm "wl=8"; ipparm "size=32"; }
InterfaceName
Type
Parameters
3
Applications of ipblock
• Capture functionality not available as FSMD• FSMD does not exist: memory modules• FSMD unavailable: IP, complex modules, ..
• Interfaces to other simulation engines• Instruction-set simulators: ARM, 8051• Other languages/environments: SystemC,...
• Extensions of GEZEL simulation capabilities• Collect signal statistics• Debug facility
4
Who develops ipblock?
GEZEL Designers GEZEL Users
ipblock
with generic use design-specific
5
How are ipblock implemented?
aipblock
ipblock
GEZEL class lib(data types,
symbol table, ...)C++
ld.sofdlsim/gplatform
dynamic-link librarystatically linked
EXE
6
Operational Principle
• ipblock are cycle-based simulation models• A cycle-based simulation has two phases
per cycle: evaluate and (state) update
R1 R2 R3logic L1 logic L2
7
Operational Principle
• ipblock are cycle-based simulation models• A cycle-based simulation has two phases
per cycle: evaluate and (state) update
R1
R2
R3
logic L1
logic L2
R1
R2
R3
Cycle N Cycle N + 1
Evaluate: next_R1 = ... next_R2 = Logic_L1(R1); next_R3 = Logic_L2(R2);
Update: R1 = next_R1; R2 = next_R2; R3 = next_R3;
8
Operational Principle
• ipblock are cycle-based simulation models• A cycle-based simulation has two phases
per cycle: evaluate and (state) update• Evaluate and update can be called only once
per cycle
R1 R3logic L1 logic L2
GEZEL ensures that all Evaluate( ) are properly sorted:Logic_L1(R1) will be called BEFORE Logic L2(L1_output)
9
Operational Principle
• ipblock are cycle-based simulation models• A cycle-based simulation has two phases
per cycle: evaluate and (state) update• Evaluate and update are called only once
per cycle
logic L1 logic L1 logic L2
If the execution order for Evaluate( ) cannot be determined,the simulator terminates ('combinatorial loop')
10
Combinational ipblock
• By default, have a single evaluate function, called once per clock cycle
ipblock
ipblockipblock
fsmd
OK
Not OK
11
Simple ipblock: combinational
ipblock ablock(in a, b : ns(8); out c : ns(8)) { iptype "myblock";}
GEZEL
C++
void myblock::run() { ioval[2]->assignulong(ioval[0]->toulong() + ioval[1]->toulong());}
class myblock : public aipblock { public: void run();};
+
12
Simple ipblock: combinational
ipblock ablock(in a, b : ns(8); out c : ns(8)) { iptype "myblock";}
GEZEL
C++
void myblock::run() { ioval[2]->assignulong(ioval[0]->toulong() + ioval[1]->toulong());}
class myblock : public aipblock { public: void run();};
ioval[0]
ioval[1]
ioval[2]
a
b
c
13
Simple ipblock: combinational
ipblock ablock(in a, b : ns(8); out c : ns(8)) { iptype "myblock";}
GEZEL
C++
void myblock::run() { ioval[2]->assignulong(ioval[0]->toulong() + ioval[1]->toulong());}
class myblock : public aipblock { public: void run();};
• run() is called once per clock cycle• When called, input ioval[ ] reflects proper value
for that clock cycle• When called, output ioval[ ] must be assigned
proper value for that clock cycle
14
Adding parameters
ipblock ablock(in a, b : ns(8); out c : ns(8)) { iptype "myblock"; ipparm "thisparam=thatval";}
GEZEL
C++
void myblock::run() { ioval[2]->assignulong(ioval[0]->toulong() + ioval[1]->toulong());}
void myblock::setparam(char *n) { // ...}
class myblock : public aipblock { public: void run(); void setparam(char *);};
call constructor
for each 'ipparm'call setparam
for each cyclecall run
15
Terminal-check function
ipblock ablock(in a, b : ns(8); out c : ns(8)) { iptype "myblock"; ipparm "thisparam=thatval";}
GEZEL
C++
class myblock : public aipblock { public: void run(); void setparam(char *); bool checkterminal(int n, char *tname, iodir d);};
bool myblock::checkterminal(int n, char *tname, iodir d) { switch(n) { case 0 : return (isinput(d) && isname(tname, "a")); break; ... } return false;}
• ipblock use positional port matching• checkterminal verifies that ioval[0] is
an input name "a", ioval[1] is input "b", ...
16
Terminal-check function
ipblock ablock(in a, b : ns(8); out c : ns(8)) { iptype "myblock"; ipparm "thisparam=thatval";}
GEZEL
C++
class myblock : public aipblock { public: void run(); void setparam(char *); void checkterminal(..);};
call constructor
for each 'ipparm'call setparam
for each cyclecall run
for each i/o portcall checkterminal
17
Completing the C++
#ifndef myblock_h#define myblock_h
#include "ipblock.h"
extern "C" aipblock *create_myblock(char *instname);
class myblock : public aipblock {
public: myblock(char *name); void setparm(char *); void run(); bool checkterminal(int n, char *tname, aipblock::iodir d); bool cannotSleepTest(); bool needsWakeupTest();};
#endif
myblock.h
Access to GEZEL library functions(aipblock definition, arbitrary-precision data types, ..)
Called by the dynamic-link facility,Function name depends on class name!
simulator control(see part 2)
18
Completing the C++
myblock.cxx
#include "myblock.h"
extern "C" aipblock *create_myblock(char *instname) { return new myblock(instname);}
myblock::myblock(char *name) : aipblock(name) {..}
void myblock::setparm(char *_name) {..}
void myblock::run() {..}bool myblock::checkterminal(..) {..}
bool myblock::cannotSleepTest(){ return false;}
bool myblock::needsWakeupTest(){ return true;}
Default implementationfor combinational modules
Called by dynamic-link facility
19
Compilation-Simulation Example
g++ -fPIC -O3 -I/opt/gezel-2.2/include/gezel -c myblock.cxx
g++ -shared -O3 \ -Wl,--rpath -Wl,/home/schaum/gezel/devel/build/lib \ myblock.o \ /opt/gezel-2.2/lib/libipconfig.so \ /opt/gezel-2.2/lib/libfdl.so \ -lgmp -ldl -o libmyblock.so
Compile:
Create dynamic-link library
20
Compilation-Simulation Example
g++ -fPIC -O3 -I/opt/gezel-2.2/include/gezel -c myblock.cxx
g++ -shared -O3 \ -Wl,--rpath -Wl,/home/schaum/gezel/devel/build/lib \ myblock.o \ /opt/gezel-2.2/lib/libipconfig.so \ /opt/gezel-2.2/lib/libfdl.so \ -lgmp -ldl -o libmyblock.so
Compile:
Create dynamic-link library
position-independent code
.so library
path to gezel lib
gezel lib and predefined ipblocks
arbitrary precisionmath lib
dynamic link lib
21
GEZEL File
ipblock ablock(in a, b : ns(8); out c : ns(8)) { iptype "myblock"; ipparm "thisparam=thatval";}
dp top { sig a, b, c : ns(8); reg a1 : ns(8); use ablock(a, b, c); always { a = a1; b = 2; $display("a ", a, " b ", b, " c ",c); a1 = a1 + 1; }}
system S { top;}
22
Simulation
> /opt/gezel-2.2/bin/fdlsim ipb.fdl 5
set parm: thisparam=thatvala 0 b 2 c 2a 1 b 2 c 3a 2 b 2 c 4a 3 b 2 c 5a 4 b 2 c 6
1. parse ipb.fdl2. instantiate ipblock 2.1. link dynamic-link lib3. simulate 5 cycles
output:
define all FSM next-state
evaluate output of each dp
call ipblock with no output
update dp registers
Per clock cycle:
23
Summary
#ifndef myblock_h#define myblock_h
#include "ipblock.h"
class myblock : public aipblock {
public: myblock(char *name); void setparm(char *); void run(); bool checkterminal(int n, char *tname, aipblock::iodir d); bool cannotSleepTest(); bool needsWakeupTest();};
#endif
24
Sleep Cycle Mechanism
#ifndef myblock_h#define myblock_h
#include "ipblock.h"
class myblock : public aipblock {
public: myblock(char *name); void setparm(char *); void run(); bool checkterminal(int n, char *tname, aipblock::iodir d); bool cannotSleepTest(); bool needsWakeupTest();};
#endif
25
Sleep Cycle Mechanism
Software(typ 1Mc/s)
Hardware(typ 10K/s)
100K cycles
100 cycles
100 cycles
100K cycles
100K cycles
26
Sleep Cycle Mechanism
Software(typ 1Mc/s)
Hardware(typ 10K/s)
100K cycles
100 cycles
100 cycles
100K cycles
100K cycles
Without sleep-cycle:300,200 cycles @ 10K/s
=30.02 seconds
27
Sleep Cycle Mechanism
Software(typ 1Mc/s)
Hardware(typ 10K/s)
100K cycles
100 cycles
100 cycles
100K cycles
100K cycles
With sleep-cycle:300K cycles @ 1M/s +
300K cycles (testing_overhead) +200 cycles @ 10K/s
=less than 0.5 seconds!
28
Sleep Cycle Mechanism
• GEZEL simulator has two states:• Active:
– each clock cycle, evaluate all datapath outputs (and dependent signals), evaluate all registers, evaluate all ipblock
– perform sleep test
• Passive:– perform wakeup test
29
Sleep Cycle Mechanism
• Transition from active to passive
Active
Passive
sleep_test = false
sleep_test = truewakeup_test = true
wakeup_test = false
30
Sleep Test
• Sleep test evaluates to false in cycle X if:• Any register changes state during a clock X• Any FSM changes state during clock cycle X• Any ipblock returns true in
aipblock::cannotSleepTest()
• GEZEL simulator will call cannotSleepTest () once per cycle in active mode, default value should be false
• (why is my GEZEL cosimulation so slow?Might be because there is remaining HW activity in idle phases)
31
Wakeup Test
• Wakeup test evaluates to true in cycle X if:• Any ipblock returns true in
aipblock::needsWakeupTest()
• GEZEL simulator will call needsWakeupTest () once per cycle in passive mode, default value should be false
• If needsWakeupTest() never returns false, your simulation will never sleep (may be the cause of a slow cosimulation)
• If needsWakeupTest() never returns true, your simulation will never wakeup (may be the cause of a ‘halted’ cosimulation)
32
Example: 8051 cosimulation interface
8051 4 bi-directional ports
Three GEZEL ipblock:
ipblock my8051 { iptype "i8051system"; ipparm "exec=driver.ihx"; ipparm "verbose=1"; ipparm "period=1";}
ipblock my8051_datain(out data : ns(8)) { iptype "i8051systemsource"; ipparm "core=my8051"; ipparm "port=P1";}
ipblock my8051_dataout(in data : ns(8)) { iptype "i8051systemsink"; ipparm "core=my8051"; ipparm "port=P2";}
Core
Input port
Output port
33
The Core
void i8051system::run() { if (sim.IsRunning()) { period_cnt--; if (period_cnt == 0) { period_cnt = period; sim.ClockTick(); if (! sim.IsRunning())
glbRunningISS--; } }}
bool i8051system::cannotSleepTest() { return false; // the ISS will continue to run in sleep mode // so we can also return 'OK to sleep'}
bool i8051system::needsWakeupTest() { run(); return false;}
34
The Input Port
void i8051systemsink::run() { if (hook) { hook->writeRAM(address, ioval[0]->toulong()); }}
bool i8051systemsink::cannotSleepTest() { return false;}
(If you do not specify needsWakeupTest(), default implementation is used, which returns false)
35
The Output Port
void i8051systemsource::run() {}
Obviously, it is the 8051 simulator that decides what the value of the output port should be. The 8051 simulator calls a functionexternalwrite(address, data) each time is performs a port write
36
The Output Port
void i8051systemsource::run() {}
Obviously, it is the 8051 simulator that decides what the value of the output port should be. The 8051 simulator calls a functionexternalwrite(address, data) each time is performs a port write
void i8051externalwrite(int dev, unsigned char d) { i8051devmap[dev]->ioval[0]->assignulong((long) d); i8051devmap[dev]->touch();}
I8051devmap is an array of output port ipblocks that are
implemented by GEZEL
The result of the externalwrite( ) is that an ipblock output is updated
37
The Output Port
void i8051systemsource::run() {}
bool i8051systemsource::needsWakeupTest() { bool v = interfacewritten; interfacewritten = false; return v;}
bool i8051systemsource::cannotSleepTest() { bool v = interfacewritten; interfacewritten = false; return v;}
void i8051systemsource::touch() { interfacewritten = true;}
void i8051externalwrite(int dev, unsigned char d) { i8051devmap[dev]->ioval[0]->assignulong((long) d); i8051devmap[dev]->touch();}
As a result ofthe 8051 WRITING
to the hardware,the cycle-simulation
will wake-up
38
Review: One C++ class
#ifndef myblock_h#define myblock_h
#include "ipblock.h"
class myblock : public aipblock {
public: myblock(char *name); void setparm(char *); void run(); bool checkterminal(int n, char *tname, aipblock::iodir d); bool cannotSleepTest(); bool needsWakeupTest();};
#endif
OK!
39
Ipblock are combinational
• By default, have a single evaluate function, run( ), called once per clock cycle
ipblock
ipblockipblock
fsmd
OK
Not OK
40
Support for sequential IP block
• Define sequential IP block:
a sequential ipblock is an ipblock with an output which is is known and stable at the start of a clock cycle.
• Thus, ‘sequential’ is a property of an output, not an entire ipblock
41
Support for Sequential IPblock
• For example, assume you develop a C++ class for this structure:
ipblock
CombFunction
Sequential output
Combinational output
42
Support for Sequential IP block
• This will simulate fine !
ipblock
CombFunction
CombFunction
0
43
Sequential IP Block in C++
#ifndef myblock_h#define myblock_h
#include "ipblock.h"
class myblock : public aipblock {
public: myblock(char *name); void setparm(char *); void run(); bool checkterminal(int n, char *tname, aipblock::iodir d); bool cannotSleepTest(); bool needsWakeupTest(); void regOutput(); void out_run();};
#endif
44
regOutput
• Used in constructor to define an ipblock output as sequential
armsfu2x1::armsfu2x1(char *name) : aipblock(name) { deviceid = 0; hook = 0; myarm = 0; interfacewritten = false; regOutput(0); // d1 and d2 are registered regOutput(1);}
// ipblock mysfu(out d1 : ns(32); out d2 : ns(32);// in q1 : ns(32); in q2 : ns(32)) {// iptype "armsfu2x2";// ipparm "core = mycore"; -- core to hook into// ipparm "device = 0"; -- 2 possible devices per sfu type// }
45
regOutput
• Used in constructor to define an ipblock output as sequential
// ipblock mysfu(out d1 : ns(32); out d2 : ns(32);// in q1 : ns(32); in q2 : ns(32)) {// iptype "armsfu2x2";// ipparm "core = mycore"; -- core to hook into// ipparm "device = 0"; -- 2 possible devices per sfu type// }
armsfu2x2Custom
Datapath(combinational)
d1d2
q1q2
OK!
Stable at the start of a clock cycle
46
out_run( )
• out_run( ) is called at the start of the clock cycle, before any other run( ) is called, and before any signal or register is evaluated.
• Typically, out_run( ) is used to initialize regOutput outputs to a stable value for that clock cycle.
47
Example: accumulator ipblock
ipblock
add
ipblock acc(in d : ns(8); out q : ns(8)) { iptype “accumulator”;}
myacc::myacc(char *name) : aipblock(name) { regOutput(0); accvalue = 0;}
myacc::out_run() { ioval[0]->assignulong(accvalue);}
myacc::run() { accvalue = accvalue + ioval[1]->toulong();}
48
Final hints
• ipblock are a powerful extension mechanism for GEZEL• Puts a designer in control of design
environment• Allows to put hardware design in context
• Other neat tool: icg (incremental code generator)• Generates ipblock C++ out of GEZEL code• Useful to speed up simulation (3X – 10X faster)• Useful to compile HW to SW
nice open research problems left here