eel3792c_rv32i

RV32I implementation on a DE10-Lite FPGA for the EEL3792C course.
Log | Files | Refs

riscvsingle.sv (14127B)


      1 // riscvsingle.sv
      2 
      3 // RISC-V single-cycle processor
      4 // From Section 7.6 of Digital Design & Computer Architecture
      5 // 27 April 2020
      6 // David_Harris@hmc.edu 
      7 // Sarah.Harris@unlv.edu
      8 
      9 // run 210
     10 // Expect simulator to print "Simulation succeeded"
     11 // when the value 25 (0x19) is written to address 100 (0x64)
     12 
     13 // Single-cycle implementation of RISC-V (RV32I)
     14 // User-level Instruction Set Architecture V2.2 (May 7, 2017)
     15 // Implements a subset of the base integer instructions:
     16 //    lw, sw
     17 //    add, sub, and, or, slt, 
     18 //    addi, andi, ori, slti
     19 //    beq
     20 //    jal
     21 // Exceptions, traps, and interrupts not implemented
     22 // little-endian memory
     23 
     24 // 31 32-bit registers x1-x31, x0 hardwired to 0
     25 // R-Type instructions
     26 //   add, sub, and, or, slt
     27 //   INSTR rd, rs1, rs2
     28 //   Instr[31:25] = funct7 (funct7b5 & opb5 = 1 for sub, 0 for others)
     29 //   Instr[24:20] = rs2
     30 //   Instr[19:15] = rs1
     31 //   Instr[14:12] = funct3
     32 //   Instr[11:7]  = rd
     33 //   Instr[6:0]   = opcode
     34 // I-Type Instructions
     35 //   lw, I-type ALU (addi, andi, ori, slti)
     36 //   lw:         INSTR rd, imm(rs1)
     37 //   I-type ALU: INSTR rd, rs1, imm (12-bit signed)
     38 //   Instr[31:20] = imm[11:0]
     39 //   Instr[24:20] = rs2
     40 //   Instr[19:15] = rs1
     41 //   Instr[14:12] = funct3
     42 //   Instr[11:7]  = rd
     43 //   Instr[6:0]   = opcode
     44 // S-Type Instruction
     45 //   sw rs2, imm(rs1) (store rs2 into address specified by rs1 + immm)
     46 //   Instr[31:25] = imm[11:5] (offset[11:5])
     47 //   Instr[24:20] = rs2 (src)
     48 //   Instr[19:15] = rs1 (base)
     49 //   Instr[14:12] = funct3
     50 //   Instr[11:7]  = imm[4:0]  (offset[4:0])
     51 //   Instr[6:0]   = opcode
     52 // B-Type Instruction
     53 //   beq rs1, rs2, imm (PCTarget = PC + (signed imm x 2))
     54 //   Instr[31:25] = imm[12], imm[10:5]
     55 //   Instr[24:20] = rs2
     56 //   Instr[19:15] = rs1
     57 //   Instr[14:12] = funct3
     58 //   Instr[11:7]  = imm[4:1], imm[11]
     59 //   Instr[6:0]   = opcode
     60 // J-Type Instruction
     61 //   jal rd, imm  (signed imm is multiplied by 2 and added to PC, rd = PC+4)
     62 //   Instr[31:12] = imm[20], imm[10:1], imm[11], imm[19:12]
     63 //   Instr[11:7]  = rd
     64 //   Instr[6:0]   = opcode
     65 
     66 //   Instruction  opcode    funct3    funct7
     67 //   add          0110011   000       0000000
     68 //   sub          0110011   000       0100000
     69 //   and          0110011   111       0000000
     70 //   or           0110011   110       0000000
     71 //   slt          0110011   010       0000000
     72 //   addi         0010011   000       immediate
     73 //   andi         0010011   111       immediate
     74 //   ori          0010011   110       immediate
     75 //   slti         0010011   010       immediate
     76 //   beq          1100011   000       immediate
     77 //   lw	         0000011   010       immediate
     78 //   sw           0100011   010       immediate
     79 //   jal          1101111   immediate immediate
     80 
     81 
     82 // This part is modified by Dr.Toker
     83 module my_computer(input  logic        clk, reset, 
     84 			  input  logic[ 9:0] my_sw,
     85 			  output logic[31:0] my_rd,
     86 			  output logic[31:0] my_PC
     87 );
     88 
     89   logic [31:0] PC, Instr, ReadData, WriteData, DataAddr;
     90   logic MemWrite;
     91   
     92   // instantiate processor 
     93   riscvsingle rvsingle(clk, reset, PC, Instr, MemWrite, DataAddr, 
     94                        WriteData, ReadData);
     95   // program memory - ROM
     96   imem imem(PC, Instr);
     97   
     98   // data memort - RAM
     99   dmem dmem(clk, MemWrite, DataAddr, WriteData, ReadData, my_sw, my_rd);
    100   
    101   assign my_PC = PC;
    102 
    103    always_ff @(posedge clk)
    104      $display("PC: %x", PC);
    105 endmodule
    106 
    107 // =======================================================================
    108 // NEW STUFF ABOUT MEMORIES - MUST REVIEW FIRST
    109 // =======================================================================
    110 
    111 module regfile(input  logic        clk, 
    112                input  logic        we3, 
    113                input  logic [ 4:0] a1, a2, a3,
    114                input  logic [31:0] wd3, 
    115                output logic [31:0] rd1, rd2);
    116 
    117   logic [31:0] rf[31:0];
    118 
    119   // three ported register file
    120   // read two ports combinationally (A1/RD1, A2/RD2)
    121   // write third port on rising edge of clock (A3/WD3/WE3)
    122   // register 0 hardwired to 0
    123 
    124   always_ff @(posedge clk)
    125     if (we3) rf[a3] <= wd3;	
    126 
    127   assign rd1 = (a1 != 0) ? rf[a1] : 0;
    128   assign rd2 = (a2 != 0) ? rf[a2] : 0;
    129 endmodule
    130  
    131 module imem(input  logic [31:0] a,
    132             output logic [31:0] rd);
    133 
    134   logic [31:0] ROM[127:0];
    135 
    136   // Initialize the program memory
    137   // Simulator : ok
    138   // Hardware  : For FPGA ok, non-FPGA we need a 3rd party solution to program the FLASH memory (ROM)
    139   initial
    140       $readmemh("/home/vin/src/public/eel3792c_rv32i/riscvtest_rom_image.txt", ROM);
    141 
    142   assign rd = ROM[a[31:2]]; // word aligned
    143 endmodule
    144 
    145 // This part is modified by Dr. Toker
    146 module dmem(input  logic        clk, we,
    147             input  logic [31:0] a, wd,
    148             output logic [31:0] rd,
    149 				input  logic [ 7:0] my_sw,
    150 				output logic [31:0] my_rd);
    151 
    152   logic [31:0] RAM[255:0];
    153 
    154   assign rd = RAM[a[31:2]]; // word aligned
    155 
    156   always_ff @(posedge clk)
    157   begin
    158     if (we) RAM[a[31:2]] <= wd;
    159 	 
    160 	 // Used only for simulation, does not correspond to ANY hardware
    161 	 if (we)
    162 		$display("Write RAM[%08x]=%08x at %t", a[31:2], wd, $time);
    163 	 else
    164 		$display("Read  RAM[%08x]=%08x at %t", a[31:2], rd, $time);	
    165 		
    166   end
    167   
    168   assign my_rd = RAM[my_sw[7:2]];
    169   
    170   // Initialize the program memory
    171   // Simulator : ok
    172   // Hardware  : For FPGA ok, non-FPGA we need a 3rd party solution to program the DATA memory (RAM)
    173   initial
    174       $readmemh("/home/vin/src/public/eel3792c_rv32i/riscvtest_ram_image.txt", RAM);  
    175   
    176 endmodule
    177  
    178 module flopr #(parameter WIDTH = 8)
    179               (input  logic             clk, reset,
    180                input  logic [WIDTH-1:0] d, 
    181                output logic [WIDTH-1:0] q);
    182 
    183   always_ff @(posedge clk, posedge reset)
    184     if (reset) q <= 0;
    185     else       q <= d;
    186 endmodule
    187   
    188 // =======================================================================
    189 // OLD STUFF - Component Instantiation or New Combinatorial Designs
    190 // =======================================================================
    191 
    192 module riscvsingle(input  logic        clk, reset,
    193                    output logic [31:0] PC,
    194                    input  logic [31:0] Instr,
    195                    output logic        MemWrite,
    196                    output logic [31:0] ALUResult, WriteData,
    197                    input  logic [31:0] ReadData);
    198 
    199   logic       ALUSrc, RegWrite, Jump, Zero;
    200   logic [1:0] ResultSrc, ImmSrc;
    201   logic [3:0] ALUControl;
    202 
    203   controller c(Instr[6:0], Instr[14:12], Instr[30], Zero,
    204                ResultSrc, MemWrite, PCSrc,
    205                ALUSrc, RegWrite, Jump,
    206                ImmSrc, ALUControl);
    207   datapath dp(clk, reset, ResultSrc, PCSrc,
    208               ALUSrc, RegWrite,
    209               ImmSrc, ALUControl,
    210               Zero, PC, Instr,
    211               ALUResult, WriteData, ReadData);
    212 endmodule
    213 
    214 module controller(input  logic [6:0] op,
    215                   input  logic [2:0] funct3,
    216                   input  logic       funct7b5,
    217                   input  logic       Zero,
    218                   output logic [1:0] ResultSrc,
    219                   output logic       MemWrite,
    220                   output logic       PCSrc, ALUSrc,
    221                   output logic       RegWrite, Jump,
    222                   output logic [1:0] ImmSrc,
    223                   output logic [3:0] ALUControl);
    224 
    225   logic [1:0] ALUOp;
    226   logic       Branch;
    227 
    228   maindec md(op, ResultSrc, MemWrite, Branch,
    229              ALUSrc, RegWrite, Jump, ImmSrc, ALUOp);
    230   aludec  ad(op[5], funct3, funct7b5, ALUOp, ALUControl);
    231 
    232 //  assign PCSrc = Branch & Zero | Jump;
    233   always_comb
    234     if (Branch)
    235        case (funct3)
    236 	 3'b000: PCSrc = Zero;  // beq
    237 	 3'b001: PCSrc = ~Zero; // bne
    238 	 3'b100: PCSrc = Zero; // blt
    239 	 3'b101: PCSrc = ~Zero; // blt
    240 	 default: PCSrc = 1'bx;
    241        endcase
    242     else
    243       PCSrc = Jump;
    244 endmodule
    245 
    246 module maindec(input  logic [6:0] op,
    247                output logic [1:0] ResultSrc,
    248                output logic       MemWrite,
    249                output logic       Branch, ALUSrc,
    250                output logic       RegWrite, Jump,
    251                output logic [1:0] ImmSrc,
    252                output logic [1:0] ALUOp);
    253 
    254   logic [10:0] controls;
    255 
    256   assign {RegWrite, ImmSrc, ALUSrc, MemWrite,
    257           ResultSrc, Branch, ALUOp, Jump} = controls;
    258 
    259   always_comb
    260     case(op)
    261     // RegWrite_ImmSrc_ALUSrc_MemWrite_ResultSrc_Branch_ALUOp_Jump
    262       7'b0000011: controls = 11'b1_00_1_0_01_0_00_0; // lw
    263       7'b0100011: controls = 11'b0_01_1_1_00_0_00_0; // sw
    264       7'b0110011: controls = 11'b1_xx_0_0_00_0_10_0; // R-type 
    265       7'b1100011: controls = 11'b0_10_0_0_00_1_01_0; // B-type
    266       7'b0010011: controls = 11'b1_00_1_0_00_0_10_0; // I-type ALU
    267       7'b1101111: controls = 11'b1_11_0_0_10_0_00_1; // jal
    268       default:    controls = 11'bx_xx_x_x_xx_x_xx_x; // non-implemented instruction
    269     endcase
    270 endmodule
    271 
    272 module aludec(input  logic       opb5,
    273               input  logic [2:0] funct3,
    274               input  logic       funct7b5, 
    275               input  logic [1:0] ALUOp,
    276               output logic [3:0] ALUControl);
    277 
    278   logic  RtypeSub;
    279   assign RtypeSub = funct7b5 & opb5;  // TRUE for R-type subtract instruction
    280 
    281   always_comb
    282     case(ALUOp)
    283       2'b00:                ALUControl = 4'b0000; // addition
    284       2'b01:                ALUControl = {funct3[2], 3'b001}; // branching
    285       // (funct3[2] is used because it's set in blt/bge but not beq/bne
    286       default: case(funct3) // R-type or I-type ALU
    287                  3'b000:  if (RtypeSub) 
    288                             ALUControl = 4'b0001; // sub
    289                           else          
    290                             ALUControl = 4'b0000; // add, addi
    291 		 3'b001:    ALUControl = 4'b0110; // sll, slli
    292                  3'b010:    ALUControl = 4'b0101; // slt, slti
    293 		 3'b100:    ALUControl = 4'b0100; // xor, xori
    294 		 3'b101:  if (RtypeSub)
    295 		            ALUControl = 4'b1000; // sra, srai
    296 		          else
    297 		            ALUControl = 4'b0111; // srl, srli
    298                  3'b110:    ALUControl = 4'b0011; // or, ori
    299                  3'b111:    ALUControl = 4'b0010; // and, andi
    300                  default:   ALUControl = 4'bxxxx; // ???
    301                endcase
    302     endcase
    303 endmodule
    304 
    305 module datapath(input  logic        clk, reset,
    306                 input  logic [1:0]  ResultSrc, 
    307                 input  logic        PCSrc, ALUSrc,
    308                 input  logic        RegWrite,
    309                 input  logic [1:0]  ImmSrc,
    310                 input  logic [3:0]  ALUControl,
    311                 output logic        Zero,
    312                 output logic [31:0] PC,
    313                 input  logic [31:0] Instr,
    314                 output logic [31:0] ALUResult, WriteData,
    315                 input  logic [31:0] ReadData);
    316 
    317   logic [31:0] PCNext, PCPlus4, PCTarget;
    318   logic [31:0] ImmExt;
    319   logic [31:0] SrcA, SrcB;
    320   logic [31:0] Result;
    321 
    322   // next PC logic
    323   flopr #(32) pcreg(clk, reset, PCNext, PC); 
    324   adder       pcadd4(PC, 32'd4, PCPlus4);
    325   adder       pcaddbranch(PC, ImmExt, PCTarget);
    326   mux2 #(32)  pcmux(PCPlus4, PCTarget, PCSrc, PCNext);
    327  
    328   // register file logic
    329   regfile     rf(clk, RegWrite, Instr[19:15], Instr[24:20], 
    330                  Instr[11:7], Result, SrcA, WriteData);
    331   extend      ext(Instr[31:7], ImmSrc, ImmExt);
    332 
    333   // ALU logic
    334   mux2 #(32)  srcbmux(WriteData, ImmExt, ALUSrc, SrcB);
    335   alu         alu(SrcA, SrcB, ALUControl, ALUResult, Zero);
    336   mux3 #(32)  resultmux(ALUResult, ReadData, PCPlus4, ResultSrc, Result);
    337 endmodule
    338 
    339 
    340 module adder(input  [31:0] a, b,
    341              output [31:0] y);
    342 
    343   assign y = a + b;
    344 endmodule
    345 
    346 module extend(input  logic [31:7] instr,
    347               input  logic [1:0]  immsrc,
    348               output logic [31:0] immext);
    349  
    350   always_comb
    351     case(immsrc) 
    352                // I-type 
    353       2'b00:   immext = {{20{instr[31]}}, instr[31:20]};  
    354                // S-type (stores)
    355       2'b01:   immext = {{20{instr[31]}}, instr[31:25], instr[11:7]}; 
    356                // B-type (branches)
    357       2'b10:   immext = {{20{instr[31]}}, instr[7], instr[30:25], instr[11:8], 1'b0}; 
    358                // J-type (jal)
    359       2'b11:   immext = {{12{instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0}; 
    360       default: immext = 32'bx; // undefined
    361     endcase             
    362 endmodule
    363 
    364 module mux2 #(parameter WIDTH = 8)
    365              (input  logic [WIDTH-1:0] d0, d1, 
    366               input  logic             s, 
    367               output logic [WIDTH-1:0] y);
    368 
    369   assign y = s ? d1 : d0; 
    370 endmodule
    371 
    372 module mux3 #(parameter WIDTH = 8)
    373              (input  logic [WIDTH-1:0] d0, d1, d2,
    374               input  logic [1:0]       s, 
    375               output logic [WIDTH-1:0] y);
    376 
    377   assign y = s[1] ? d2 : (s[0] ? d1 : d0); 
    378 endmodule
    379 
    380 module alu(input  logic [31:0] a, b,
    381            input  logic [3:0]  alucontrol,
    382            output logic [31:0] result,
    383            output logic        zero);
    384 
    385   logic [31:0] condinvb, sum;
    386   logic        v;              // overflow
    387   logic        isAddSub;       // true when is add or subtract operation
    388 
    389   assign condinvb = alucontrol[0] ? ~b : b;
    390   assign sum = a + condinvb + alucontrol[0];
    391   assign isAddSub = ~alucontrol[2] & ~alucontrol[1] |
    392                     ~alucontrol[1] & alucontrol[0];
    393 
    394   always_comb
    395     case (alucontrol)
    396       4'b0000:  result = sum;         // add
    397       4'b0001:  result = sum;         // subtract
    398       4'b0010:  result = a & b;       // and
    399       4'b0011:  result = a | b;       // or
    400       4'b0100:  result = a ^ b;       // xor
    401       4'b0101:  result = sum[31] ^ v; // slt
    402       4'b0110:  result = a << b[4:0]; // sll
    403       4'b0111:  result = a >> b[4:0]; // srl
    404       4'b1000:  result = $signed(a) >>> b[4:0]; // srl
    405       default: result = 32'bx;
    406     endcase
    407 
    408    always_comb
    409      case (alucontrol)
    410        4'b1001: zero = a < b;             // blt and bge
    411        default: zero = (result == 32'b0); // beq and bne
    412      endcase
    413 
    414   assign v = ~(alucontrol[0] ^ a[31] ^ b[31]) & (a[31] ^ sum[31]) & isAddSub;
    415 endmodule