You are on page 1of 49

Processor Design 5Z032

SystemC + miniMIPS
Henk Corporaal
Eindhoven University of Technology 2011
1

SystemC and our MIPS project
‡ As part of the lab you·ll be building a real MIPS processor ² Here we discuss the so-called mmMIPS (miniminiMIPS) ‡ based on your book, ch 5 and 6 (3rd ed) / ch 4 (4th ed) ² It has only 9 instructions, in 3 categories: ‡ arithmetic ‡ data load and store ‡ branch and jump ² Described in SystemC ‡ In the lab (exercise B) we directly start with the mMIPS (miniMIPS) ² it has about 35 instructions ² it can run C-code by using the available LCC C-compiler ‡ SystemC; we discuss ² basics (module example, tracing, main function) ² modules and submodules ² processes ² data types
© PG/HC 2008 Programming 5JJ70 pg 2

mmMIPS (pipelined version)

© PG/HC 2008 Programming 5JJ70 pg 3

Hardware-software co-design
‡ We·re 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 we·re 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

© PG/HC 2008 Programming 5JJ70 pg 4

exe C compiler mips-as. etc Analyze: Oscilloscope. etc.Overview of mmMIPS design trajectory SystemC model of mini-mini MIPS (bunch of C++ files) subset of MIPS instructions lcc. © PG/HC 2008 Programming 5JJ70 pg 5 .exe MIPS assembler machine code (program) C++ compiler Synopsys CoCentric compiler Running the simulation program: Your MIPS machine processor ram code system (program) FPGA hardware: Your MIPS machine processor code system ram (program) Analyze: waveform. logic analyzer.

exe SystemC model of miniminiMIPS Assembler mips-as.exe GTK Signal analyzer winwave.cpp C++ source C++ source main.vcd © PG/HC 2008 Programming 5JJ70 pg 6 .o Model of mips single-cycle.cpp C++ compiler Visual C++ To strip the first 34 bytes HDD hex editor hex-editor.exe Object code file.c Programming flow MIPS simulator spim.exe software MIPS assembler hardware MIPS assembler file.exe Disassembler disas Object code file.cpp C++ source main.cpp main.C-program file.o Initially we start here C++ source main.asm runs in cygwin runs in Windows Compiler lcc.exe Simulation output mips.

nl/education/Computation/mmips-lab For download instructions.ele. Go to the directory web site http://www.WinWave .LCC .es. ‡ This will install: ² HDD Hex Editor ² Cygwin ² PC Spim .tue.SystemC stuff for Borland/Visual C++ .Single Cycle Minimips in SystemC. Multi-cycle Minimips and pipelined MIPS. © PG/HC 2008 Programming 5JJ70 pg 7 .Getting all this stuff ‡ We·ve collected all tools you need in a single (BIG) file 176MByte file.

© PG/HC 2008 Programming 5JJ70 pg 8 . ‡ The distribution contains a GNU Unix environment called cygwin. ‡ This is a command-line shell. ‡ cd /cygdrive/<drivename> to get to the windows disks.cygwin ‡ Some of the programs we use (LCC. the MIPS assembler) are written as UNIX tools.

.2/lcc/lccdir assembler program $ ls -l mips-as.out run the disassembler © PG/HC 2008 Programming 5JJ70 pg 9 .Getting around in cygwin Type UNIX commands here Which directory am I? $ whoami henk / = the root $ pwd / list the directory $ ls bin cygwin.exe test..2/test run the assembler $ ls a.full usr go to the windows disk cygwin.log.out test. $ mkdir test $ cd test make a new subdirectory $ mips-as.exe -rwxr-xr-x 1 henk unknown 2472629 Nov 22 14:35 mips-as.bat etc include setup.log tmp var $ cd /cygdrive/c/Ogo1.exe $ PATH=/cygdrive/c/Ogo1.asm $ disas a.asm henk@HENK-LAP /cygdrive/c/Ogo1.ico home lib setup.2/lcc/lccdir:$PATH set the search path $ cd ./.

Circuit description in SystemC ‡ A number of hardware description languages exist: ² Verilog (USA) ² VHDL (Japan. not always) © PG/HC 2008 Programming 5JJ70 pg 10 . Europe) ² SystemC (newer) ²« ‡ They allow you to: ² Describe the logic and functionality ² Describe timing ² Describe parallelism (HW = parallel) ² Check the consistency ² Simulate ² Synthesize hardware (well.

This describes two issues: ²1 Circuit structure (schematic/functionality) ²2 Simulation settings ‡ Compiling and running it will perform the simulation. though it looks funny. ‡ SystemC is just C++ code. ‡ You write some C++ code using the classes.SystemC ‡ SystemC is a C++ library with class definitions. © PG/HC 2008 Programming 5JJ70 pg 11 .

. User User Module Module #N #N Event & Signa l I/F C++ Class Library Events Hardware Simulation Kernel (Event Scheduler) SystemC SystemC Executable Specification Executable Specification © PG/HC 2008 Programming 5JJ70 pg 12 ....SystemC and User Modules User User Module Module #1 #1 User User Module Module #2 #2 .

else return b. } Can we avoid this duplication by making the type a parameter? © PG/HC 2008 Programming 5JJ70 pg 13 . int r = 15. q = 12. } int maximum (int a. short b) { if(a > b) return a. } double maximum (double a. short maximum (short a. s = 1.0. else return b. but that have different data types.0. double b) { if(a > b) return a. int b) { if(a > b) return a. int b = maximum(r. q). else return b. } void main(void) { double p = 10.SystemC usesTemplates. s). let's have a look ‡ Often we need to use functions that are similar. double a = maximum(p.

else return b.0. } template <class T> T maximum (T a. and call that type T Declares T as a ¶variable· type void main(void) { double p = 10. q). int r = 15. and also harder to debug.Template functions in C++ ‡ Lets build a template. int b = maximum(r.0. double a = maximum(p. the compiler builds the routine for each class that is required. T b) { if(a > b) return a. ‡ This is a little heavy on the compiler. © PG/HC 2008 Programming 5JJ70 pg 14 . s = 1. } returns type T a and b are of type T Uses the integer type ‡ Behind the scenes. q = 12. s).

a. the compiler builds a separate code instance for each type that is required. } ~coordinate().2. } private: T _x. © PG/HC 2008 Programming 5JJ70 pg 15 .print(). } 1 . ³ << y << endl. coordinate <double> b(3. } void main(void) { coordinate <int> a(1. 2 3. T y) { _x = x. 6. b.2 .4).print(). _y = y.4 The class datamembers _x and _y of parameterized type T b is the double incarnation of coordinate. _y. ‡ Again. void print(void) { cout << x << ³ . 6. 2).Template classes in C++ ‡ The same can be done with classes! template <class T> class coordinate { public: coordinate(T x.

« } The word width W is the parameter void main(void) { sc_signal< sc_bv<32> > bus_mux1. ‡ I suggest to single-step through the example to get a feel for it. bool value). © PG/HC 2008 Programming 5JJ70 pg 16 . } Signal wires 32 bit vector ‡ The SystemC class structure is rather complicated. lrotate( int n ).SystemC class templates ‡ Lets look at an example: template <int W> class sc_bv : public sc_bv_base { public: sc_bv(). set_bit(int i.

} void or_process() { o. All systemC classes start with sc_ This sets up a class containing a module with a functionality.read() ). Calls read and write member functions of pins. }.h> SC_MODULE(OR2) { sc_in<bool> a. sensitive << a << b. // output pin o SC_CTOR(OR2) // the ctor { SC_METHOD(or_process).write( a. #include <systemc. sc_in<bool> b. This stuff is executed during construction of an µor2¶ object This is run to process the input pins. This object inherits all systemC properties of a pin.read() || b. 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. They carry boolean sygnals.A 2-input or-gate class in SystemC This include file contains all systemc functions and base classes. how this is actually implemented is hidden from us! Similarly. a OR b o // input pin a // input pin b Instantiates the input pins a and b. } .

‡ Then the simulation can be started. char *argv[]) { // 1: Instantiate gate objects « // 2: Instantiate signal objects « // 3: Connect the gates to signals « // 4: specify which values to print // 5: put values on signal objects // 6: Start simulator run } © PG/HC 2008 Programming 5JJ70 pg 18 ‡ First a data structure is built that describes the circuit.h´ // etc. int sc_main(int argc.h> #include ³and. ‡ This is a set of module (cell-)objects with attached pin objects.h´ #include ³or. ‡ Signal objects tie the pins together. ‡ The simulation needs: ² input values ² the list of pins that is to reported.SystemC program structure #include <systemc. ..

or8(³or8´). and5("and5"). OR3 or2(³or2´). AND3 and6("and6"). AND2 and3("and3"). Name stored INV inv9(³inv9´). in instance // « continued next page © PG/HC 2008 Programming 5JJ70 pg 19 . NOR2 nor7(³nor7").Step 1: make the gate objects OR1 AND3 NOR7 INV9 AND4 AND5 OR2 OR8 AND6 Instance name Module type // 1: instantiate the gate objects OR2 or1("or1"). and4("and4").

and_3. and_4. // input nets sc_signal<bool> CO. SUM. or_2. B. nor_7. and_6.Step 2: make the signal objects OR1 or_1 AND3 and_3 NOR7 nor_7 INV9 CO AND4 and_4 and_5 OR2 or_2 AND5 OR8 AND6 SUM A B CI and_6 Template class used for boolean Boolean signal // « continued from previous page // 2: instantiate the signal objects sc_signal<bool> A. // internal nets // « continued next page © PG/HC 2008 Programming 5JJ70 pg 20 . // internal nets sc_signal<bool> and_5. // output nets sc_signal<bool> or_1. CI.

b(B). nor7.b(B).a(A). or2.a(nor_7). or1.o(and_6). inv9.o(and_5).c(CI).o(and_3). or2. or2. inv9. and4.b(B).o(SUM).b(CI).b(B). // « continued next page © PG/HC 2008 Programming 5JJ70 pg 21 .a(nor_7). and3.b(and_6).b(and_4).c(CI). and6. or8. Signal net object and5. and5. and4.o(nor_7). and3. and6. and4. and5. nor7.a(or_1). and3.o(or_1). nor7.a(A).a(and_5). and6.a(and_3). or2. or8.o(and_4). or1.o(or_2).a(A).b(or_2).o(CO).a(A). or8.Step 3: Connecting pins of gates to signals or_1 OR1 AND3 NOR7 nor_7 AND4 and_4 INV9 CO and_3 and_5 AND5 OR2 A B CI or_2 OR8 AND6 SUM and_6 Gate instance object or2 // 3: Connect the gates to the signal nets pin object o or1. and6.

continued from previous page sc_initialize().. 0). CI=0. // generate all input combinations // // // // value of A is the bit0 of i value of B is the bit1 of i value of CI is the bit2 of i evaluate sc_close_vcd_trace_file(tf). "CO"). SUM. // initialize the simulation engine // create the file to store simulation results sc_trace_file *tf = sc_create_vcd_trace_file("trace"). for( int i = 0 . CO. // 5: put values on the input signals A=0. ³CI"). sc_trace(tf. B=0. B. sc_trace(tf. } // close file and we¶re done © PG/HC 2008 Programming 5JJ70 pg 22 . sc_trace(tf. // 4: specify the signals we¶d like to record in the trace file sc_trace(tf.Running the simulation // . // initialize the input values sc_cycle(10). 0). i < 8 { A = ((i & 0x1) != B = ((i & 0x2) != CI = ((i & 0x4) != sc_cycle(10). "B"). } . "A"). sc_trace(tf. i++ ) 0). CI. A. ³SUM").

Waveform viewer © PG/HC 2008 Programming 5JJ70 pg 23 .

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 } © PG/HC 2008 Programming 5JJ70 pg 24 .

sensitive << in1. selection. void doIt( void ). in2. © PG/HC 2008 Programming 5JJ70 pg 25 . selection } }. sensitive << selection. SC_CTOR( Mux21 ) { SC_METHOD( doIt ). out. sensitive << in2.A Mux 2:1 module SC_MODULE( Mux21 ) { sc_in< sc_uint<8> > sc_in< sc_uint<8> > sc_in< bool > sc_out< sc_uint<8> > out in2 MUX in1 in1.

s. // Signals // Constructor : ³architecture´ SC_CTOR(filter) { // Sub-modules instantiation and mapping s1 = new sample (³s1´). q). c1->out(c). c1 = new coeff(³c1´). c. (*m1)(s. // Positional mapping } } © PG/HC 2008 Programming 5JJ70 pg 26 Example: 'filter' . c. coeff *c1. s1->din(q). // named mapping m1 = new mult (³m1´). mult *m1. // named mapping s1->dout(s). sc_signal<sc_uint <32> > q.Submodules and Connections SC_MODULE(filter) { // Sub-modules : ³components sample *s1.

clock value). 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). © PG/HC 2008 Programming 5JJ70 pg 27 .3 types of Processes ‡ Methods ² When activated. ‡ CThreads ² Activated by the clock pulse ² SC_CTHREAD(process_name.

‡ sensitive_neg with either ( ) or << operator ² Defines sensitivity to negative edge of Boolean signal or clock ² sensitive_neg << clk.Defining the Sensitivity List of a Process ‡ sensitive with the ( ) operator ² Takes a single port or signal as argument ² sensitive(sig1). ‡ sensitive_pos with either ( ) or << operator ² Defines sensitivity to positive edge of Boolean signal or clock ² sensitive_pos << clk. sensitive(sig2). sensitive(sig3). ‡ sensitive with the stream notation ² Takes an arbitrary number of arguments ² sensitive << sig1 << sig2 << sig3. © PG/HC 2008 Programming 5JJ70 pg 28 .

q. } else if (count) { value++. } wait(). } } Repeat forever Wait till next event ! © PG/HC 2008 Programming 5JJ70 pg 29 .An Example of an SC_THREAD void do_count() { while(1) { if(reset) { value = 0.write(value).

Thread Processes: wait( ) Function ‡ wait( ) may be used in both SC_THREAD and SC_CTHREAD processes but not in SC_METHOD process block ‡ wait( ) suspends execution of the process until the process is invoked again ‡ wait(<pos_int>) may be used to wait for a certain number of cycles (SC_CTHREAD only) ‡ In Synchronous process (SC_CTHREAD) ² Statements before the wait( ) are executed in one cycle ² Statements after the wait( ) executed in the next cycle ‡ In Asynchronous process (SC_THREAD) ² Statements before the wait( ) are executed in the last event ² Statements after the wait( ) are executed in the next even © PG/HC 2008 Programming 5JJ70 pg 30 .

sc_in<sc_uint<3> > in_a. } }.write(in_b.read()). © PG/HC 2008 Programming 5JJ70 pg 31 . sensitive << clock. wait().read()).SC_THREAD Example SC_MODULE(my_module) { sc_in<bool> id. sc_in<bool> clock.write(in_a. else out_c. SC_CTOR(my_module) { SC_THREAD(my_thread). } }. sc_out<sc_uint<3> > out_c. void my_thread().pos().read()) out_c.cpp void my_module:: my_thread() { while(true) { if (id. sc_in<sc_uint<3> > in_b. Thread implementation: //my_module.

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 .

// Constructor: SC_CTOR(countsub) { // Declare addsub as SC_METHOD SC_METHOD(addsub).read(). sc_out<double> diff. a = in1. in1 in2 clk adder subtractor sum diff © PG/HC 2008 Programming 5JJ70 pg 33 . } }. //Definition of addsub method void countsub::addsub() { double a. sc_out<double> sum. // make it sensitive to // positive clock sensitive_pos << clk. diff. sc_in<double> in2. void addsub(). b = in2.Counter in SystemC SC_MODULE(countsub) { sc_in<double> in1. sum.read(). sc_in<bool> clk.write(a+b). }.write(a-b). double b.

OUT or INOUT ‡ Signals are used to connect module ports allowing modules to communicate ‡ Similar to ports and signals in VHDL © PG/HC 2008 Programming 5JJ70 pg 34 .Ports and Signals ‡ Ports of a module are the external interfaces that pass information to and from a module ‡ In SystemC one port can be IN.

Ports and Signals ‡ Types of ports and signals: ² All natives C/C++ types ² All SystemC types ² User defined types ‡ How to declare ² IN : ² OUT : ² Bi-Directional : sc_in<port_typ> sc_out<port_type> sc_inout<port_type> © PG/HC 2008 Programming 5JJ70 pg 35 .

write(out_temp).read( ). ² out. ‡ Examples: ² in_tmp = in. //reads the port in to in_tmp //writes out_temp in the out port © PG/HC 2008 Programming 5JJ70 pg 36 . and write( ).Ports and Signals ‡ How to read and write a port ? ² Methods read( ).

offset. initial_value ). //where f1 is a module © PG/HC 2008 Programming 5JJ70 pg 37 .Clocks ‡ Special object ‡ How to create ? sc_clock clock_name ( ´clock_labelµ. period. duty_ratio.clk( clk_signal ). ‡ Clock connection f1.

·1·) ² 4 values (¶0·.·Z·.·1·.·X·) ² Arbitrary size integer (Signed/Unsigned) ² Fixed point types © PG/HC 2008 Programming 5JJ70 pg 38 .Data Types ‡ SystemC supports: ² all C/C++ native types ² plus specific SystemC types ‡ SystemC types ² Types for systems modelling ² 2 values (¶0·.

SC_LOGIC type ‡ More general than bool. ¶X· (undefined) . ² my_logic = ¶Z·. © PG/HC 2008 Programming 5JJ70 pg 39 . ¶1· (true). ‡ Simulation time bigger than bool ‡ Operators like bool ‡ Declaration ² sc_logic my_logic. 4 values : ² (¶0· (false). ¶Z·(high-impedance) ) ‡ Assignment like bool ² my_logic = ¶0·.

signed integer with n-bits ² sc_uint<n> -.unsigned integer with n-bits © PG/HC 2008 Programming 5JJ70 pg 40 .Fixed precision integers ‡ Used when arithmetic operations need fixed size arithmetic operands ‡ INT can be converted in UINT and vice-versa ‡ ´intµ in C++ ² The size depends on the machine ² Faster in the simulation ‡ 1-64 bits integer in SystemC ² sc_int<n> -.

Arbitrary precision integers ‡ Integer bigger than 64 bits ² sc_bigint<n> ² sc_biguint<n> ‡ More precision. sc_uint © PG/HC 2008 Programming 5JJ70 pg 41 . slow simulation ‡ Can be used together with: ² Integer C++ ² sc_int.

Other SystemC types ‡ Bit vector ² sc_bv<n> ² 2-valued vector (0/1) ² Not used in arithmetics operations ² Faster simulation than sc_lv ‡ Logic Vector ² sc_lv<n> ² Vector of the 4-valued sc_logic type ‡ Assignment operator (´=´) ² my_vector = ´XZ01µ ² Conversion between vector and integer (int or uint) ² Assignment between sc_bv and sc_lv © PG/HC 2008 Programming 5JJ70 pg 42 .

SystemC types overview Type sc_logic sc_int sc_uint sc_bigint sc_biguint sc_bv sc_lv sc_fixed sc_ufixed sc_fix sc_ufix 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 © PG/HC 2008 Programming 5JJ70 pg 43 .

Examples of use of SystemC types sc_bit y. result = databus. sc_bv<8> y. sc_logic result. cout << ³bus = ³ << bus2. © PG/HC 2008 Programming 5JJ70 pg 44 . sc_bv<16> x. sc_lv<32> bus2. y = x[6]. sc_bv<64> databus. sc_bv<8> x.or_reduce(). y = x.7).range(0.to_string().

void proc_half_adder().Example ² Half adder #include ³systemc. } }.h´ SC_MODULE(half_adder) { sc_in<bool> a. SC_CTOR(half_adder) { SC_METHOD (proc_half_adder). carry. b. } a sum half-adder b carry © PG/HC 2008 Programming 5JJ70 pg 45 . sc_out<bool>sum. sensitive << a << b. carry = a & b. void half_adder::proc_half_adder() { sum = a ^ b.

SC_CTOR(full_adder) { ha1. carry_in.a(a).b(b). sc_out<bool>sum. c2) SC_METHOD (proc_or). s2. void proc_or(). half_adder ha1(³ha1´). sensitive << c1 << c2. carry_in. sc_signal<bool>c1. b. h2(s1. sum. ha2(³ha2´). carry_out. ha1. c2.Describing Hierarchy: Full adder #include ³half_adder.h´ SC_MODULE (full_adder) { sc_in<bool>a. } }. a a sum sum half-adder ha1 b b carry a sum half-adder ha2 carry_in b carry //by name connection //by position connection © PG/HC 2008 Programming 5JJ70 pg 46 . ha1.carry(c1). ha1.sum(s1).

pg_ptr->d_b(t_b).Top Module sum #Include ³full_adder. return 0.h´ #Include ³pattern_gen. sc_start(100. mo1 << t_a << t_b << t_cin << t_sum << t_cout.Main --. t_b. SC_NS). char* argv[]) { sc_signal<booL> t_a. t_cin.h´ #include ³monitor. //connection using named association pg_ptr->d_a(t_a). } Pattern_gen © PG/HC 2008 Programming 5JJ70 pg 47 . t_cout. t_sum. pattern_gen pg_ptr = new pattern_gen(³Generation´).h´ a Full_adder carry b c_in Monitor int sc_main(int argc. monitor mol(³Monitor´). //connect using positional association f1 << t_a << t_b << t_cin << t_sum << t_cout. full_adder f1(³Fulladder´). (*pg_ptr->d_cin(t_cin).

Unresolved signals ² Rich set of port and signal types ² Rich set of data types ‡ All C/C++ types. 32/64-bit signed/unsigned. fixedpoints. user defined © PG/HC 2008 Programming 5JJ70 pg 48 . out). Event sensitivity ² Ports ‡ Single-directional(in.SystemC Highlights Summary (1) ‡ Support Hardware-Software Co-Design ‡ Interface in a C++ environment ² Modules ‡ Container class includes hierarchical Entity and Processes ² Processes ‡ Describe functionality. MVL. Bi-directional(inout) mode ² Signals ‡ Resolved.

Timekeeper of simulation and Multiple clocks. with arbitrary phase relationship ² Cycle-based simulation ‡ High-Speed Cycle-Based simulation kernel ² Multiple abstraction levels ‡ Untimed from high-level functional model to detailed clock cycle accuracy RTL model ² Communication Protocols ² Debugging Supports ‡ Run-Time error check ² Waveform Tracing © PG/HC 2008 Programming 5JJ70 pg 49 .SystemC Highlights Summary (2) ‡ Interface in a C++ environment (continued) ² Clocks ‡ Special signal.