~ruther/verilog-riscv-semestral-project

acf0f7243e7b45dc7db8e51c5c7ae659f7ef2bb3 — Rutherther 1 year, 5 months ago bc02aba
feat: implement sb, sh, lb, lh support via masking
M src/control_unit.sv => src/control_unit.sv +7 -4
@@ 3,8 3,8 @@ import cpu_types::*;
module control_unit(
  input [31:0]  instruction,

  // TODO: mask for: memory in and out
  // don't forget zero extension, sign extension...
  output        memory_mask_t memory_mask,
  output        memory_sign_extension,

  // whether to save alu to memory
  output        memory_we,


@@ 47,6 47,8 @@ module control_unit(
  wire       alu_reg_add_one, alu_reg_negate, alu_reg_signed;
  wire       alu_jump_add_one, alu_jump_negate;

  wire       alu_override;

  assign jump_instruction = conditional_jump;

  instruction_decoder decoder(


@@ 55,8 57,9 @@ module control_unit(
    .store_memory(memory_we),

    .load_memory(load_memory),
    .load_memory_size(),
    .load_memory_sign_extension(),

    .memory_mask(memory_mask),
    .memory_sign_extension(memory_sign_extension),

    .load_pc(load_pc),
    .store_pc(store_pc),

M src/cpu.sv => src/cpu.sv +22 -2
@@ 12,6 12,7 @@ module cpu(
  output [31:0]     memory_address,
  input [31:0]      memory_out,
  output reg [31:0] memory_write,
  output            memory_mask_t memory_mask,
  output reg        memory_we
);
  parameter WIDTH = 32;


@@ 38,7 39,23 @@ module cpu(
  wire        jump_instruction, jump_negate_zero;
  wire        jump_taken;

  assign memory_write = reg_rd2;
  wire        memory_sign_extension;

  function bit[31:0] mem_sext_maybe;
    input [31:0] num;
    input        memory_mask_t mask;
    input        sext;
    begin
      case(mask)
        MEM_BYTE: return {{(32 - 8){sext & num[7]}}, num[7:0]};
        MEM_HALFWORD: return {{(32 - 16){sext & num[15]}}, num[15:0]};
        MEM_WORD: return num[31:0]; // rv32i, no 64 bit regs, no sign extension needed
        default: return 0;
      endcase
    end
  endfunction

  assign memory_write = mem_sext_maybe(.num(reg_rd2), .mask(memory_mask), .sext(memory_sign_extension));
  assign memory_address = alu_out;

  // alu source 1


@@ 76,7 93,7 @@ module cpu(
    case (reg_write_src)
      RD_ALU : reg_write = alu_out;
      RD_PC_PLUS : reg_write = pc + 4;
      RD_MEMORY : reg_write = memory_out;
      RD_MEMORY : reg_write = mem_sext_maybe(.num(memory_out), .mask(memory_mask), .sext(memory_sign_extension));
      default : ;
    endcase
  end


@@ 91,6 108,9 @@ module cpu(
    .alu_negate(alu_negate),
    .alu_signed(alu_signed),

    .memory_mask(memory_mask),
    .memory_sign_extension(memory_sign_extension),

    .memory_we(memory_we),

    .jump_instruction(jump_instruction),

M src/cpu_types.sv => src/cpu_types.sv +2 -0
@@ 3,4 3,6 @@ package cpu_types;
  typedef enum bit[0:0] { REG_FILE_RS1, PC } alu_1_source_t;
  typedef enum bit[0:0] { REG_FILE_RS2, IMMEDIATE } alu_2_source_t;
  typedef enum bit[1:0] { RD_ALU, RD_PC_PLUS, RD_MEMORY } reg_rd_source_t;

  typedef enum bit[1:0] { MEM_BYTE, MEM_HALFWORD, MEM_WORD } memory_mask_t;
endpackage

M src/instruction_decoder.sv => src/instruction_decoder.sv +15 -12
@@ 1,3 1,5 @@
import cpu_types::* ;

module instruction_decoder(
  input [31:0]     instruction,



@@ 7,8 9,8 @@ module instruction_decoder(

  // whether to load memory to rd
  output reg       load_memory,
  output reg [5:0] load_memory_size,
  output reg       load_memory_sign_extension,
  output           memory_mask_t memory_mask,
  output reg       memory_sign_extension,

  // put alu_jump to alu if conditional_jump
  //


@@ 64,27 66,27 @@ module instruction_decoder(

  // load memory mask/size
  always_comb begin
    load_memory_size = 32;
    load_memory_sign_extension = 1'b0;
    memory_mask = MEM_WORD;
    memory_sign_extension = 1'b0;

    case (funct3)
      3'b000: begin
        load_memory_size = 8; // sign extends
        load_memory_sign_extension = 1'b1;
        memory_mask = MEM_BYTE; // sign extends
        memory_sign_extension = 1'b1;
      end
      3'b001: begin
        load_memory_size = 16; // sign extends
        load_memory_sign_extension = 1'b1;
        memory_mask = MEM_HALFWORD; // sign extends
        memory_sign_extension = 1'b1;
      end
      3'b010: begin
        load_memory_size = 32; // sign extends
        load_memory_sign_extension = 1'b1;
        memory_mask = MEM_WORD; // sign extends
        memory_sign_extension = 1'b1;
      end
      3'b100: begin
        load_memory_size = 8; // zero extends
        memory_mask = MEM_BYTE; // zero extends
      end
      3'b101: begin
        load_memory_size = 16; // zero extends
        memory_mask = MEM_HALFWORD; // zero extends
      end
      default : ;
    endcase


@@ 93,6 95,7 @@ module instruction_decoder(
  // immediate load
  always_comb begin
    case (instruction_type)
      // beware, slli, srai and srli, are I, but have funct7
      I : immediate = {{20{instruction[31]}}, instruction[31:20]};
      S : immediate = {{20{instruction[31]}}, instruction[31:25], instruction[11:7]};
      SB : immediate = {{20{instruction[31]}}, instruction[7], instruction[30:25], instruction[11:8], 1'b0};

M src/ram.sv => src/ram.sv +13 -3
@@ 1,13 1,23 @@
import cpu_types::*;

module ram (
  input         clk, we,
  input [31:0]  a, wd,
  input         memory_mask_t mask,
  output [31:0] rd);

  reg [31:0]    RAM[0:127];
  reg [4095:0]    RAM;

  assign rd = RAM[a[8:2]]; // word aligned
  assign rd = RAM[a[11:0] +:32]; // word aligned

  always @(posedge clk)
    if(we) RAM[a[8:2]] <= wd;
    if(we) begin
      case(mask)
        MEM_BYTE: RAM[a[11:0] +:8] <= wd[7:0];
        MEM_HALFWORD: RAM[a[11:0] +:16] <= wd[15:0];
        MEM_WORD: RAM[{a[11:0]} +:32] <= wd[31:0];
        default: ;
      endcase
    end

endmodule

M testbench/tb_control_unit.sv => testbench/tb_control_unit.sv +9 -1
@@ 27,6 27,9 @@ module tb_control_unit();
  wire [4:0]  reg_rd;
  wire        reg_we;

  memory_mask_t memory_mask;
  wire memory_sign_extension;

  control_unit uut(
    .instruction(instruction),
    .memory_we(memory_we),


@@ 44,7 47,9 @@ module tb_control_unit();
    .reg_rs2(reg_rs2),
    .reg_rd_src(reg_rd_src),
    .reg_rd(reg_rd),
    .reg_we(reg_we)
    .reg_we(reg_we),
    .memory_mask(memory_mask),
    .memory_sign_extension(memory_sign_extension)
  );

  initial begin


@@ 103,6 108,9 @@ module tb_control_unit();
    #5 // lui
    instruction = {20'hA000A, 5'b00001, 7'b0110111};

    #5
    instruction = 32'b1000000000101111101011110010011;


    #5 $finish;
  end

M testbench/tb_cpu_simple.sv => testbench/tb_cpu_simple.sv +7 -0
@@ 1,9 1,14 @@

import cpu_types::*;

module tb_cpu_simple();
  reg clk, rst_n;

  wire [31:0] memory_address, memory_write, memory_out;
  wire        memory_we;

  memory_mask_t memory_mask;

  wire [31:0] pc;
  reg [31:0]  instruction;



@@ 17,12 22,14 @@ module tb_cpu_simple();
    .memory_address(memory_address),
    .memory_out(memory_out),
    .memory_write(memory_write),
    .memory_mask(memory_mask),
    .memory_we(memory_we)
  );

  ram memory_inst(
    .clk(clk),
    .a(memory_address),
    .mask(memory_mask),
    .we(memory_we),
    .wd(memory_write),
    .rd(memory_out)

Do not follow this link