Starting from:

$29.99

LAB 6 Datapath part of the processor

Introduction to Digital Logic Design Lab
EECS 31L
LAB 6
Through this course, we want to design a RISC-V Single Cycle Processor. Here in this Lab, we will
work on the Datapath part of the processor. Part 1 reviews some information from Verilog regarding the
design hierarchies. In Part 2, we review the RISC-V datapath. In part 3 we talk about how to design
the data memory and in part 4 we talk about designing the datapath (as a top module) and in part 5
we test the datapath.
1 Manage Design Hierarchies with Component Declaration
This section shows you how to use partitioning and design management to manage larger design.
Hierarchy is a way of managing a design by creating references to external, lower-level design modules
from within a higher-level design module. The basic unit of hierarchy in Verilog is the component. A
component is a Verilog module that is referenced as a lower-level module from another, higher-level
module. A Verilog design (a particular module/architecture pair) can be referenced from another architecture as a Verilog component. Instantiating components within another design provides a mechanism
for partitioned design, or for using existing designs as reusable components of larger designs.
Figure 1 : Hierarchy and Components.
1
2 Datapath
Figure 2 : RISC-V Datapath.
Figure 2 shows the datapath of a RISC-V single cycle processor. The instruction execution starts by
using the program counter to supply the instruction address to the instruction memory. After the instruction is fetched, the register operands used by an instruction are specified by fields of that instruction.
Once the register operands have been fetched, they can be operated on to compute a memory address
(for a load or store), to compute an arithmetic result (for an integer arithmetic-logical instruction), or
an equality check (for a branch). If the instruction is an arithmetic-logical instruction, the result from
the ALU must be written to a register. If the operation is a load or store, the ALU result is used as an
address to either store a value from the registers or load a value from memory into the registers. The
result from the ALU or memory is written back into the register file. The blue lines interconnecting
the functional units represent buses, which consist of multiple signals. The arrows are used to guide the
reader in knowing how information flows. Since signal lines may cross, we explicitly show when crossing
lines are connected by the presence of a dot where the lines cross.
Some of the inputs (RegWrite, ALUSrc, ALUCC, MemRead, MemWrite, MemtoReg) are control signals
which are derived by a module named ”Control”. The control unit is supposed to be designed later and
here in this lab you assume you have all the control signals as inputs.
Table 1 shows the list of Instructions that our Datapath supports.
Table 1 : Instruction Set.
Note: along with the provided instructions in Table 1, your datapath needs to support "lw" and
"sw" instructions too. Table 2 and 3 shows format of these two data-transfer instructions.
2
Table 2 : Instruction Set (lw).
Table 3 : Instruction Set (sw).
For this part, you need to save these two instructions into the ”Instruction memory” that you designed in previous lab. The following two commands will write these two instructions into the instruction
memory:
memory[18] = 32’h02b02823; // sw r11, 48(r0) alu result = 32’h00000030
memory[19] = 32’h03002603; // lw r12, 48(r0) alu result = 32’h00000030 r12 = 32’h00000005
3 Lower Level Modules
As it is shown in Figure 2, there is a top module (Datapath) and nine lower-level modules (FlipFlop,
HA, Instr mem, RegFile, Imm Gen, Mux (two instantiations), ALU, data mem). You have already designed four lower-modules such as FlipFlop, Inst mem,RegFile, and ALU. As it was mentioned in Lab
5, HA module can be easily implemented in Verliog using ”+” operation (simply adding PC with value
4: PC Next = PC + 4). Imm Gen and Mux designs also provided for you in Lab 5.
In this lab, we start by designing the last sub-module which is Data mem.
Note: 32-bit ALU design is also provided for you in section 3.3. You are welcome to use your own ALU
design , if your design got the full credit.
3.1 Data Memory
Same as the Instruction memory (refer to the previous lab), the data memory in our processor is byte
addressable. We can store 128 data each with 32 bits (128 x 32). To address 128 x 4 = 512 bytes 9 bits
are required for address line. These 9-bits come from the 9 LSBs of the output of the ALU (ALU Result).
To read a data we need an address and the read enable signal (MemRead). To write a data we need an
address, the write enable signal (MemWrite), and a data to write (Write data).
addr
Note: Use the provided module definition to design your Data Memory. Otherwise, your submission
will not be considered for grading.
3
Code 1: Data Memory
1 ‘timescale 1ns / 1ps
2 // Module definition
3 module DataMem ( MemRead , MemWrite , addr , write_data , read_data );
4 // Define I/O ports
5
6
7 // Describe data_mem behaviour
8
9
10 endmodule // data_mem
3.1.1 Result Mux
The MUX on the output of the Data Memory will decide whether the writing data (to the register file)
should come from the ALU or come from the Data Memory (refer to Figure 2). You can use 2-to-1 Mux
design from Lab 5.
3.2 Immediate Generator
Use the code provided in Lab 5.
3.3 32-bit ALU
Code 2: 32-bit ALU
1 module alu_32 (
2 input [ 31 : 0 ] A_in ,B_in , // ALU 32 bit inputs
3 input [ 3 : 0 ] ALU_Sel , // ALU 4 bits selection
4 output [ 31 : 0 ] ALU_Out , // ALU 32 bits output
5 output reg Carry_Out ,
6 output Zero , // 1 bit Zero Flag
7 output reg Overflow = 1 ’b0 // 1 bit Overflow flag
8 );
9 reg [ 31 : 0 ] ALU_Result ;
10 reg [ 32 : 0 ] temp ;
11 reg [ 32 : 0 ] twos_com ; // to hold 2 ’sc of second source of ALU
12
13 assign ALU_Out = ALU_Result ; // ALU Out
14 assign Zero = ( ALU_Result == 0); // Zero Flag
15
16 always @ (*)
17 begin
18 Overflow = 1 ’b0;
19 Carry_Out = 1 ’b0;
20 case ( ALU_Sel )
21 4 ’ b0000 : // and
22 ALU_Result = A_in & B_in ;
23
24 4 ’ b0001 : // or
25 ALU_Result = A_in | B_in ;
26
27 4 ’ b0010 : // Signed Addition with Overflow and Carry_out checking
28 begin
29 ALU_Result = $signed ( A_in ) + $signed ( B_in );
30 temp = {1 ’b0 , A_in } + {1 ’b0 , B_in };
31 Carry_Out = temp [ 32 ] ;
4
32 if (( A_in [ 31 ] & B_in [ 31 ] & ~ ALU_Out [ 31 ] ) |
33 (~ A_in [ 31 ] & ~ B_in [ 31 ] & ALU_Out [ 31 ] ))
34 Overflow = 1 ’b1;
35 else
36 Overflow = 1 ’b0;
37 end
38
39 4 ’ b0110 : // Signed Subtraction with Overflow checking
40 begin
41 ALU_Result = $signed ( A_in ) - $signed ( B_in ) ;
42 twos_com = ~( B_in ) + 1 ’b1;
43 if (( A_in [ 31 ] & twos_com [ 31 ] & ~ ALU_Out [ 31 ] ) |
44 (~ A_in [ 31 ] & ~ twos_com [ 31 ] & ALU_Out [ 31 ] ))
45 Overflow = 1 ’b1;
46 else
47 Overflow = 1 ’b0;
48 end
49
50 4 ’ b0111 : // Signed less than comparison
51 ALU_Result = ( $signed ( A_in ) < $signed ( B_in ))?32 ’ d1: 32 ’ d0;
52
53 4 ’ b1100 : // nor
54 ALU_Result = ~( A_in | B_in );
55
56 4 ’ b1111 : // Equal comparison
57 ALU_Result = ( A_in == B_in )?32 ’ d1: 32 ’ d0 ;
58
59 default : ALU_Result = A_in + B_in ;
60 endcase
61 end
62
63 endmodule
4 Higher Level Module
Now that we have designed all of the submodules, we can use them as a component and design the
Datapath. Here again, you see the Datapath. Blue lines are some wires which we used to connect the
submodules. Define these blue lines as ”wire” and connect the components to complete the Datapath.
Note: In data memory design (which is a top module), you need to instantiate from each sub module
and make wire connections as it is shown in the figure bellow.
5
Note: For Datapath code, we used lowercase letters for input/output naming. You need to use
the exact code samples provided for you to design the Datapath and tb Datapath. Otherwise, your
submission will not be considered for grading.
Use the following code for the module definition of your Datapath.
Code 3: Datapath
1 module data_path #(
2 parameter PC_W = 8 , // Program Counter
3 parameter INS_W = 32 , // Instruction Width
4 parameter RF_ADDRESS = 5 , // Register File Address
5 parameter DATA_W = 32 , // Data WriteData
6 parameter DM_ADDRESS = 9 , // Data Memory Address
7 parameter ALU_CC_W = 4 // ALU Control Code Width
8 )(
9 input clk , // CLK in Datapath figure
10 input reset , // Reset in Datapath figure
11 input reg_write , // RegWrite in Datapath figure
12 input mem2reg , // MemtoReg in Datapath figure
13 input alu_src , // ALUSrc in Datapath figure
14 input mem_write , // MemWrite in Datapath Figure
15 input mem_read , // MemRead in Datapath Figure
16 input [ ALU_CC_W -1 : 0 ] alu_cc , // ALUCC in Datapath Figure
17 output [ 6 : 0 ] opcode , // opcode in Datapath Figure
18 output [ 6 : 0 ] funct7 , // Funct7 in Datapath Figure
19 output [ 2 : 0 ] funct3 , // Func3 in Datapath Figure
20 output [ DATA_W -1 : 0 ] alu_result // Datapath_Result in Datapath Figure
21 );
22
23 // Write your code here
24
25
26 endmodule // Datapath
Important: we want you to have separate source files for each of the datapath submodules. As you
can see in the picture bellow, in the ”Design Sources” section, all the submodules are included along with
data path design (data path is the top module and other modules listed bellow it are the submodules in
the design).
Note: In this picture, you don’t see any submodule design for MUX, since MUX is designed with
another method using Verilog statements. You can use the provided sample code for MUX (in Lab 5),
6
and in this case, you also need to include MUX source code in ”Design Sources” section.
5 Test the Datapath
Use the provided test-bench to test your Datapath design.
Code 4: tb Datapath
1 module dp_tb_top ();
2
3 /** Clock & reset **/
4 reg clk , rst ;
5 always begin
6 #10;
7 clk = ~clk;
8 end
9
10 initial begin
11 clk = 0;
12 @( posedge clk );
13 rst = 1;
14 @( posedge clk );
15 rst = 0;
16 end
17
18 /** DUT Instantiation **/
19 wire reg_write ;
20 wire mem2reg ;
21 wire alu_src ;
22 wire mem_write ;
23 wire mem_read ;
24 wire [ 3 : 0 ] alu_cc ;
25 wire [ 6 : 0 ] opcode ;
26 wire [ 6 : 0 ] funct7 ;
27 wire [ 2 : 0 ] funct3 ;
28 wire [ 31 : 0 ] alu_result ;
7
29
30 data_path dp_inst (
31 .clk ( clk ) ,
32 . reset ( rst ) ,
33 . reg_write ( reg_write ) ,
34 . mem2reg ( mem2reg ) ,
35 . alu_src ( alu_src ) ,
36 . mem_write ( mem_write ) ,
37 . mem_read ( mem_read ) ,
38 . alu_cc ( alu_cc ) ,
39 . opcode ( opcode ) ,
40 . funct7 ( funct7 ) ,
41 . funct3 ( funct3 ) ,
42 . alu_result ( alu_result )
43 );
44
45 /** Stimulus **/
46 wire [ 6 : 0 ] R_TYPE , LW , SW , RTypeI ;
47
48 assign R_TYPE = 7 ’ b0110011 ;
49 assign LW = 7 ’ b0000011 ;
50 assign SW = 7 ’ b0100011 ;
51 assign RTypeI = 7 ’ b0010011 ;
52
53
54 assign alu_src = ( opcode == LW || opcode == SW || opcode == RTypeI );
55 assign mem2reg = ( opcode == LW );
56 assign reg_write = ( opcode == R_TYPE || opcode == LW || opcode == RTypeI );
57 assign mem_read = ( opcode == LW );
58 assign mem_write = ( opcode == SW );
59
60 assign alu_cc = (( opcode == R_TYPE || opcode == RTypeI )
61 && ( funct7 == 7 ’ b0000000 ) && ( funct3 == 3 ’ b000 )) ? 4 ’ b0010 :
62 (( opcode == R_TYPE || opcode == RTypeI )
63 && ( funct7 == 7 ’ b0100000 )) ? 4 ’ b0110 :
64 (( opcode == R_TYPE || opcode == RTypeI )
65 && ( funct7 == 7 ’ b0000000 ) && ( funct3 == 3 ’ b100 )) ? 4 ’ b1100 :
66 (( opcode == R_TYPE || opcode == RTypeI )
67 && ( funct7 == 7 ’ b0000000 ) && ( funct3 == 3 ’ b110 )) ? 4 ’ b0001 :
68 (( opcode == R_TYPE || opcode == RTypeI )
69 && ( funct7 == 7 ’ b0000000 ) && ( funct3 == 3 ’ b111 )) ? 4 ’ b0000 :
70 (( opcode == R_TYPE || opcode == RTypeI )
71 && ( funct7 == 7 ’ b0000000 ) && ( funct3 == 3 ’ b010 )) ? 4 ’ b0111 :
72 (( opcode == R_TYPE || opcode == RTypeI )
73 && ( funct3 == 3 ’ b100 )) ? 4 ’ b1100 :
74 (( opcode == R_TYPE || opcode == RTypeI )
75 && ( funct3 == 3 ’ b110 )) ? 4 ’ b0001 :
76 (( opcode == R_TYPE || opcode == RTypeI )
77 && ( funct3 == 3 ’ b010 )) ? 4 ’ b0111 :
78 (( opcode == LW || opcode == SW)
79 && ( funct3 == 3 ’ b010 ))? 4 ’ b0010 : 0;
80
81 initial begin
82 #420;
83 $finish ;
84 end
85
86 endmodule
8
Check the outputs (opcode, funct3, funct7, alu result) to see if they are correct. Put a screenshot of
the wave in your report.
Here you can see screenshot of the waveform for the datapath design:
6 Assignment Deliverable
Your submission should include the following:
• Block designs and testbenches. (FlipFlop.v, Instr mem.v, RegFile.v, Imm Gen.v, Mux.v, ALU.v,
Data mem.v, Datapath.v. tb Datapath.v)
• If you designed a HA module to perform PC + 4 operation, you need to include it in your submission
files. Otherwise (in case of using simple ”PC Next = PC + 4”), no need to submit any design
code for HA module.
• A report in pdf format. Your report should have all details for your design + screenshot of the
wave. Each report should include group members if your are working as a group.
Note1: Compress all files (.v files + report) into zip and upload to the Beachboard Dropbox before
deadline.
Note2: Use the code samples that are given in the lab description. The module part of your code
should exactly look like the code sample otherwise your submission will not be considered
for grading..
9

More products