鄭九彰
The project is to enhence the 3-stage pipeline cpu。
Use GitHub forks instead of creating a new repository!
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
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:
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:
v2:
It is evident that performance improved, but Load and Store instructions (memory access instructions) remained the critical path. Thus, improvements continued in this area.
An adder dedicated to calculating memory access locations was directly added to the circuit, reducing the delay caused by the original ALU MUX.
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:
objcopy_cmd = f"riscv{self.xlen}-unknown-elf-objcopy -O binary {elf} my.bin"
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])
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 "
)
vvp_cmd = (
f"vvp simv +signature={sig_file} "
f"+begin_signature=0x{begin_signature} +end_signature=0x{end_signature}"
)
Write a testbench and pass in the signature location for each test case to ensure data is correctly written.
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/
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
The RISCV RV32M Extension OPcode:
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:
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
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
Select at least 3 RISC-V programs from the course quizzes, rewrite them, and make them executable on your extended RV32 processor.
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.
##
and ###
explicitly.