~ruther/verilog-riscv-semestral-project

586cf7122913dbe1faece5e92b9da4bfc0d36403 — Rutherther 1 year, 3 months ago af6386a
chore: clearer naming
M src/cpu.sv => src/cpu.sv +11 -11
@@ 10,7 10,7 @@ module cpu(

  // ram
  output [31:0]     memory_address,
  input [31:0]      memory_out,
  input [31:0]      memory_read,
  output [31:0]     memory_write,
  output [3:0]      memory_byte_enable,
  output            memory_we,


@@ 22,7 22,7 @@ module cpu(
  reg [31:0]  pc_next;

  wire [4:0]  reg_a_1, reg_a_2, reg_a_w;
  wire [31:0] reg_rd1, reg_rd2;
  wire [31:0] reg_rs1, reg_rs2;
  reg [31:0]  reg_write;
  wire        reg_we;



@@ 46,10 46,10 @@ module cpu(
  // stage registers
  always_ff @(posedge clk) begin
    if (rst_n == 0) begin
      decode_in.data.address = 0;
      execute_in.data.address = 0;
      memory_access_in.data.address = 0;
      writeback_in.data.address = 0;
      decode_in.data.target = 0;
      execute_in.data.target = 0;
      memory_access_in.data.target = 0;
      writeback_in.data.target = 0;
    end
    else begin
      if (decode_out.ready && execute_out.ready && memory_access_out.ready)


@@ 96,8 96,8 @@ module cpu(
    .data_in_pipeline(data_in_pipeline),
    .reg_a_1(reg_a_1),
    .reg_a_2(reg_a_2),
    .reg_rd1(reg_rd1),
    .reg_rd2(reg_rd2),
    .reg_rs1(reg_rs1),
    .reg_rs2(reg_rs2),
    .stage_in(decode_in),
    .stage_out(decode_out)
  );


@@ 112,7 112,7 @@ module cpu(

  memory_access memory_access_inst(
    .clk(clk),
    .memory_out(memory_out),
    .memory_read(memory_read),
    .memory_byte_enable(memory_byte_enable),
    .memory_write(memory_write),
    .memory_we(memory_we),


@@ 136,8 136,8 @@ module cpu(
    .a3(reg_a_w),
    .we3(reg_we),
    .wd3(reg_write),
    .rd1(reg_rd1),
    .rd2(reg_rd2)
    .rd1(reg_rs1),
    .rd2(reg_rs2)
  );

  program_counter program_counter_inst(

M src/cpu_singlecycle.sv => src/cpu_singlecycle.sv +6 -6
@@ 31,7 31,7 @@ module cpu(
  wire [31:0] alu_out;

  wire [4:0]  reg_a_1, reg_a_2, reg_a_w;
  wire [31:0] reg_rd1, reg_rd2;
  wire [31:0] reg_rs1, reg_rs2;
  reg [31:0]  reg_write;
  wire [1:0]  reg_write_src;
  wire        reg_we;


@@ 72,13 72,13 @@ module cpu(
  endfunction

  assign memory_byte_enable = mask_to_mask_bytes(.mask(memory_mask)) << memory_address[1:0];
  assign memory_write = reg_rd2 << (8*memory_address[1:0]);
  assign memory_write = reg_rs2 << (8*memory_address[1:0]);
  assign memory_address = alu_out;

  // alu source 1
  always_comb begin
    case (alu_1_src)
      REG_FILE_RS1 : alu_1 = reg_rd1;
      REG_FILE_RS1 : alu_1 = reg_rs1;
      PC : alu_1 = pc;
    endcase
  end


@@ 86,7 86,7 @@ module cpu(
  // alu source 2
  always_comb begin
    case (alu_2_src)
      REG_FILE_RS2 : alu_2 = reg_rd2;
      REG_FILE_RS2 : alu_2 = reg_rs2;
      IMMEDIATE : alu_2 = immediate;
    endcase
  end


@@ 169,8 169,8 @@ module cpu(
    .a3(reg_a_w),
    .we3(reg_we),
    .wd3(reg_write),
    .rd1(reg_rd1),
    .rd2(reg_rd2)
    .rd1(reg_rs1),
    .rd2(reg_rs2)
  );

  program_counter program_counter_inst(

M src/cpu_types.sv => src/cpu_types.sv +4 -10
@@ 40,8 40,8 @@ package cpu_types;
  // of getting it from the register. Additionaly, if the data
  // are invalid, stalling will be necessary.
  typedef struct {
    bit [4:0]  address; // The address the data will be written to
    bit [31:0] data; // The data to be written to the address
    bit [4:0]  target; // The address the data will be written to
    bit [31:0] value; // The data to be written to the address
    bit        valid; // Are the data valid? (data will be invalid for memory operations in execute stage)
  } register_data_status_t;



@@ 57,17 57,11 @@ package cpu_types;

    bit [31:0] pc;

    bit [31:0] reg_rd1;
    bit [31:0] reg_rd2;
    bit [31:0] reg_rs1;
    bit [31:0] reg_rs2;

    bit valid;
    bit ready;
    // !ready == stall
  } stage_status_t;

  const int FETCH = 0;
  const int DECODE = 1;
  const int EXECUTE = 2;
  const int ACCESS = 3;
  const int WRITEBACK = 4;
endpackage

M src/forwarder.sv => src/forwarder.sv +6 -6
@@ 21,19 21,19 @@ module forwarder(
    data = register_file_data;
    forwarding = 0;

    if (read_address != 0 && data_in_pipeline.execute_out.address == read_address) begin
    if (read_address != 0 && data_in_pipeline.execute_out.target == read_address) begin
      stall = !data_in_pipeline.execute_out.valid;
      data = data_in_pipeline.execute_out.data;
      data = data_in_pipeline.execute_out.value;
      forwarding = 1;
    end
    else if (read_address != 0 && data_in_pipeline.access_out.address == read_address) begin
    else if (read_address != 0 && data_in_pipeline.access_out.target == read_address) begin
      stall = !data_in_pipeline.access_out.valid;
      data = data_in_pipeline.access_out.data;
      data = data_in_pipeline.access_out.value;
      forwarding = 1;
    end
    else if (read_address != 0 && data_in_pipeline.writeback_in.address == read_address) begin
    else if (read_address != 0 && data_in_pipeline.writeback_in.target == read_address) begin
      stall = !data_in_pipeline.writeback_in.valid;
      data = data_in_pipeline.writeback_in.data;
      data = data_in_pipeline.writeback_in.value;
      forwarding = 1;
    end
  end

M src/stages/decode.sv => src/stages/decode.sv +16 -16
@@ 7,8 7,8 @@ module decode(

  output [4:0] reg_a_1,
  output [4:0] reg_a_2,
  input [31:0] reg_rd1,
  input [31:0] reg_rd2,
  input [31:0] reg_rs1,
  input [31:0] reg_rs2,

  input        flush,



@@ 28,19 28,19 @@ module decode(
  alu_2_source_t alu_2_src;

  wire        stall_1, stall_2;
  wire [31:0] forwarded_reg_rd1, forwarded_reg_rd2;
  wire [31:0] forwarded_reg_rs1, forwarded_reg_rs2;

  wire        memory_we;

  assign stage_out.data.address = reg_we && !stalling ? reg_rd : 0;
  assign stage_out.data.target = reg_we && !stalling ? reg_rd : 0;
  assign stage_out.data.valid = 0; // the data cannot be valid at this point;

  assign stage_out.pc = stage_in.pc;

  assign stage_out.instruction.reg_we = reg_we;

  assign stage_out.reg_rd1 = forwarded_reg_rd1;
  assign stage_out.reg_rd2 = forwarded_reg_rd2;
  assign stage_out.reg_rs1 = forwarded_reg_rs1;
  assign stage_out.reg_rs2 = forwarded_reg_rs2;

  assign stage_out.instruction.memory_we = memory_we;



@@ 78,32 78,32 @@ module decode(
  forwarder forwarder_a_inst(
    .clk(clk),
    .read_address(reg_a_1),
    .register_file_data(reg_rd1),
    .register_file_data(reg_rs1),
    .data_in_pipeline(data_in_pipeline),
    .stall(stall_1),
    .forwarding(),
    .data(forwarded_reg_rd1)
    .data(forwarded_reg_rs1)
  );

  forwarder forwarder_b_inst(
    .clk(clk),
    .read_address(reg_a_2),
    .register_file_data(reg_rd2),
    .register_file_data(reg_rs2),
    .data_in_pipeline(data_in_pipeline),
    .stall(stall_2),
    .forwarding(),
    .data(forwarded_reg_rd2)
    .data(forwarded_reg_rs2)
  );

  // stalling logic
  //   if should use reg_rd1 => wait until stall_1 == 0
  //   if should use reg_rd2 => wait until stall_2 == 0
  wire uses_reg_rd1, uses_reg_rd2;
  assign uses_reg_rd1 = (alu_1_src == REG_FILE_RS1);
  assign uses_reg_rd2 = (alu_2_src == REG_FILE_RS2) || memory_we;
  //   if should use reg_rs1 => wait until stall_1 == 0
  //   if should use reg_rs2 => wait until stall_2 == 0
  wire uses_reg_rs1, uses_reg_rs2;
  assign uses_reg_rs1 = (alu_1_src == REG_FILE_RS1);
  assign uses_reg_rs2 = (alu_2_src == REG_FILE_RS2) || memory_we;

  wire stalling;
  assign stalling = (uses_reg_rd1 && stall_1) || (uses_reg_rd2 && stall_2);
  assign stalling = (uses_reg_rs1 && stall_1) || (uses_reg_rs2 && stall_2);
  assign stage_out.valid = !flush && !stalling && stage_in.valid;
  assign stage_out.ready = !stalling || !stage_in.valid;
    // if input is not valid, do not care about stalling...

M src/stages/execute.sv => src/stages/execute.sv +6 -6
@@ 16,11 16,11 @@ module execute(

  assign stage_out.instruction = stage_in.instruction;
  assign stage_out.pc = stage_in.pc;
  assign stage_out.reg_rd1 = stage_in.reg_rd1;
  assign stage_out.reg_rd2 = stage_in.reg_rd2;
  assign stage_out.reg_rs1 = stage_in.reg_rs1;
  assign stage_out.reg_rs2 = stage_in.reg_rs2;

  assign stage_out.data.address = stage_in.valid ? stage_in.data.address : 0;
  assign stage_out.data.data = stage_in.instruction.reg_rd_src == RD_PC_PLUS ? stage_in.pc + 4 : alu_out;
  assign stage_out.data.target = stage_in.valid ? stage_in.data.target : 0;
  assign stage_out.data.value = stage_in.instruction.reg_rd_src == RD_PC_PLUS ? stage_in.pc + 4 : alu_out;
  assign stage_out.data.valid = stage_in.valid && (stage_in.instruction.reg_rd_src != RD_MEMORY);

  assign stage_out.valid = stage_in.valid;


@@ 43,7 43,7 @@ module execute(
  // alu source 1
  always_comb begin
    case (stage_in.instruction.alu_1_src)
      REG_FILE_RS1 : alu_1 = stage_in.reg_rd1;
      REG_FILE_RS1 : alu_1 = stage_in.reg_rs1;
      PC : alu_1 = stage_in.pc;
    endcase
  end


@@ 51,7 51,7 @@ module execute(
  // alu source 2
  always_comb begin
    case (stage_in.instruction.alu_2_src)
      REG_FILE_RS2 : alu_2 = stage_in.reg_rd2;
      REG_FILE_RS2 : alu_2 = stage_in.reg_rs2;
      IMMEDIATE : alu_2 = stage_in.instruction.immediate;
    endcase
  end

M src/stages/memory_access.sv => src/stages/memory_access.sv +31 -35
@@ 3,7 3,7 @@ import cpu_types::*;
module memory_access(
  input             clk,

  input [31:0]      memory_out,
  input [31:0]      memory_read,
  output reg [3:0]  memory_byte_enable,
  output reg [31:0] memory_write,
  output            memory_we,


@@ 40,36 40,36 @@ module memory_access(
  endfunction

  reg [31:0]  read_data;
  reg [31:0]  stored_read_data;
  reg [31:0]  reg_read_data;
  reg         misaligned_access; // signals that two addresses will have to be accessed
  reg         offset_position;
  reg         misaligned_phase;
  wire        is_read;
  wire        is_write;
  wire [1:0]  bit_position;
  wire [1:0]  byte_position_offset;
  memory_mask_t       memory_mask;

  assign memory_mask = stage_in.instruction.memory_mask;
  assign is_read = stage_in.valid && stage_in.instruction.reg_rd_src == RD_MEMORY;
  assign is_write = stage_in.valid && stage_in.instruction.memory_we;
  assign bit_position = memory_address[1:0];
  assign byte_position_offset = memory_address[1:0];

  assign misaligned_access = (is_read || is_write) &&
                          ((bit_position == 2'b11 && memory_mask == MEM_HALFWORD) ||
                          (bit_position != 0 && memory_mask == MEM_WORD)); // for MEM_BYTE, cannot happen
                          ((byte_position_offset == 2'b11 && memory_mask == MEM_HALFWORD) ||
                          (byte_position_offset != 0 && memory_mask == MEM_WORD)); // for MEM_BYTE, cannot happen

  always_ff @ (posedge clk) begin
    stored_read_data = read_data;
    reg_read_data = read_data;

    if (misaligned_access) begin
      if (offset_position == 1'b1) begin
        offset_position = 1'b0;
      if (misaligned_phase == 1'b1) begin
        misaligned_phase = 1'b0;
      end
      else begin
        offset_position = offset_position + 1;
        misaligned_phase = misaligned_phase + 1;
      end
    end
    else begin
      offset_position = 1'b0;
      misaligned_phase = 1'b0;
    end
  end



@@ 77,26 77,22 @@ module memory_access(
    read_data = 32'bX;
    memory_write = 32'bX;
    memory_byte_enable = 4'bX;
    // regular access (or not access at all)
    if (misaligned_access == 1'b0) begin
      memory_byte_enable = mask_to_mask_bytes(.mask(memory_mask)) << bit_position;
      memory_write = stage_in.reg_rd2 << (8*bit_position);
    if (misaligned_phase == 1'b0) begin
      memory_byte_enable = mask_to_mask_bytes(.mask(memory_mask)) << byte_position_offset;
      memory_write = stage_in.reg_rs2 << (8*byte_position_offset);
      read_data = mem_sext_maybe(
          .num(memory_out >> (8 * bit_position)),
// for misaligned access, the byte that would be extended
// isn't loaded yet, so this is safe (won't extend to ones)
          .num(memory_read >> (8 * byte_position_offset)),
          .mask(memory_mask),
          .sext(stage_in.instruction.memory_sign_extension)
      );
    end // misaligned access:
    else if (offset_position == 1'b0) begin
      memory_byte_enable = mask_to_mask_bytes(.mask(memory_mask)) << bit_position;
      memory_write = stage_in.reg_rd2 << (8*bit_position);
      read_data = memory_out >> (8 * bit_position);
    end // second stage of misaligned access:
    else if (offset_position == 1'b1) begin
      memory_byte_enable = mask_to_mask_bytes(.mask(memory_mask)) >> (4 - {2'b0, bit_position});
      memory_write = stage_in.reg_rd2 >> (4 - {2'b0, bit_position})*8;
    else if (misaligned_phase == 1'b1) begin
      memory_byte_enable = mask_to_mask_bytes(.mask(memory_mask)) >> (4 - {2'b0, byte_position_offset});
      memory_write = stage_in.reg_rs2 >> (4 - {2'b0, byte_position_offset})*8;
      read_data = mem_sext_maybe(
        .num((memory_out << (4 - {2'b0, bit_position}) * 8) | stored_read_data),
        .num((memory_read << (4 - {2'b0, byte_position_offset}) * 8) | reg_read_data),
        .mask(memory_mask),
        .sext(stage_in.instruction.memory_sign_extension)
      );


@@ 104,7 100,7 @@ module memory_access(

  end

  assign memory_address = stage_in.data.data + {29'b0, offset_position, 2'b0};
  assign memory_address = stage_in.data.value + {29'b0, misaligned_phase, 2'b0};

  // 1. figure out if two addresses will have to be read
  // if yes, set ready to 0


@@ 117,16 113,16 @@ module memory_access(

  assign stage_out.instruction = stage_in.instruction;
  assign stage_out.pc = stage_in.pc;
  assign stage_out.reg_rd1 = stage_in.reg_rd1;
  assign stage_out.reg_rd2 = stage_in.reg_rd2;
  assign stage_out.reg_rs1 = stage_in.reg_rs1;
  assign stage_out.reg_rs2 = stage_in.reg_rs2;

  assign stage_out.data.valid = stage_in.valid && (offset_position == 1'b1 || !misaligned_access);
  assign stage_out.data.address = stage_in.valid ? stage_in.data.address : 0;
  assign stage_out.data.data =
  assign stage_out.data.valid = stage_in.valid && (misaligned_phase == 1'b1 || !misaligned_access);
  assign stage_out.data.target = stage_in.valid ? stage_in.data.target : 0;
  assign stage_out.data.value =
    is_read ?
        read_data :
        stage_in.data.data;
        stage_in.data.value;

  assign stage_out.valid = stage_in.valid && (offset_position == 1'b1 || !misaligned_access);
  assign stage_out.ready = offset_position == 1'b1 || !misaligned_access;
  assign stage_out.valid = stage_in.valid && (misaligned_phase == 1'b1 || !misaligned_access);
  assign stage_out.ready = misaligned_phase == 1'b1 || !misaligned_access;
endmodule

M src/stages/writeback.sv => src/stages/writeback.sv +3 -3
@@ 10,7 10,7 @@ module writeback(

  input         stage_status_t stage_in
);
  assign reg_a_write = stage_in.data.address;
  assign reg_we = stage_in.valid && stage_in.data.valid && stage_in.instruction.reg_we; // stage_in.data.address != 0
  assign reg_write = stage_in.data.data;
  assign reg_a_write = stage_in.data.target;
  assign reg_we = stage_in.valid && stage_in.data.valid && stage_in.instruction.reg_we; // stage_in.data.target != 0
  assign reg_write = stage_in.data.value;
endmodule

M testbench/tb_cpu_program.sv => testbench/tb_cpu_program.sv +1 -1
@@ 32,7 32,7 @@ module tb_cpu_program();
    .pc(pc),

    .memory_address(memory_address),
    .memory_out(memory_out),
    .memory_read(memory_out),
    .memory_write(memory_write),
    .memory_byte_enable(memory_write_byte_enable),
    .memory_we(memory_we),

Do not follow this link