rv32 core

鄭九彰

GitHub

Mission

The project is to enhence the 3-stage pipeline cpu

Use GitHub forks instead of creating a new repository!

1. Organizing Changes from Verilog v1 to v4

To start,from v1 to v4, they consistently increased the CPU frequency.
Therefore, for each update from v1 to v4, I will focus on how each revision managed to boost the frequency.

This is a 3-stage pipeline architecture:

Fetch & Decode
Execute
Memory & Writeback

v1

  • Architecture
    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

All RISC-V Load and Store instructions use the addition of a register and an immediate value (imm) to calculate addresses.
To handle misaligned access, the ALU calculation result is forwarded to the next address to read higher addresses, while the pipeline is stalled to read lower addresses.
It is believed that forwarding the ALU result to the next address extended the critical path, so optimizations began here.

The following operations were introduced:

  • Store the ALU output in a register.
  • Use a multiplexer (MUX) to choose between the incremented value of the previous ALU output or the ALU output itself.

v2

  • Architecture
    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

Differences from v1

Although the critical path became slightly longer, adding a register to store ALU outputs reduced the number of stalls and successfully increased the frequency.
v1:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

v2:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

It is evident that performance improved, but Load and Store instructions (memory access instructions) remained the critical path. Thus, improvements continued in this area.

v3

  • Architecture
    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

Differences from v2

An adder dedicated to calculating memory access locations was directly added to the circuit, reducing the delay caused by the original ALU MUX.

v4

Architecture

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

2. Based on v4, implement the complete RV32I and pass the tests from https://github.com/riscv-non-isa/riscv-arch-test.

Using SAIL as a reference and leveraging RISCOF to conduct our tests.

Run the following command to set up a RISCOF environment directly:

riscof setup --refname=sail_cSim --dutname=core  

# ref: Reference (using SAIL here)  
# dut: Name of the hardware under test  

The following folder structure will be generated:

├──config.ini                   # configuration file for riscof
├──core/                        # DUT plugin templates
   ├── env
   │   ├── link.ld              # DUT linker script
   │   └── model_test.h         # DUT specific header file
   ├── riscof_core.py           # DUT python plugin
   ├── core_isa.yaml            # DUT ISA yaml based on riscv-config
   └── core_platform.yaml       # DUT Platform yaml based on riscv-config
├──sail_cSim/                   # reference plugin templates
   ├── env
   │   ├── link.ld              # Reference linker script
   │   └── model_test.h         # Reference model specific header file
   ├── __init__.py
   └── riscof_sail_cSim.py      # Reference model python plugin.

Since I only need to test RV32I, I need to modify the core_isa.yaml file:

hart_ids: [0]
hart0:
  # ISA: RV32IMCZicsr_Zifencei
  ISA: RV32I
  physical_addr_sz: 32
  User_Spec_Version: '2.3'
  supported_xlen: [32]
  misa:
  #  reset-val: 0x40001104
   reset-val: 0x40000100  # Enable only the I extension instruction set
   rv32:
     accessible: true
     mxl:
       implemented: true
       type:
           warl:
              dependency_fields: []
              legal:
                - mxl[1:0] in [0x1]
              wr_illegal:
                - Unchanged
     extensions:
       implemented: true
       type:
           warl:
              dependency_fields: []
              legal:
                # - extensions[25:0] bitmask [0x0001104, 0x0000000]
                - extensions[25:0] bitmask [0x0000100, 0x0000000]  # Allow only the I extension instruction set
              wr_illegal:
                - Unchanged

The following steps need to be completed to successfully test the original Verilog code:

  1. Convert the generated ELF file into a binary file.
objcopy_cmd = f"riscv{self.xlen}-unknown-elf-objcopy -O binary {elf} my.bin"
  1. Convert the binary file into a hexadecimal format so that it can be used by my circuit.
bin2hex_cmd = "python //rv32_core/core/bin_to_hex.py my.bin code.mem"
==========================================================================================================================
# bin_to_hex.py
import sys

def bin_to_hex(bin_file, mem_file, width=4):
    with open(bin_file, 'rb') as f_in, open(mem_file, 'w') as f_out:
        while True:
            bytes_read = f_in.read(width)
            if not bytes_read:
                break
            bytes_read = bytes_read.ljust(width, b'\x00')
            # transfer to little endian
            word = int.from_bytes(bytes_read, byteorder='little')
            f_out.write("{:08x}\n".format(word))

if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("Usage: python bin_to_hex.py <input.bin> <output.mem>")
        sys.exit(1)
    bin_to_hex(sys.argv[1], sys.argv[2])

  1. Use iverilog to compile my hardware and testbench into an executable file.
iverilog_cmd = ( "iverilog -Wall -I //rv32_core/core -o simv -g2012 " + "//rv32_core/core/core.v " + "//rv32_core/core/alu.v " + "//rv32_core/core/br_unit.v " + "//rv32_core/core/csr.v " + "//rv32_core/core/decoder.v " + "//rv32_core/core/ma_ctrl.v " + "//rv32_core/core/r_data_fmt.v " + "//rv32_core/core/ram.v " + "//rv32_core/core/reg_file.v " + "//rv32_core/core/test_bench.v " )
  1. Perform the simulation and generate a .signature file for RISCOF to use for comparison.
vvp_cmd = (
                f"vvp simv +signature={sig_file} "
                f"+begin_signature=0x{begin_signature} +end_signature=0x{end_signature}"
            )
  1. Write a testbench and pass in the signature location for each test case to ensure data is correctly written.

  2. In the folder containing the config.ini file, use the following command:

riscof run --config config.ini --suite ../riscv-arch-test/riscv-test-suite/rv32i_m --env ../riscv-arch-test/riscv-test-suite/env/
  1. Results:
INFO | TEST NAME                                          : COMMIT ID                                : STATUS
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/add-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/addi-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/and-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/andi-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/auipc-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/beq-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/bge-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/bgeu-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/blt-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/bltu-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/bne-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/fence-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/jal-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/jalr-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/lb-align-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/lbu-align-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/lh-align-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/lhu-align-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/lui-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/lw-align-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/misalign1-jalr-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/or-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/ori-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/sb-align-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/sh-align-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/sll-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/slli-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/slt-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/slti-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/sltiu-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/sltu-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/sra-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/srai-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/srl-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/srli-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/sub-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/sw-align-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/xor-01.S : -                                        : Passed
    INFO | riscv-arch-test/riscv-test-suite/rv32i_m/I/src/xori-01.S : -                                        : Passed
    INFO | Test report generated at //rv32_core/riscof_work/report.html.
    INFO | Opening test report in web-browser

3. Implement RV32M

The RISCV RV32M Extension OPcode:
image

Since these operations require the ALU to perform different tasks, the original ALU's MUX is expanded from 4 bits to 5 bits, allowing for more options. Afterward, add the following circuit in alu.v:

casex(sel) `ALU_SEL_ADD: out = in1 + in2; `ALU_SEL_SUB: out = in1 - in2; `ALU_SEL_SLL: out = in1 << in2[4:0]; `ALU_SEL_SLT: out = in1 < in2; `ALU_SEL_SLTU: out = $unsigned(in1) < $unsigned(in2); `ALU_SEL_XOR: out = in1 ^ in2; `ALU_SEL_SRL: out = in1 >> in2[4:0]; `ALU_SEL_SRA: out = in1 >>> in2[4:0]; `ALU_SEL_OR: out = in1 | in2; `ALU_SEL_AND: out = in1 & in2; // RV32M extension instructions `ALU_SEL_MUL: begin mul_result_signed = in1 * in2; // Signed multiplication out = mul_result_signed[31:0]; // Lower 32 bits as the result end `ALU_SEL_MULH: begin mul_result_signed = in1 * in2; // Signed multiplication out = mul_result_signed[63:32]; // Upper 32 bits as the result end `ALU_SEL_MULHSU: begin mul_result_signed = $signed({{32{in1[31]}}, in1}) * $unsigned({32'b0, in2}); // Signed x Unsigned multiplication out = mul_result_signed[63:32]; // Upper 32 bits as the result end `ALU_SEL_MULHU: begin mul_result_unsigned = $unsigned(in1) * $unsigned(in2); // Unsigned multiplication out = mul_result_unsigned[63:32]; // Upper 32 bits as the result end `ALU_SEL_DIV: begin if (in2 != 0) begin div_result = in1 / in2; // Signed integer division out = div_result; end else begin out = 32'hffffffff; end end `ALU_SEL_DIVU: begin if (in2 != 0) begin div_result = $unsigned(in1) / $unsigned(in2); // Unsigned integer division out = div_result; end else begin out = 32'hffffffff; end end `ALU_SEL_REM: begin if (in2 != 0) begin rem_result = in1 % in2; // Signed remainder out = rem_result; end else begin out = in1; end end `ALU_SEL_REMU: begin if (in2 != 0) begin rem_result = $unsigned(in1) % $unsigned(in2); // Unsigned remainder out = rem_result; end else begin out = $unsigned(in1); end end default: out = in1; endcase

Abnormal issues:

  • rem: When encountering a remainder with a divisor of 0, directly output in1.
  • DIV: When encountering a division by 0, directly output 0xffffffff.
  • MULHSU: It requires sign extension of the signed number first; otherwise, it may cause errors with the sign of the result.

Results:

    INFO | TEST NAME                                          : COMMIT ID                                : STATUS
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/add-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/addi-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/and-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/andi-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/auipc-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/beq-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/bge-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/bgeu-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/blt-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/bltu-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/bne-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/fence-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/jal-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/jalr-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/lb-align-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/lbu-align-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/lh-align-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/lhu-align-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/lui-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/lw-align-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/misalign1-jalr-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/or-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/ori-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/sb-align-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/sh-align-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/sll-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/slli-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/slt-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/slti-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/sltiu-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/sltu-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/sra-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/srai-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/srl-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/srli-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/sub-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/sw-align-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/xor-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/I/src/xori-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/M/src/div-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/M/src/divu-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/M/src/mul-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/M/src/mulh-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/M/src/mulhsu-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/M/src/mulhu-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/M/src/rem-01.S : -                                        : Passed
    INFO | /riscv-arch-test/riscv-test-suite/rv32i_m/M/src/remu-01.S : -                                        : Passed
    INFO | Test report generated at //rv32_core/riscof_work/report.html.
    INFO | Opening test report in web-browser

4. Implement B extension

The OPCODE and corresponding operation for each instruction can be referenced as Reference.

Since these operations require the ALU to perform different tasks, the original ALU's MUX is expanded from 5 bits to 6 bits, allowing for more options. Afterward, add the following circuit in alu.v:

`ALU_SEL_ANDN:      out = in1 & ~in2;                      // AND NOT
`ALU_SEL_ORN:       out = in1 | ~in2;                      // OR NOT
`ALU_SEL_XNOR:      out = ~(in1 ^ in2);                    // XOR NOT
`ALU_SEL_CLZ: begin
    out = (in1[31] == 1) ? 0 :
        (in1[30] == 1) ? 1 :
        (in1[29] == 1) ? 2 :
        (in1[28] == 1) ? 3 :
        (in1[27] == 1) ? 4 :
        (in1[26] == 1) ? 5 :
        (in1[25] == 1) ? 6 :
        (in1[24] == 1) ? 7 :
        (in1[23] == 1) ? 8 :
        (in1[22] == 1) ? 9 :
        (in1[21] == 1) ? 10 :
        (in1[20] == 1) ? 11 :
        (in1[19] == 1) ? 12 :
        (in1[18] == 1) ? 13 :
        (in1[17] == 1) ? 14 :
        (in1[16] == 1) ? 15 :
        (in1[15] == 1) ? 16 :
        (in1[14] == 1) ? 17 :
        (in1[13] == 1) ? 18 :
        (in1[12] == 1) ? 19 :
        (in1[11] == 1) ? 20 :
        (in1[10] == 1) ? 21 :
        (in1[9]  == 1) ? 22 :
        (in1[8]  == 1) ? 23 :
        (in1[7]  == 1) ? 24 :
        (in1[6]  == 1) ? 25 :
        (in1[5]  == 1) ? 26 :
        (in1[4]  == 1) ? 27 :
        (in1[3]  == 1) ? 28 :
        (in1[2]  == 1) ? 29 :
        (in1[1]  == 1) ? 30 :
        (in1[0]  == 1) ? 31 : 32;
end

`ALU_SEL_CTZ: begin
    out = (in1[0] == 1) ? 0 :
        (in1[1] == 1) ? 1 :
        (in1[2] == 1) ? 2 :
        (in1[3] == 1) ? 3 :
        (in1[4] == 1) ? 4 :
        (in1[5] == 1) ? 5 :
        (in1[6] == 1) ? 6 :
        (in1[7] == 1) ? 7 :
        (in1[8] == 1) ? 8 :
        (in1[9] == 1) ? 9 :
        (in1[10] == 1) ? 10 :
        (in1[11] == 1) ? 11 :
        (in1[12] == 1) ? 12 :
        (in1[13] == 1) ? 13 :
        (in1[14] == 1) ? 14 :
        (in1[15] == 1) ? 15 :
        (in1[16] == 1) ? 16 :
        (in1[17] == 1) ? 17 :
        (in1[18] == 1) ? 18 :
        (in1[19] == 1) ? 19 :
        (in1[20] == 1) ? 20 :
        (in1[21] == 1) ? 21 :
        (in1[22] == 1) ? 22 :
        (in1[23] == 1) ? 23 :
        (in1[24] == 1) ? 24 :
        (in1[25] == 1) ? 25 :
        (in1[26] == 1) ? 26 :
        (in1[27] == 1) ? 27 :
        (in1[28] == 1) ? 28 :
        (in1[29] == 1) ? 29 :
        (in1[30] == 1) ? 30 :
        (in1[31] == 1) ? 31 : 32;
end

`ALU_SEL_CPOP: begin
    out = in1[0]  + in1[1]  + in1[2]  + in1[3]  +
        in1[4]  + in1[5]  + in1[6]  + in1[7]  +
        in1[8]  + in1[9]  + in1[10] + in1[11] +
        in1[12] + in1[13] + in1[14] + in1[15] +
        in1[16] + in1[17] + in1[18] + in1[19] +
        in1[20] + in1[21] + in1[22] + in1[23] +
        in1[24] + in1[25] + in1[26] + in1[27] +
        in1[28] + in1[29] + in1[30] + in1[31];
end

`ALU_SEL_MAX:       out = (in1 > in2) ? in1 : in2;         // Signed Maximum
`ALU_SEL_MAXU:      out = ($unsigned(in1) > $unsigned(in2)) ? in1 : in2; // Unsigned Maximum
`ALU_SEL_MIN:       out = (in1 < in2) ? in1 : in2;         // Signed Minimum
`ALU_SEL_MINU:      out = ($unsigned(in1) < $unsigned(in2)) ? in1 : in2; // Unsigned Minimum
`ALU_SEL_ROL:       out = (in1 << in2[4:0]) | (in1 >> (32 - in2[4:0])); // Rotate Left
`ALU_SEL_ROR:       out = (in1 >> in2[4:0]) | (in1 << (32 - in2[4:0])); // Rotate Right 、 RORI 
`ALU_SEL_REV8:      out = {in1[7:0], in1[15:8], in1[23:16], in1[31:24]}; // Reverse Bytes
`ALU_SEL_ORCB: begin
    out = { 
        (in1[31:24] == 8'b0) ? 8'b00000000 : 8'b11111111, 
        (in1[23:16] == 8'b0) ? 8'b00000000 : 8'b11111111, 
        (in1[15:8]  == 8'b0) ? 8'b00000000 : 8'b11111111, 
        (in1[7:0]   == 8'b0) ? 8'b00000000 : 8'b11111111 
    };
end

`ALU_SEL_SEXT_B:    out = {{24{in1[7]}}, in1[7:0]};         // Sign Extend Byte
`ALU_SEL_SEXT_H:    out = {{16{in1[15]}}, in1[15:0]};       // Sign Extend Halfword
`ALU_SEL_ZEXT_H:    out = {16'b0, in1[15:0]};               // Zero Extend Halfword

Results:

INFO | Running Tests on Reference Model.
    INFO | Initiating signature checking.
    INFO | Following 65 tests have been run :

    INFO | TEST NAME                                          : COMMIT ID                                : STATUS
    INFO | /home/eason/Desktop/ComputerArchitecture/Final_Project/riscv-arch-test/riscv-test-suite/rv32i_m/B/src/andn-01.S : -                                        : Passed
    INFO | /home/eason/Desktop/ComputerArchitecture/Final_Project/riscv-arch-test/riscv-test-suite/rv32i_m/B/src/clz-01.S : -                                        : Passed
    INFO | /home/eason/Desktop/ComputerArchitecture/Final_Project/riscv-arch-test/riscv-test-suite/rv32i_m/B/src/cpop-01.S : -                                        : Passed
    INFO | /home/eason/Desktop/ComputerArchitecture/Final_Project/riscv-arch-test/riscv-test-suite/rv32i_m/B/src/ctz-01.S : -                                        : Passed
    INFO | /home/eason/Desktop/ComputerArchitecture/Final_Project/riscv-arch-test/riscv-test-suite/rv32i_m/B/src/max-01.S : -                                        : Passed
    INFO | /home/eason/Desktop/ComputerArchitecture/Final_Project/riscv-arch-test/riscv-test-suite/rv32i_m/B/src/maxu-01.S : -                                        : Passed
    INFO | /home/eason/Desktop/ComputerArchitecture/Final_Project/riscv-arch-test/riscv-test-suite/rv32i_m/B/src/min-01.S : -                                        : Passed
    INFO | /home/eason/Desktop/ComputerArchitecture/Final_Project/riscv-arch-test/riscv-test-suite/rv32i_m/B/src/minu-01.S : -                                        : Passed
    INFO | /home/eason/Desktop/ComputerArchitecture/Final_Project/riscv-arch-test/riscv-test-suite/rv32i_m/B/src/orcb_32-01.S : -                                        : Passed
    INFO | /home/eason/Desktop/ComputerArchitecture/Final_Project/riscv-arch-test/riscv-test-suite/rv32i_m/B/src/orn-01.S : -                                        : Passed
    INFO | /home/eason/Desktop/ComputerArchitecture/Final_Project/riscv-arch-test/riscv-test-suite/rv32i_m/B/src/rev8_32-01.S : -                                        : Passed
    INFO | /home/eason/Desktop/ComputerArchitecture/Final_Project/riscv-arch-test/riscv-test-suite/rv32i_m/B/src/rol-01.S : -                                        : Passed
    INFO | /home/eason/Desktop/ComputerArchitecture/Final_Project/riscv-arch-test/riscv-test-suite/rv32i_m/B/src/ror-01.S : -                                        : Passed
    INFO | /home/eason/Desktop/ComputerArchitecture/Final_Project/riscv-arch-test/riscv-test-suite/rv32i_m/B/src/rori-01.S : -                                        : Passed
    INFO | /home/eason/Desktop/ComputerArchitecture/Final_Project/riscv-arch-test/riscv-test-suite/rv32i_m/B/src/sext.b-01.S : -                                        : Passed
    INFO | /home/eason/Desktop/ComputerArchitecture/Final_Project/riscv-arch-test/riscv-test-suite/rv32i_m/B/src/sext.h-01.S : -                                        : Passed
    INFO | /home/eason/Desktop/ComputerArchitecture/Final_Project/riscv-arch-test/riscv-test-suite/rv32i_m/B/src/xnor-01.S : -                                        : Passed
    INFO | /home/eason/Desktop/ComputerArchitecture/Final_Project/riscv-arch-test/riscv-test-suite/rv32i_m/B/src/zext.h_32-01.S : -                                        : Passed

Validations

Select at least 3 RISC-V programs from the course quizzes, rewrite them, and make them executable on your extended RV32 processor.

1. Quiz2 Problem A: shift-and-add multiplication

Origin Version:

.data multiplier: .word -9 multiplicand: .word 7 result: .word 0 .text la a0, multiplier # Load multiplier address lw a1, 0(a0) # Load multiplier value la a2, multiplicand # Load multiplicand address lw a3, 0(a2) # Load multiplicand value li t0, 0 # Initialize accumulator li t1, 32 # Set bit counter (#A01) # Check for negative values bltz a1, handle_negative1 # If multiplier negative (#A02) j shift_and_add_loop # Skip to main loop (#A05) bltz a3, handle_negative2 # If multiplicand negative (#A03) j shift_and_add_loop # Continue to main loop (#A04) handle_negative1: neg a1, a1 # Make multiplier positive handle_negative2: neg a3, a3 # Make multiplicand positive shift_and_add_loop: beqz t1, end_shift_and_add # Exit if bit count is zero andi t2, a1, 1 # Check least significant bit (#A06) beqz t2, skip_add # Skip add if bit is 0 add t0, t0, a3 # Add to accumulator skip_add: srai a1, a1, 1 # Right shift multiplier slli a3, a3, 1 # Left shift multiplicand addi t1, t1, -1 # Decrease bit counter j shift_and_add_loop # Repeat loop (#A07) end_shift_and_add: la a4, result # Load result address sw t0, 0(a4) # Store final result (#A08)

My CPU does not support the li, la, and neg instructions, so modifications are required.

.data multiplier: .word -9 multiplicand: .word 7 result: .word 0 .text # using lui and addi replace la lui a0, %hi(multiplier) # Load the upper 20 bits of multiplier address addi a0, a0, %lo(multiplier) # Add the lower 12 bits to complete the address lw a1, 0(a0) # Load multiplier value lui a2, %hi(multiplicand) # Load the upper 20 bits of multiplicand address addi a2, a2, %lo(multiplicand) # Add the lower 12 bits lw a3, 0(a2) # Load multiplicand value # Initialize accumulator (t0 = 0) lui t0, 0 # Load upper 20 bits (0) into t0 addi t0, t0, 0 # Add lower 12 bits (0) to t0 # Initialize bit counter (t1 = 32) lui t1, 0 # Load upper 20 bits (0) into t1 addi t1, t1, 32 # Add lower 12 bits (32) to t1 # Check for negative values bltz a1, handle_negative1 # If multiplier negative, go to handle_negative1 j shift_and_add_loop # Skip to main loop bltz a3, handle_negative2 # If multiplicand negative, go to handle_negative2 j shift_and_add_loop # Continue to main loop handle_negative1: # using 0 - reg replace neg add t2, zero, zero # t2 = 0 sub a1, t2, a1 # a1 = 0 - a1 j shift_and_add_loop # Jump back to main loop handle_negative2: add t2, zero, zero # t2 = 0 sub a3, t2, a3 # a3 = 0 - a3 j shift_and_add_loop # Jump back to main loop shift_and_add_loop: beqz t1, end_shift_and_add # Exit if bit count is zero andi t2, a1, 1 # Check least significant bit of a1 beqz t2, skip_add # Skip add if bit is 0 add t0, t0, a3 # Add a3 to accumulator (t0) skip_add: srai a1, a1, 1 # Right shift a1 (logical shift) slli a3, a3, 1 # Left shift a3 addi t1, t1, -1 # Decrement bit counter j shift_and_add_loop # Repeat loop end_shift_and_add: lui a4, %hi(result) # Load the upper 20 bits of result address addi a4, a4, %lo(result) # Add the lower 12 bits sw t0, 0(a4) # Store accumulator (t0) in result

Similarly, create a Python script to execute instructions that convert assembly code into 16-bit machine code.

# test.py: import os import subprocess import sys def run_command(command, cwd=None): try: print(f"run command: {command}") result = subprocess.run(command, shell=True, cwd=cwd, check=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) print(result.stdout) except subprocess.CalledProcessError as e: print(f"Fail: {command}") print(e.stderr) sys.exit(1) def compile_to_elf(source_file, output_elf, linker_script, include_dirs = None): # include_flags = " ".join([f"-I {include}" for include in include_dirs]) compile_cmd = f"riscv32-unknown-elf-gcc -march=rv32i -static -mcmodel=medany -fvisibility=hidden " \ f"-nostdlib -nostartfiles -g -T {linker_script} -o {output_elf} {source_file}" run_command(compile_cmd) def elf_to_bin(elf_file, bin_file): objcopy_cmd = f"riscv32-unknown-elf-objcopy -O binary {elf_file} {bin_file}" run_command(objcopy_cmd) def bin_to_hex(bin_file, hex_file, script_path): bin2hex_cmd = f"python {script_path} {bin_file} {hex_file}" run_command(bin2hex_cmd) def load_to_hardware(hex_file, Verilog_main, verilog_testbench, simulation_directory, iverilog_path="iverilog", vvp_path="vvp"): compile_cmd = f"{iverilog_path} -Wall -I /home/eason/Desktop/ComputerArchitecture/Final_Project/rv32_core/core/src/main -o simv -g2012 {Verilog_main} {verilog_testbench}" run_command(compile_cmd, cwd=simulation_directory) # run simulate simulation_cmd = f"{vvp_path} simv" run_command(simulation_cmd, cwd=simulation_directory) def main(): # path source_file = "shift_and_add_mul.S" # target assembly code output_elf = f"{source_file}.elf" # .elf file output_bin = f"{source_file}.bin" # binary file output_hex = f"{source_file}.mem" # HEX file linker_script = "./env/link.ld" # Linker script bin_to_hex_script = "./bin_to_hex.py" # bin_to_hex.py verilog_testbench = "../core/src/test/test_bench.v" # Verilog test_bench Verilog_main = ( "/home/eason/Desktop/ComputerArchitecture/Final_Project/rv32_core/core/src/main/core.v " + "/home/eason/Desktop/ComputerArchitecture/Final_Project/rv32_core/core/src/main/alu.v " + "/home/eason/Desktop/ComputerArchitecture/Final_Project/rv32_core/core/src/main/br_unit.v " + "/home/eason/Desktop/ComputerArchitecture/Final_Project/rv32_core/core/src/main/csr.v " + "/home/eason/Desktop/ComputerArchitecture/Final_Project/rv32_core/core/src/main/decoder.v " + "/home/eason/Desktop/ComputerArchitecture/Final_Project/rv32_core/core/src/main/ma_ctrl.v " + "/home/eason/Desktop/ComputerArchitecture/Final_Project/rv32_core/core/src/main/r_data_fmt.v " + "/home/eason/Desktop/ComputerArchitecture/Final_Project/rv32_core/core/src/main/ram.v " + "/home/eason/Desktop/ComputerArchitecture/Final_Project/rv32_core/core/src/main/reg_file.v ") simulation_directory = "./" if not os.path.exists(source_file): print(f"File Not Found: {source_file}") sys.exit(1) if not os.path.exists(linker_script): print(f"Linker Script Not Found: {linker_script}") sys.exit(1) # compile .S 2 .elf # compile_to_elf(source_file, output_elf, linker_script, include_dirs) compile_to_elf(source_file, output_elf, linker_script) # transfer .elf 2 binary elf_to_bin(output_elf, output_bin) # transfer binary 2 hex bin_to_hex(output_bin, output_hex, bin_to_hex_script) print(f"Generate Success: {output_hex}") print(f"Start Simulation...") load_to_hardware(output_hex, Verilog_main, verilog_testbench, simulation_directory) print("simulation done") if __name__ == "__main__": main()

Run this command under the test.py folder to perform the test:

python test.py

Results:

Result in memory: 0000003f

During program execution, through the VSD file, I observed that the value was written to the memory address 0x1008. However, when I checked through the test bench, it was at line 1026. I'm not quite sure why the .data section starts from line 1024.

2.

  1. Always write in English.
  2. Be aware of the indention. Use ## and ### explicitly.
  3. Check the permissions of uploaded pictures.