Académique Documents
Professionnel Documents
Culture Documents
SystemC + miniMIPS
Henk Corporaal
Eindhoven University of Technology 2011
1
Hardware-software co-design
Were designing a processor system. This is hardware that runs software. We need to design BOTH hardware and software Hence the name: Hardware-Software co-design. In our case the hardware is an FPGA. In real life this could be a multi-million dollar chip that takes 6 months to implement in hardware. We need to emulate/simulate the hardware before were actually making it. In this way errors can be found early on. A simulation model of the hardware can be described in SystemC. This is actually a C++ program with a special toolkit. We also compile our SystemC processor into FPGA hardware; so we use SystemC for 2 purposes.
Hardware
System
Software
lcc.exe C compiler
C++ compiler
Running the simulation program: Your MIPS machine processor ram code system
(program)
ram
(program)
C-program file.c
Programming flow
MIPS simulator spim.exe software MIPS assembler hardware MIPS assembler file.asm
Compiler lcc.exe
Assembler mips-as.exe
C++ source main.cpp C++ source main.cpp C++ source C++ source main.cpp main.cpp C++ compiler Visual C++
cygwin
Some of the programs we use (LCC, the MIPS assembler) are written as UNIX tools. The distribution contains a GNU Unix environment called cygwin.
SystemC
SystemC is a C++ library with class definitions. You write some C++ code using the classes. This describes two issues: 1 Circuit structure (schematic/functionality) 2 Simulation settings Compiling and running it will perform the simulation. SystemC is just C++ code, though it looks funny.
PG/HC 2008 Programming 5JJ70 pg 11
.....
Event & Signa l I/F C++ Class Library Events Hardware Simulation Kernel (Event Scheduler)
template <class T> T maximum (T a, T b) { if(a > b) return a; else return b; } returns type T a and b are of type T
Behind the scenes, the compiler builds the routine for each class that is required. This is a little heavy on the compiler, and also harder to debug.
PG/HC 2008 Programming 5JJ70 pg 14
Again, the compiler builds a separate code instance for each type that is required.
PG/HC 2008 Programming 5JJ70 pg 15
The SystemC class structure is rather complicated. I suggest to single-step through the example to get a feel for it.
a
OR
Instantiates the input pins a and b. They carry boolean sygnals. This object inherits all systemC properties of a pin. how this is actually implemented is hidden from us! Similarly, a boolean output pin called o Tells the simulator which function to run to evaluate the output pin Run the method when signal a or b changes This is the actual or!
PG/HC 2008 Programming 5JJ70 pg 17
sc_out<bool> o; // output pin o SC_CTOR(OR2) // the ctor { SC_METHOD(or_process); sensitive << a << b; } void or_process() { o.write( a.read() || b.read() ); }
First a data structure is built that describes the circuit. This is a set of module (cell-)objects with attached pin objects. Signal objects tie the pins together. Then the simulation can be started. The simulation needs: input values the list of pins that is to reported.
AND4
Instance name
Module type
// 1: instantiate the gate objects OR2 or1("or1"), or8(or8); OR3 or2(or2); AND2 and3("and3"), and4("and4"), and5("and5"); AND3 and6("and6"); NOR2 nor7(nor7"); Name stored INV inv9(inv9);
in instance
or_1
AND3
and_3
NOR7
nor_7
INV9
CO
AND4
and_4 and_5
OR2
or_2
SUM
A B CI
and_6
Boolean signal
// continued from previous page // 2: instantiate the signal objects sc_signal<bool> A, B, CI; // input nets sc_signal<bool> CO, SUM; // output nets sc_signal<bool> or_1, or_2, and_3, and_4; // internal nets sc_signal<bool> and_5, and_6, nor_7; // internal nets // continued next page
PG/HC 2008 Programming 5JJ70 pg 20
and_6
// 3: Connect the gates to the signal nets pin object o or1.a(A); or1.b(B); or1.o(or_1); or2.a(A); or2.b(B); or2.c(CI); or2.o(or_2); and3.a(or_1); and3.b(CI); and3.o(and_3); and4.a(A); and4.b(B); and4.o(and_4); Signal net object and5.a(nor_7); and5.b(or_2); and5.o(and_5); and6.a(A); and6.b(B); and6.c(CI); and6.o(and_6); nor7.a(and_3); nor7.b(and_4); nor7.o(nor_7); or8.a(and_5); or8.b(and_6); or8.o(SUM); inv9.a(nor_7); inv9.o(CO); // continued next page PG/HC 2008 Programming 5JJ70
pg 21
sc_close_vcd_trace_file(tf); }
Waveform viewer
Modules
Modules are the basic building blocks to partition a design they allow to partition complex systems in smaller components Modules hide internal data representation, use interfaces Modules are classes in C++ A module is similar to an entity in VHDL
SC_MODULE(module_name) { // Ports declaration // Signals declaration // Module constructor : SC_CTOR // Process constructors and sensibility list // SC_METHOD // Sub-Modules creation and port mappings // Signals initialization }
in1
void doIt( void ); SC_CTOR( Mux21 ) { SC_METHOD( doIt ); sensitive << selection; sensitive << in1; sensitive << in2;
selection
} };
Example: 'filter'
3 types of Processes
Methods When activated, executes and returns (just like a function) SC_METHOD(process_name); no staticly kept state activated by event on sensitivity list Threads Can be suspended and reactivated wait() -> suspends execution activated by event on sensitivity list SC_THREAD(process_name); CThreads Activated by the clock pulse SC_CTHREAD(process_name, clock value);
PG/HC 2008 Programming 5JJ70 pg 27
An Example of an SC_THREAD
void do_count() { while(1) { if(reset) { value = 0; } else if (count) { value++; q.write(value); } wait(); } }
Repeat forever
SC_THREAD Example
SC_MODULE(my_module) { sc_in<bool> id; sc_in<bool> clock; sc_in<sc_uint<3> > in_a; sc_in<sc_uint<3> > in_b; sc_out<sc_uint<3> > out_c; void my_thread(); SC_CTOR(my_module) { SC_THREAD(my_thread); sensitive << clock.pos(); } };
Thread implementation:
//my_module.cpp void my_module:: my_thread() { while(true) { if (id.read()) out_c.write(in_a.read()); else out_c.write(in_b.read()); wait(); } };
SC_CTHREAD
Will be deprecated in future releases Almost identical to SC_THREAD, but implements clocked threads Sensitive only to one edge of one and only one clock It is not triggered if inputs other than the clock change Models the behavior of unregistered inputs and registered outputs Useful for high level simulations, where the clock is used as the only synchronization device Adds wait_until( ) and watching( ) semantics for easy deployment
PG/HC 2008 Programming 5JJ70 pg 32
Counter in SystemC
SC_MODULE(countsub) { sc_in<double> in1; sc_in<double> in2; sc_out<double> sum; sc_out<double> diff; sc_in<bool> clk; void addsub(); // Constructor: SC_CTOR(countsub) { // Declare addsub as SC_METHOD SC_METHOD(addsub); // make it sensitive to // positive clock sensitive_pos << clk; } }; //Definition of addsub method void countsub::addsub() { double a; double b; a = in1.read(); b = in2.read(); sum.write(a+b); diff.write(a-b); };
sum diff
Examples: in_tmp = in.read( ); out.write(out_temp); //reads the port in to in_tmp //writes out_temp in the out port
Clocks
Special object How to create ?
Data Types
SystemC supports: all C/C++ native types plus specific SystemC types SystemC types Types for systems modelling 2 values (0,1) 4 values (0,1,Z,X) Arbitrary size integer (Signed/Unsigned) Fixed point types
SC_LOGIC type
More general than bool, 4 values : (0 (false), 1 (true), X (undefined) , Z(high-impedance) ) Assignment like bool my_logic = 0; my_logic = Z; Simulation time bigger than bool Operators like bool Declaration sc_logic my_logic;
Description
Simple bit with 4 values(0/1/X/Z) Signed Integer from 1-64 bits Unsigned Integer from 1-64 bits Arbitrary size signed integer Arbitrary size unsigned integer Arbitrary size 2-values vector Arbitrary size 4-values vector templated signed fixed point templated unsigned fixed point untemplated signed fixed point untemplated unsigned fixed point
See chapter 7 of the SystemC user manual for all details on Fixed Point Types
sum half-adder
carry
Monitor
int sc_main(int argc, char* argv[]) { sc_signal<booL> t_a, t_b, t_cin, t_sum, t_cout; full_adder f1(Fulladder); //connect using positional association f1 << t_a << t_b << t_cin << t_sum << t_cout; pattern_gen pg_ptr = new pattern_gen(Generation); //connection using named association pg_ptr->d_a(t_a); pg_ptr->d_b(t_b); (*pg_ptr->d_cin(t_cin); monitor mol(Monitor); mo1 << t_a << t_b << t_cin << t_sum << t_cout; sc_start(100, SC_NS); return 0; }
Pattern_gen