Home Projects Resume About

Project: Implementing a multistage pipelined RISCV architecture

Slide 1
Slide 2
Slide 3
Slide 4
Slide 5

Overview

Materials

Implementation

Testing

Results

The final implementation successfully executes RISC-V programs with proper pipeline operation. Below is the main processor module:

📄 riscvpipelined.sv System Verilog
// 5-Stage RISC-V Pipeline Processor

// riscvpipelined.sv

// RISC-V pipelined processor
// From Section 7.6 of Digital Design & Computer Architecture: RISC-V Edition
// 27 April 2020
// David_Harris@hmc.edu 
// Sarah.Harris@unlv.edu

// run 210
// Expect simulator to print "Simulation succeeded"
// when the value 25 (0x19) is written to address 100 (0x64)

// Pipelined implementation of RISC-V (RV32I)
// User-level Instruction Set Architecture V2.2 (May 7, 2017)
// Implements a subset of the base integer instructions:
//    lw, sw
//    add, sub, and, or, slt, 
//    addi, andi, ori, slti
//    beq
//    jal
// Exceptions, traps, and interrupts not implemented
// little-endian memory

// 31 32-bit registers x1-x31, x0 hardwired to 0
// R-Type instructions
//   add, sub, and, or, slt
//   INSTR rd, rs1, rs2
//   Instr[31:25] = funct7 (funct7b5 & opb5 = 1 for sub, 0 for others)
//   Instr[24:20] = rs2
//   Instr[19:15] = rs1
//   Instr[14:12] = funct3
//   Instr[11:7]  = rd
//   Instr[6:0]   = opcode

// I-Type Instructions
//   lw, I-type ALU (addi, andi, ori, slti)
//   lw:         INSTR rd, imm(rs1)
//   I-type ALU: INSTR rd, rs1, imm (12-bit signed)
//   Instr[31:20] = imm[11:0]
//   Instr[24:20] = rs2
//   Instr[19:15] = rs1
//   Instr[14:12] = funct3
//   Instr[11:7]  = rd
//   Instr[6:0]   = opcode

// S-Type Instruction
//   sw rs2, imm(rs1) (store rs2 into address specified by rs1 + immm)
//   Instr[31:25] = imm[11:5] (offset[11:5])
//   Instr[24:20] = rs2 (src)
//   Instr[19:15] = rs1 (base)
//   Instr[14:12] = funct3
//   Instr[11:7]  = imm[4:0]  (offset[4:0])
//   Instr[6:0]   = opcode

// B-Type Instruction
//   beq rs1, rs2, imm (PCTarget = PC + (signed imm x 2))
//   Instr[31:25] = imm[12], imm[10:5]
//   Instr[24:20] = rs2
//   Instr[19:15] = rs1
//   Instr[14:12] = funct3
//   Instr[11:7]  = imm[4:1], imm[11]
//   Instr[6:0]   = opcode

// J-Type Instruction
//   jal rd, imm  (signed imm is multiplied by 2 and added to PC, rd = PC+4)
//   Instr[31:12] = imm[20], imm[10:1], imm[11], imm[19:12]
//   Instr[11:7]  = rd
//   Instr[6:0]   = opcode

//   Instruction  opcode    funct3    funct7
//   add          0110011   000       0000000
//   sub          0110011   000       0100000
//   and          0110011   111       0000000
//   or           0110011   110       0000000
//   slt          0110011   010       0000000
//   addi         0010011   000       immediate
//   andi         0010011   111       immediate
//   ori          0010011   110       immediate
//   slti         0010011   010       immediate
//   beq          1100011   000       immediate
//   lw	          0000011   010       immediate
//   sw           0100011   010       immediate
//   jal          1101111   immediate immediate

/*
add Done
addi Done
and Done
andi Done
auipc Jump instruction dont work
beq Done
bge Done
bgeu Done
blt Done
bltu Done
bne Done
jal 
jalr 
lb Done
lbu Done
lh Done
lhu Done
lw Done
lui Done
or Done
ori Done
sb Done
sh Done
sll Done
slt Done
slli Done
slti Done
sltiu Done
sltu Done
sra Done
srai Done
srl Done
srli Done
sub Done
sw Done
xor Done
xori Done

*/

module testbench();

   logic        clk;
   logic        reset;

   logic [31:0] WriteData, DataAdr;
   logic        MemWrite;

   // instantiate device to be tested
   top dut(clk, reset, WriteData, DataAdr, MemWrite);

   initial
     begin
	string memfilename;
        memfilename = {"../testing/auipc.memfile"};
	$readmemh(memfilename, dut.imem.RAM);
  $readmemh(memfilename, dut.dmem.RAM);

     end
   
   // initialize test
   initial
     begin
	reset <= 1; # 22; reset <= 0;
     end

   // generate clock to sequence tests
   always
     begin
	clk <= 1; # 5; clk <= 0; # 5;
     end

/*   // check results
   always @(negedge clk)
     begin
	if(MemWrite) begin
           if(DataAdr === 100 & WriteData === 25) begin
              $display("Simulation succeeded");
              $stop;
           end else if (DataAdr !== 96) begin
              $display("Simulation failed");
              $stop;
           end
	end
     end*/
endmodule

/*module top(input  logic        clk, reset, 
           output logic [31:0] WriteDataM, DataAdrM, 
           output logic        MemWriteM);

   logic [31:0] 	       PCF, InstrF, ReadDataM;
   
   // instantiate processor and memories
   riscv rv32pipe (clk, reset, PCF, InstrF, MemWriteM, DataAdrM, 
		   WriteDataM, ReadDataM);
   imem imem (PCF, InstrF);
   dmem dmem (clk, MemWriteM, DataAdrM, WriteDataM, ReadDataM);
   
endmodule*/

module riscv(input  logic        clk, reset,
             output logic [31:0] PCF,
             input logic [31:0]  InstrF,
             output logic 	 MemWriteM,
             output logic [31:0] ALUResultM, WriteDataM,
             input logic [31:0]  ReadDataM);

   logic [6:0] 			 opD;
   logic [2:0] 			 funct3D, funct3M, funct3E;
   logic 			 funct7b5D;
   logic [2:0] 			 ImmSrcD;
   logic 			 ZeroE, NegativeE, CarryE, OverflowE;
   logic 			 PCSrcE, PCSrcNextE;
   logic [3:0] 			 ALUControlE;
   logic [1:0] ALUSrcE;
   logic 			 ResultSrcEb0;
   logic 			 RegWriteM;
   logic [1:0] 			 ResultSrcW;
   logic 			 RegWriteW;

   logic [1:0] 			 ForwardAE, ForwardBE;
   logic 			 StallF, StallD, FlushD, FlushE;

   logic [4:0] 			 Rs1D, Rs2D, Rs1E, Rs2E, RdE, RdM, RdW;
   logic [31:0] dpReadDataM, dpWriteDataM;
   
   controller c(clk, reset,
            opD, funct3D, funct3E, funct7b5D, ImmSrcD,
            FlushE, ZeroE, NegativeE, CarryE, OverflowE, PCSrcE, PCSrcNextE, ALUControlE, ALUSrcE, ResultSrcEb0,
            MemWriteM, RegWriteM, 
            RegWriteW, ResultSrcW, funct3M);

   datapath dp(clk, reset,
           StallF, PCF, InstrF,
           opD, funct3D, funct7b5D, StallD, FlushD, ImmSrcD,
           FlushE, ForwardAE, ForwardBE, PCSrcE, PCSrcNextE, ALUControlE, ALUSrcE, ZeroE, NegativeE, CarryE, OverflowE,
           MemWriteM, dpWriteDataM, ALUResultM, ReadDataM,
           RegWriteW, ResultSrcW,
           Rs1D, Rs2D, Rs1E, Rs2E, RdE, RdM, RdW);


   hazard  hu(Rs1D, Rs2D, Rs1E, Rs2E, RdE, RdM, RdW,
              PCSrcE,PCSrcNextE, ResultSrcEb0, RegWriteM, RegWriteW,
              ForwardAE, ForwardBE, StallF, StallD, FlushD, FlushE);			

always_comb
  case(funct3M)
    // Store byte (sb)
    3'b000: begin
      case(ALUResultM[1:0])
        2'b00: WriteDataM = {ReadDataM[31:8], dpWriteDataM[7:0]};
        2'b01: WriteDataM = {ReadDataM[31:16], dpWriteDataM[7:0], ReadDataM[7:0]};
        2'b10: WriteDataM = {ReadDataM[31:24], dpWriteDataM[7:0], ReadDataM[15:0]};
        2'b11: WriteDataM = {dpWriteDataM[7:0], ReadDataM[23:0]};
      endcase
    end
    // Store halfword (sh)
    3'b001: begin
      case(ALUResultM[1])
        1'b0: WriteDataM = {ReadDataM[31:16], dpWriteDataM[15:0]};
        1'b1: WriteDataM = {dpWriteDataM[15:0], ReadDataM[15:0]};
      endcase
    end
    // Store word (sw)
    default: WriteDataM = dpWriteDataM;
  endcase

endmodule


module controller(input  logic        clk, reset,
                  // Decode stage control signals
                  input logic [6:0]   opD,
                  input logic [2:0]   funct3D, funct3E,
                  input logic         funct7b5D,
                  output logic [2:0]  ImmSrcD,
                  // Execute stage control signals
                  input logic         FlushE, 
                  input logic         ZeroE, NegativeE, CarryE, OverflowE,
                  output logic        PCSrcE, // for datapath and Hazard Unit
                  output logic        PCSrcNextE, // for jalr
                  output logic [3:0]  ALUControlE, 
                  output logic [1:0]  ALUSrcE,
                  output logic        ResultSrcEb0, // for Hazard Unit
                  // Memory stage control signals
                  output logic        MemWriteM,
                  output logic        RegWriteM, // for Hazard Unit                  
                  // Writeback stage control signals
                  output logic        RegWriteW, // for datapath and Hazard Unit
                  output logic [1:0]  ResultSrcW,
                  output logic [2:0]  funct3M);
   // pipelined control signals
   logic 			     RegWriteD, RegWriteE;
   logic [1:0] 			     ResultSrcD, ResultSrcE, ResultSrcM;
   logic 			     MemWriteD, MemWriteE;
   logic 			     JumpD, JumpE;
   logic 			     BranchD, BranchE, BranchTakenE;
   logic [1:0] 			     ALUOpD;
   logic [3:0] 			     ALUControlD;
   logic [1:0]			     ALUSrcD;
   logic                Memstrobe;
   // Fetching Instructions
   
   // Decode stage logic
   maindec md(opD, ResultSrcD, MemWriteD, BranchD,
              ALUSrcD, RegWriteD, JumpD, Memstrobe, ImmSrcD, ALUOpD);
   aludec  ad(opD[5], funct3D, funct7b5D, ALUOpD, ALUControlD);
   
   // Execute stage pipeline control register and logic
   floprc #(15) controlregE(clk, reset, FlushE,
                        {RegWriteD, ResultSrcD, MemWriteD, JumpD, BranchD, ALUControlD, ALUSrcD, funct3D},
                        {RegWriteE, ResultSrcE, MemWriteE, JumpE, BranchE, ALUControlE, ALUSrcE, funct3E});

always_comb
  case(funct3E)
    3'b000: BranchTakenE = ZeroE;                    // beq =
    3'b001: BranchTakenE = ~ZeroE;                   // bne !=
    3'b100: BranchTakenE = (NegativeE ^ OverflowE);  // blt 
    3'b101: BranchTakenE = ~(NegativeE ^ OverflowE); // bge >=
    3'b110: BranchTakenE = ~CarryE;                  // bltu < unsigned
    3'b111: BranchTakenE = CarryE;                   // bgeu >= unsigned
    default: BranchTakenE = 1'b0;
  endcase

   assign PCSrcE = (BranchE & BranchTakenE) | JumpE;
   assign PCSrcNextE = JumpE & ALUSrcE;
   assign ResultSrcEb0 = ResultSrcE[0];
   
   // Memory stage pipeline control register
   flopr #(7) controlregM(clk, reset,
                      {RegWriteE, ResultSrcE, MemWriteE, funct3E},
                      {RegWriteM, ResultSrcM, MemWriteM, funct3M});
   
   // Writeback stage pipeline control register
   flopr #(3) controlregW(clk, reset,
                          {RegWriteM, ResultSrcM},
                          {RegWriteW, ResultSrcW});     
endmodule

module maindec (input  logic [6:0] op,
		output logic [1:0] ResultSrc,
		output logic 	   MemWrite,
		output logic 	   Branch,
		output logic [1:0]  ALUSrc,
		output logic 	   RegWrite, Jump, MemStrobe,
		output logic [2:0] ImmSrc,
		output logic [1:0] ALUOp);
   
	logic [13:0] 		   controls;
   
   assign {RegWrite, ImmSrc, ALUSrc, MemWrite,
	   ResultSrc, Branch, ALUOp, Jump ,MemStrobe} = controls;
   
   always_comb
     case(op)
       // RegWrite_ImmSrc_ALUSrc_MemWrite_ResultSrc_Branch_ALUOp_Jump_MemStrobe
       7'b0000011: controls = 14'b1_000_01_0_11_0_00_0_1; // load
       7'b0100011: controls = 14'b0_001_01_1_01_0_00_0_1; // save
       7'b0110011: controls = 14'b1_xxx_00_0_00_0_10_0_0; // R–type
       7'b1100011: controls = 14'b0_010_00_0_00_1_01_0_0; // B-Type
       7'b0010011: controls = 14'b1_000_01_0_00_0_10_0_0; // I–type ALU
       7'b1101111: controls = 14'b1_011_00_0_10_0_00_1_0; // Jal
       7'b1100111: controls = 14'b1_000_01_0_10_0_00_1_0; // jalr   
       7'b0010111: controls = 14'b1_100_11_0_00_0_00_0_0; // auipc    
       7'b0110111: controls = 14'b1_100_01_0_00_0_11_0_0; // lui      

       default: controls = 14'bx_xxx_xx_x_xx_x_xx_x_x; // ???
     endcase // case (op)
   
endmodule // maindec

module aludec (input  logic     opb5,
	       input  logic [2:0]   funct3,
	       input  logic 	    funct7b5,
	       input  logic [1:0]   ALUOp,
	       output logic [3:0]   ALUControl);
   
   logic 			  RtypeSub;
   
   assign RtypeSub = funct7b5 & opb5; // TRUE for R–type subtract


   always_comb
     case(ALUOp)
        2'b00: ALUControl = 4'b0000; // addition
        2'b01: ALUControl = 4'b0001; // subtraction
        2'b11: ALUControl = 4'b1110; // lui
        default: case(funct3) // R–type or I–type ALU
            3'b000: if (RtypeSub)
                         ALUControl = 4'b0001; // sub
                    else
                         ALUControl = 4'b0000; // add, addi
            3'b010: if (!RtypeSub) // I type set less than
                         ALUControl = 4'b0101; // slt, slti
                    else
                         if (!funct7b5)
                             ALUControl = 4'b0101; // slt
                         else
                             ALUControl = 4'b1010; // sgt
            3'b110: ALUControl = 4'b0011; // or, ori
            3'b111: ALUControl = 4'b0010; // and, andi
            3'b100: ALUControl = 4'b0100; // xor, xori
            3'b101: if (funct7b5)
                         ALUControl = 4'b0111; // sra, srai
                    else
                         ALUControl = 4'b0110; // srl, srli
            3'b001: ALUControl = 4'b1000; // sll, slli
            3'b011: if (!RtypeSub) // I type
                         ALUControl = 4'b1001; // sltiu
                    else // R type
                         if (!funct7b5)
                             ALUControl = 4'b1001; // sltu
                         else
                             ALUControl = 4'b1100;
            default: ALUControl = 4'bxxxx; // ???
        endcase // case (funct3)
     endcase // case (ALUOp)

endmodule // aludec

module datapath(input logic clk, reset,
                // Fetch stage signals
                input logic         StallF,
                output logic [31:0] PCF,
                input logic [31:0]  InstrF,
                // Decode stage signals
                output logic [6:0]  opD,
                output logic [2:0]  funct3D,
                output logic        funct7b5D,
                input logic         StallD, FlushD,
                input logic [2:0]   ImmSrcD,
                // Execute stage signals
                input logic         FlushE,
                input logic [1:0]   ForwardAE, ForwardBE,
                input logic         PCSrcE,
                input logic         PCSrcNextE,
                input logic [3:0]   ALUControlE,
                input logic [1:0]   ALUSrcE,
                output logic        ZeroE, NegativeE, CarryE, OverflowE,
                // Memory stage signals
                input logic         MemWriteM,
                output logic [31:0] dpWriteDataM, ALUResultM,
                input logic [31:0]  ReadDataM,
                // Writeback stage signals
                input logic         RegWriteW,
                input logic [1:0]   ResultSrcW,
                // Hazard Unit signals
                output logic [4:0]  Rs1D, Rs2D, Rs1E, Rs2E,
                output logic [4:0]  RdE, RdM, RdW);
   // Fetch stage signals
   logic [31:0] PCNextTemp, PCNextF, PCPlus4F;
   // Decode stage signals
   logic [31:0] InstrD;
   logic [31:0] PCD, PCPlus4D;
   logic [31:0] RD1D, RD2D;
   logic [31:0] ImmExtD;
   logic [4:0] RdD;
   // Execute stage signals
   logic [31:0] RD1E, RD2E;
   logic [31:0] PCE, ImmExtE;
   logic [31:0] SrcAE, SrcBE, RegOutAE;
   logic [31:0] ALUResultE;
   logic [31:0] WriteDataE;
   logic [31:0] PCPlus4E;
   logic [31:0] PCTargetE;
   // Memory stage signals
   logic [31:0] PCPlus4M;
   // Writeback stage signals
   logic [31:0] ALUResultW;
   logic [31:0] ReadDataW;
   logic [31:0] PCPlus4W;
   logic [31:0] ResultW;
   logic [31:0] ResultLoad;

   // Fetch stage pipeline register and logic
   mux2 #(32) pcmux(PCPlus4F, PCTargetE, PCSrcE, PCNextTemp);
   mux2 #(32) pcmux2(PCNextTemp, ALUResultE, PCSrcNextE, PCNextF);
   flopenr #(32) pcreg(clk, reset, ~StallF, PCNextF, PCF);
   adder pcadd(PCF, 32'h4, PCPlus4F);

   // Decode stage pipeline register and logic
   flopenrc #(96) regD(clk, reset, FlushD, ~StallD,
                       {InstrF, PCF, PCPlus4F},
                       {InstrD, PCD, PCPlus4D});
   assign opD       = InstrD[6:0];
   assign funct3D   = InstrD[14:12];
   assign funct7b5D = InstrD[30];
   assign Rs1D      = InstrD[19:15];
   assign Rs2D      = InstrD[24:20];
   assign RdD       = InstrD[11:7];

   regfile        rf(clk, RegWriteW, Rs1D, Rs2D, RdW, ResultW, RD1D, RD2D);
   extend         ext(InstrD[31:7], ImmSrcD, ImmExtD);

   // Execute stage pipeline register and logic
   floprc #(175) regE(clk, reset, FlushE,
                      {RD1D, RD2D, PCD, Rs1D, Rs2D, RdD, ImmExtD, PCPlus4D},
                      {RD1E, RD2E, PCE, Rs1E, Rs2E, RdE, ImmExtE, PCPlus4E});

   mux3   #(32)  faemux(RD1E, ResultW, ALUResultM, ForwardAE, RegOutAE);
   mux3   #(32)  fbemux(RD2E, ResultW, ALUResultM, ForwardBE, WriteDataE);
   mux2   #(32)  srcamux(RegOutAE, PCE, ALUSrcE[1], SrcAE);
   mux2   #(32)  srcbmux(WriteDataE, ImmExtE, ALUSrcE[0], SrcBE);
   alu           alu(SrcAE, SrcBE, ALUControlE, ALUResultE, ZeroE, NegativeE, CarryE, OverflowE);
   adder         branchadd(ImmExtE, PCE, PCTargetE);

   // Memory stage pipeline register
   flopr  #(101) regM(clk, reset,
                  {ALUResultE, WriteDataE, RdE, PCPlus4E},
                  {ALUResultM, dpWriteDataM, RdM, PCPlus4M});

   // Writeback stage pipeline register and logic
   flopr  #(101) regW(clk, reset,
                      {ALUResultM, ReadDataM, RdM, PCPlus4M},
                      {ALUResultW, ReadDataW, RdW, PCPlus4W});
   mux4 #(32) resultmux(ALUResultW, ReadDataW, PCPlus4W, ResultLoad, ResultSrcW, ResultW);
   loadextend load (ALUResultW, ReadDataW, funct3D, ResultLoad);
   // If memwrite  == true go to store extend
endmodule

// Hazard Unit: forward, stall, and flush
module hazard(input  logic [4:0] Rs1D, Rs2D, Rs1E, Rs2E, RdE, RdM, RdW,
              input logic        PCSrcE, PCSrcNextE, ResultSrcEb0,
              input logic        RegWriteM, RegWriteW,
              output logic [1:0] ForwardAE, ForwardBE,
              output logic       StallF, StallD, FlushD, FlushE);

   logic lwStallD;

   // forwarding logic
   always_comb begin
      ForwardAE = 2'b00;
      ForwardBE = 2'b00;
      if (Rs1E != 5'b0)
         if      ((Rs1E == RdM) & RegWriteM) ForwardAE = 2'b10;
         else if ((Rs1E == RdW) & RegWriteW) ForwardAE = 2'b01;

      if (Rs2E != 5'b0)
         if      ((Rs2E == RdM) & RegWriteM) ForwardBE = 2'b10;
         else if ((Rs2E == RdW) & RegWriteW) ForwardBE = 2'b01;
   end

   // stalls and flushes
   assign lwStallD = ResultSrcEb0 & ((Rs1D == RdE) | (Rs2D == RdE));
   assign StallD = lwStallD;
   assign StallF = lwStallD;
   assign FlushD = PCSrcE | PCSrcNextE;
   assign FlushE = lwStallD | PCSrcE | PCSrcNextE;
endmodule

module regfile(input  logic        clk,
               input logic         we3,
               input logic [ 4:0]  a1, a2, a3,
               input logic [31:0]  wd3,
               output logic [31:0] rd1, rd2);

   logic [31:0] rf[31:0];

   // three ported register file
   // read two ports combinationally (A1/RD1, A2/RD2)
   // write third port on rising edge of clock (A3/WD3/WE3)
   // write occurs on falling edge of clock
   // register 0 hardwired to 0

   always_ff @(negedge clk)
     if (we3) rf[a3] <= wd3;

   assign rd1 = (a1 != 0) ? rf[a1] : 0;
   assign rd2 = (a2 != 0) ? rf[a2] : 0;
endmodule

module adder(input  [31:0] a, b,
             output [31:0] y);

   assign y = a + b;
endmodule

module extend (input  logic [31:7] instr,
               input  logic [2:0]  immsrc,
               output logic [31:0] immext);

   always_comb
     case(immsrc)
       // I−type
       3'b000:  immext = {{20{instr[31]}}, instr[31:20]};
       // S−type (stores)
       3'b001:  immext = {{20{instr[31]}}, instr[31:25], instr[11:7]};
       // B−type (branches)
       3'b010:  immext = {{20{instr[31]}}, instr[7], instr[30:25], instr[11:8], 1'b0};
       // J−type (jal)
       3'b011:  immext = {{12{instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0};
        // U−type (lui, auipc)
       3'b100: immext = {instr[31:12], 12'b0};
       default: immext = 32'bx; // undefined
     endcase // case (immsrc)

endmodule // extend

module loadextend (input logic [31:0] ALUResult, ReadData,
                     input logic [2:0] funct3,
                     output logic [31:0] ResultLoad);

     logic [1:0]    loadchunk;

     assign loadchunk = ALUResult[1:0];

     always_comb
        case(funct3)
         3'b000: case(loadchunk) // lb
           2'b00: ResultLoad = {{24{ReadData[7]}}, ReadData[7:0]};
           2'b01: ResultLoad = {{24{ReadData[15]}}, ReadData[15:8]};
           2'b10: ResultLoad = {{24{ReadData[23]}}, ReadData[23:16]};
           2'b11: ResultLoad = {{24{ReadData[31]}}, ReadData[31:24]};
           default: ResultLoad = 32'bx;
           endcase
         3'b001:  case(loadchunk[1]) // lh
             1'b0:  ResultLoad = {{16{ReadData[15]}}, ReadData[15:0]};
             1'b1:  ResultLoad = {{16{ReadData[31]}}, ReadData[31:16]};
             default: ResultLoad = 32'bx;
             endcase
         3'b010:  ResultLoad = ReadData; // lw
         3'b100: case(loadchunk) // lbu
           2'b00: ResultLoad = {{24{0}}, ReadData[7:0]};
           2'b01: ResultLoad = {{24{0}}, ReadData[15:8]};
           2'b10: ResultLoad = {{24{0}}, ReadData[23:16]};
           2'b11: ResultLoad = {{24{0}}, ReadData[31:24]};
           default: ResultLoad = 32'bx;
           endcase
         3'b101:  case(loadchunk[1]) // lhu
             1'b0:  ResultLoad = {{16{0}}, ReadData[15:0]};
             1'b1:  ResultLoad = {{16{0}}, ReadData[31:16]};
             default: ResultLoad = 32'bx;
             endcase
         default: ResultLoad = 32'bx;
         endcase

endmodule // loadextend

/* module store (input logic [31:0] ALUResult, Result,
               input logic Memwrite,
               input logic [2:0] funct3,
               output logic [31:0] ResultStore);

     logic [1:0]    storechunk;

     assign storechunk = ALUResult[1:0];

 if(Memwrite){
     always_comb
        case(funct3)
         3'b000: case(storechunk) // sb
           2'b00: ResultStore = {{{Result[31:8]}}, Result[7:0]};
           2'b01: ResultStore = {{{Result[31:16]}}, Result[7:0], Result[7:0]};
           2'b10: ResultStore = {{{Result[31:24]}}, Result[7:0], Result[15:0]};
           2'b11: ResultStore = {{{Result[7:0]}}, Result[23:0]};
           default: ResultStore = 32'bx;
           endcase
         3'b001:  case(storechunk[1]) // sh
             1'b0:  ResultStore = {{{Result[31:16]}}, Result[15:0]};
             1'b1:  ResultStore = {{{Result[31:16]}}, Result[15:0]};
             default: ResultStore = 32'bx;
             endcase
         3'b010:  ResultStore = Result; // sw
         default: ResultStore = 32'bx;
         endcase
 }

endmodule // loadextend */

module flopr #(parameter WIDTH = 8)
   (input  logic             clk, reset,
    input logic [WIDTH-1:0]  d,
    output logic [WIDTH-1:0] q);

   always_ff @(posedge clk, posedge reset)
     if (reset) q <= 0;
     else       q <= d;
endmodule

module flopenr #(parameter WIDTH = 8)
   (input  logic             clk, reset, en,
    input logic [WIDTH-1:0]  d,
    output logic [WIDTH-1:0] q);

   always_ff @(posedge clk, posedge reset)
     if (reset)   q <= 0;
     else if (en) q <= d;
endmodule

module flopenrc #(parameter WIDTH = 8)
   (input  logic             clk, reset, clear, en,
    input logic [WIDTH-1:0]  d,
    output logic [WIDTH-1:0] q);

   always_ff @(posedge clk, posedge reset)
     if (reset)   q <= 0;
     else if (en)
       if (clear) q <= 0;
       else       q <= d;
endmodule

module floprc #(parameter WIDTH = 8)
   (input  logic clk,
    input logic              reset,
    input logic              clear,
    input logic [WIDTH-1:0]  d,
    output logic [WIDTH-1:0] q);

   always_ff @(posedge clk, posedge reset)
     if (reset) q <= 0;
     else
       if (clear) q <= 0;
       else       q <= d;
endmodule

module mux2 #(parameter WIDTH = 8)
   (input  logic [WIDTH-1:0] d0, d1,
    input logic              s,
    output logic [WIDTH-1:0] y);

   assign y = s ? d1 : d0;
endmodule

module mux3 #(parameter WIDTH = 8)
   (input  logic [WIDTH-1:0] d0, d1, d2,
    input logic [1:0]        s,
    output logic [WIDTH-1:0] y);

   assign y = s[1] ? d2 : (s[0] ? d1 : d0);
endmodule

module mux4 # (parameter WIDTH = 8)
            (input logic [WIDTH-1:0] d0, d1, d2, d3,
             input logic [1:0] s,
             output logic [WIDTH-1:0] y);

    assign y = (s[1] ? (s[0] ? d3 : d2) : (s[0] ? d1 : d0));

endmodule

/*module imem (input  logic [31:0] a,
             output logic [31:0] rd);

   logic [31:0] RAM[2047:0];

   assign rd = RAM[a[31:2]]; // word aligned

endmodule // imem


module dmem (input  logic        clk, we,
             input  logic [31:0] a, wd,
             output logic [31:0] rd);

   logic [31:0] RAM[2047:0];

   assign rd = RAM[a[31:2]]; // word aligned
   always_ff @(posedge clk)
     if (we) RAM[a[31:2]] <= wd;

endmodule // dmem*/

module alu (input  logic [31:0] a, b,
            input  logic [3:0]  alucontrol,
            output logic [31:0] result,
            output logic         zero, negative, carry, overflow);

   logic [31:0] condinvb, sum, xorOut, sltuOut;
   logic [32:0] fullsum;
   logic        Cout;
   logic        isAddSub;       // true when is add or subtract operation

   assign condinvb = alucontrol[0] ? ~b : b;
   assign fullsum = a + condinvb + alucontrol[0];
   assign sum = {fullsum[31:0]};
   assign isAddSub = ~alucontrol[2] & ~alucontrol[1] |
                     ~alucontrol[1] & alucontrol[0]  |
                     alucontrol[2] & alucontrol[1] & alucontrol[0];

   always_comb
     case (alucontrol)
       4'b0000:  result = sum;         // add
       4'b0001:  result = sum;         // subtract
       4'b0010:  result = a & b;       // and
       4'b0011:  result = a | b;       // or
       4'b0101:  result = sum[31] ^ overflow; // slt
       4'b0110:  result = a >> unsigned'(b[4:0]);      // srl
       4'b0111:  result = $signed(a) >>> unsigned'(b[4:0]);     // sra
       4'b0100:  result = a ^ b;      // xor
       4'b1000:  result = a << unsigned'(b[4:0]);      // sll
       4'b1001:  result = unsigned'(a) < unsigned'(b);     // sltu
       4'b1110:  result = b;           // lui
       default:  result = 32'bx;
     endcase
   // overflow
   assign overflow = ~(alucontrol[0] ^ a[31] ^ b[31]) & (a[31] ^ sum[31]) & isAddSub;
   // negative
   assign negative = result[31];
   // Cout
   assign carry = fullsum[32];
   // zero
   assign zero = (result == 32'b0);

endmodule // alu
View Full Code Base on GitHub
Back to Projects