Try   HackMD

RV32C support for srv32

宋唯廷, 劉孟璋

The RV32IM, RV32C, SRV32 sections of this note serve as the theoretical notes.
The implementation part of srv32c starts from the Implementation section.

GitHub


RV32IM

Format

R-Type

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 →

inst length
op 7-bit [0-6]
rd 5-bit [7-11]
funct3 3-bit [12-14]
rs1 5-bit [15-19]
rs2 5-bit [20-24]
funct7 7-bit [25-31]

instructions - SLT, SLTU, AND, OR, XOR, SLL, SRL, SRA, ADD, SUB, MUL, MULH, MULSU, MULU, DIV, DIVU, REM, REMU

M-extension instructions expande to R-Type format


I-Type

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 →

inst length
op 7-bit [0-6]
rd 5-bit [7-11]
funct3 3-bit [12-14]
rs1 5-bit [15-19]
imm 12-bit [20-31]

instructions - ADDI, SLTI, SLTIU, ANDI, ORI, XORI, SLLI, SLRI, SRAI, LW, LH, LHU, LB, LBU


S-Type

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 →

inst length
op 7-bit [0-6]
imm 5-bit [7-11]
funct3 3-bit [12-14]
rs1 5-bit [15-19]
rs2 5-bit [20-24]
imm 7-bit [25-31]

instructions - SB, SH, SW


B-Type

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 →

inst length
op 7-bit [0-6]
imm 1-bit [7]
imm 4-bit [8-11]
funct3 3-bit [12-14]
rs1 5-bit [15-19]
rs2 5-bit [20-24]
imm 6-bit [25-30]
imm 1-bit [31]

instructions - BEQ, BNE, BLT, BLTU, BGE, BGEU


U-Type

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 →

inst length
op 7-bit [0-6]
rd 5-bit [7-11]
imm 20-bit [12-31]

instructions - LUI, AUIPC


J-Type

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 →

inst length
op 7-bit [0-6]
rd 5-bit [7-11]
imm 8-bit [12-19]
imm 1-bit [20]
imm 10-bit [21-30]
imm 1-bit [31]

instructions - JAL, JALR


NOP

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 →

instructions - NOP

NOP instruction is encoded as ADDI x0, x0, 0


SYSTEM

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 →

instructions - ECALL, EBREAK


Decode

op description type
0110011 arithmetic between reg and reg R-Type
0010011 arithmetic between reg and imm I-Type
0010011 load data
0100011 store data S-Type
1100011 conditional branch B-Type
0010011 upper imm arithmetic U-Type
0110111
1101111 unconditional jump J-Type
1100111

RV32C

Introduction

When certain 32-bit instructions have specific characteristics that allow them to be converted into compressed instructions:

  1. the immediate or address offset is small
  2. one of the registers is the zero register (x0), the ABI link register (x1), or the ABI stack pointer (x2)
  3. the destination register and the first source register are identical
  4. the registers used are the 8 most popular ones (x8 - x15). This is also the reason why some register fields in the C extension instructions are only 3 bits long

RVC is designed such that each compressed instruction maps directly to a single 32-bit instruction in the base ISA (e.g., RV32I/E, RV64I, RV128I) or the F/D extensions. This design offers two key benefits:

  1. Simplified Hardware: Hardware can expand RVC instructions during decoding, minimizing changes to existing microarchitectures and simplifying verification.
  2. Compiler Flexibility: Compilers do not need to be aware of RVC; compression can be handled by the assembler and linker. However, compression-aware compilers can produce better results.

The C extension integrates seamlessly with other standard extensions (e.g., M, A, F) without restricting functionality or reducing architectural flexibility.

The C extension is not a standalone ISA and must be used alongside a base ISA.

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 →


Format

CR-Type

Instructions for arithmetic operations between registers

image

inst length
op 2-bit [0-1]
rs2 5-bit [2-6]
rs1/rd 5-bit [7-11]
funct4 4-bit [12-15]

instructions - C.JR, C.JALR, C.MV, C.ADD


CI-Type

Instructions for arithmetic operations between immediate value and register

image

inst length
op 2-bit [0-1]
imm 5-bit [2-6]
rs1/rd 5-bit [7-11]
imm 1-bit [12]
funct3 3-bit [13-15]

instructions - C.LWSP, C.LDSP, C.LQSP, C.FLWSP, C.FLDSP, C.LI, C.LUI, C.ADDI, C.ADDIW, C.ADDI16SP, C.SLLI


CSS-Type

Instructions for stack-pointer-based stores

image

inst length
op 2-bit [0-1]
rs2 5-bit [2-6]
imm 1-bit [7-12]
funct3 3-bit [13-15]

instructions - C.SWSP, C.SDSP, C.SQSP, C.FSWSP, C.FSDSP


CIW-Type

Instructions for stack-pointer-based loads

image

inst length
op 2-bit [0-1]
rd' 3-bit [2-4]
imm 8-bit [5-12]
funct3 3-bit [13-15]

instructions - C.ADDI4SPN


CL-Type

Instructions for register-based loads

image

inst length
op 2-bit [0-1]
rd' 3-bit [2-4]
imm 2-bit [5-6]
rs1' 3-bit [7-9]
imm 2-bit [10-12]
funct3 3-bit [13-15]

instructions - C.LW, C.LD, C.LQ, C.FLW, C.FLD


CS-Type

Instructions for register-based stores

image

inst length
op 2-bit [0-1]
rs2' 3-bit [2-4]
imm 2-bit [5-6]
rs1' 3-bit [7-9]
imm 3-bit [10-12]
funct3 3-bit [13-15]

instructions - C.SW, C.SD, C.SQ, C.FSW, C.FSD


CA-Type

Instructions for atomic operations between immediate value and register

image

inst length
op 2-bit [0-1]
rs2' 3-bit [2-4]
funct2 2-bit [5-6]
rs1'/rd' 3-bit [7-9]
funct6 6-bit [10-15]

instructions - C.AND, C.OR, C.XOR, C.SUB


CB-Type

Instructions for conditional control transfers / register shift

image

inst length
op 2-bit [0-1]
imm 5-bit [2-6]
rs1' 3-bit [7-9]
imm 3-bit [10-12]
funct3 3-bit [13-15]

instructions - C.BEQZ, C.BNEZ, C.SRLI, C.SRAI, C.ANDI


CJ-Type

Instructions for unconditional control transfers

image

inst length
op 2-bit [0-1]
imm 11-bit [2-12]
funct3 3-bit [13-15]

instructions - C.J, C.JAL


NOP

image
instructions - C.NOP


Breakpoint

image
instructions - C.EBREAK


Illegal

image




Decode

Type Decode

The following is the decoding method for C-Extension instructions.

op func3 type
10 100 CR-type
01 000 CI-type
010
011
10 000
010
10 110 CSS-type
00 000 CIW-type
00 010 CL-type
00 110 CS-type
01 100 CA-type
01 100 CB-type
110
111
01 001 CJ-type
101

It can be observed that most of the C-extension instructions can be directly decoded using the op and func3. However, when op=01 and func3=100, two different instruction formats (CA-type and CB-type) can be decoded.


op func3 inst[11:10] type
01 100 11 CA-type
00 CB-type
01
10
110 -
111

Therefore, in the case where op=01 and func3=100, we will need an additional 2 bits inst[11:10] to assist in decoding.


Register Decode

  • CR-Type, CI-Type, and CSS-Type instructions can use any of the RV32I registers (x0-x31)

    This means that the register field (rs1 / rs2 / rd) length of these three types of instructions is as same as normal instructions (5-bit).

  • CIW-Type, CL-Type, CS-Type, CA-Type, and CB-Type instructions are limited to just 8 of them (x8-x15)

    This means that the register field (rs1' / rs2' / rd') length of these five types is shorter than normal instructions (3-bit)

    The regisers are mapped to x8 - x15

    reg(3-bit) mapped reg(5-bit)
    x0 000 x8 ( s0 ) 01000
    x1 001 x9 ( s1 ) 01001
    x2 010 x10 ( a0 ) 01010
    x3 011 x11 ( a1 ) 01011
    x4 100 x12 ( a2 ) 01100
    x5 101 x13 ( a3 ) 01101
    x6 110 x14 ( a4 ) 01110
    x7 111 x15 ( a5 ) 01111

Expansion

Each C Extension instructions usually corresponds to a base instruction

CR-type

RV32C RV32I Description
C.JALR JALR Perform an unconditional control transfer to the address in register rs1 and write the address of the instruction following the jump (pc+2) to the link register.
C.JR JALR Perform an unconditional control transfer to the address in register rs1
C.ADD ADD Add the values in registers rd and rs2 and write the result to register rd
C.MV ADD Copy the value in register rs2 into register rd
  • C.JALR expands to jalr x0, 0(rs1)
  • C.JR expands to jalr x1, 0(rs1)
  • C.ADD expands to add rd, rd, rs2
  • C.MV expands to add rd, x0, rs2

CI-type

RV32C RV32I Description
C.LUI LUI Load the non-zero 6-bit immediate field into bits 17–12 of the destination register, clear the bottom 12 bits, and sign-extend bit 17 into all higher bits of the destination
C.LI ADDI Load the sign-extended 6-bit immediate, imm, into register rd
C.ADDI ADDI Add the non-zero sign-extended 6-bit immediate to the value in register rd then writes the result to rd
C.ADDI16SP ADDI Add the non-zero sign-extended 6-bit immediate to the value in the stack pointer (x2), usually be used to adjust the stack pointer in procedure prologues and epilogues
C.SLLI SLLI Load the sign-extended 6-bit immediate, `imm`, into register rd
C.LWSP LW Loads a 32-bit value from memory into register rd
  • C.LUI expands to lui rd, nzimm
  • C.LI expands to addi rd, x0, imm
  • C.ADDI expands to addi rd, rd, nzimm
  • C.ADDI16SP expands to addi x2, x2, nzimm
  • C.SLLI expands to slli rd, rd, shamt
  • C.LWSP expands to lw rd, offset(x2)

C.ADDI is valid when rd!=x0 and imm!=0,
The code points with rd=x0 encode the C.NOP,
The code points with imm=0 encode the C.HINT


CSS-type

RV32C RV32I Description
C.SWSP SW Store a 32-bit value in register rs2 to memory. It computes an effective address by adding the zero-extended offset, scaled by 4, to the stack pointer (x2)
  • C.SWSP expands to sw rs2, offset(x2)

CIW-type

RV32C RV32I Description
C.ADDI4SPN ADDI Add a zero-extended non-zero immediate, scaled by 4, to the stack pointer (x2), and write the result to rd '
  • C.ADDI4SPN expands to addi rd ', x2, nzuimm

CL-type

RV32C RV32I Description
C.LW LW Load a 32-bit value from memory into register rd '
  • C.LW expands to lw rd, offset(rs1')

CS-type

RV32C RV32I Description
C.SW SW Store a 32-bit value in register rs2 ′ to memory
  • C.SW expands to sw rs2, offset(rs1')

CA-type

RV32C RV32I Description
C.SUB SUB Subtract the value in register rs2 ′ from the value in register rd ′, then write the result to register rd ′
C.XOR XOR Compute the bitwise XOR of the values in registers rd ′ and rs2 ′, then write the result to register rd ′
C.OR OR Compute the bitwise OR of the values in registers rd ′ and rs2 ′, then write the result to register rd ′
C.AND AND Compute the bitwise AND of the values in registers rd ′ and rs2 ′, then write the result to register rd ′
  • C.SUB expands to sub rd', rd', rs2'
  • C.XOR expands to xor rd', rd', rs2'
  • C.OR expands to or rd', rd', rs2'
  • C.AND expands to and rd', rd', rs2'

CB-type

RV32C RV32I Description
C.SRLI SRLI Perform a logical right shift of the value in register rd ′ then write the result to rd ′
C.SRAI SRAI Perform a arithmetic right shift of the value in register rd ′ then write the result to rd ′
C.ANDI ANDI Compute the bitwise AND of the value in register rd ′ and the sign-extended 6-bit immediate, then write the result to rd ′
C.BEQZ BEQ Perform conditional control transfers, and take the branch if the value in register rs1 ′ is zero
C.BNEZ BNE Perform conditional control transfers, and take the branch if the value in register rs1 ′ contains a nonzero value
  • C.SRLI expands to srli rd', rd', shamt
  • C.SRAI expands to srai rd', rd', shamt
  • C.ANDI expands to andi rd', rd', imm
  • C.BEQZ expands to beq rs1, x0, offset
  • C.BNEZ expands to bne rs1, x0, offset

CJ-type

RV32C RV32I Description
C.JAL JAL Perform an unconditional control transfer
C.J JAL Perform an unconditional control transfer and additionally write the address of the instruction following the jump (pc+2) to the link register (x1)
  • C.JAL expands to jal x1, offset
  • C.J expands to jal x0, offset

C.JAL is an RV32C-only instruction


Conclusion

op func inst[11:10] type reg len
10 100 - CR-type 5-bit ( x0-x31 )
01 000 CI-type
010
011
10 000
010
10 110 CSS-type
00 000 CIW-type 3-bit ( x8-x15 )
00 010 CL-type
00 110 CS-type
01 100 11 CA-type
01 100 00 CB-type
110 01
111 10
01 001 - CJ-type
101

SRV32

Introduction

srv32 is a simple RISC-V 3-stage pipeline processor and supports FreeRTOS

Stages

stage 1 - IF/ID

instruction fetch

  • If reset signal is True, instruction will be NOP
  • If reset signal is False and stall signal is False, read instruction
always @(posedge clk or negedge resetb) begin if (!resetb) begin ex_insn <= NOP; end else if (!if_stall) begin ex_insn <= inst; end end

immediate decode & extend

  • set imm according to the instruction
always @* begin case(inst[`OPCODE]) OP_AUIPC : imm = {inst[31:12], 12'd0}; // U-type OP_LUI : imm = {inst[31:12], 12'd0}; // U-type OP_JAL : imm = {{12{inst[31]}}, inst[19:12], inst[20], inst[30:21], 1'b0}; // J-type OP_JALR : imm = {{20{inst[31]}}, inst[31:20]}; // I-Type OP_BRANCH: imm = {{20{inst[31]}}, inst[7], inst[30:25], inst[11:8], 1'b0}; // B-type OP_LOAD : imm = {{20{inst[31]}}, inst[31:20]}; // I-type OP_STORE : imm = {{20{inst[31]}}, inst[31:25], inst[11:7]}; // S-type OP_ARITHI: imm = (inst[`FUNC3] == OP_SLL || inst[`FUNC3] == OP_SR) ? {27'h0, inst[24:20]} : {{20{inst[31]}}, inst[31:20]}; // I-type OP_ARITHR: imm = 'd0; // R-type OP_FENCE : imm = 'd0; OP_SYSTEM: imm = {20'h0, inst[31:20]}; default : imm = 'd0; endcase end

Used instruction : AUIPC, LUI, JAL, JALR, BEQ, BNE, BLTU, BGEU, AUIPC, AUIPC, AUIPC, AUIPC, AUIPC, AUIPC, AUIPC, AUIPC,


Control Signal / Register setting

always @(posedge clk or negedge resetb) begin if (!resetb) begin ex_imm <= 32'h0; ex_imm_sel <= 1'b0; ex_src1_sel <= 5'h0; ex_src2_sel <= 5'h0; ex_dst_sel <= 5'h0; ex_alu_op <= 3'h0; ex_subtype <= 1'b0; ex_memwr <= 1'b0; ex_alu <= 1'b0; ex_csr <= 1'b0; ex_csr_wr <= 1'b0; ex_lui <= 1'b0; ex_auipc <= 1'b0; ex_jal <= 1'b0; ex_jalr <= 1'b0; ex_branch <= 1'b0; ex_system <= 1'b0; ex_system_op <= 1'b0; ex_pc <= RESETVEC; ex_illegal <= 1'b0; ex_mul <= 1'b0; end else if (!if_stall) begin ex_imm <= imm; ex_imm_sel <= (inst[`OPCODE] == OP_JALR ) || (inst[`OPCODE] == OP_LOAD ) || (inst[`OPCODE] == OP_ARITHI); ex_src1_sel <= inst[`RS1]; ex_src2_sel <= inst[`RS2]; ex_dst_sel <= inst[`RD]; ex_alu_op <= inst[`FUNC3]; ex_subtype <= inst[`SUBTYPE] && !(inst[`OPCODE] == OP_ARITHI && inst[`FUNC3] == OP_ADD); ex_memwr <= inst[`OPCODE] == OP_STORE; ex_alu <= (inst[`OPCODE] == OP_ARITHI) || ((inst[`OPCODE] == OP_ARITHR) && (inst[`FUNC7] == 'h00 || inst[`FUNC7] == 'h20)); ex_csr <= (inst[`OPCODE] == OP_SYSTEM) && (inst[`FUNC3] != OP_ECALL); // CSRRS and CSRRC, if rs1==0, then the instruction // will not write to the CSR at all ex_csr_wr <= (inst[`OPCODE] == OP_SYSTEM) && (inst[`FUNC3] != OP_ECALL) && !(inst[`FUNC3] != OP_CSRRW && inst[`FUNC3] != OP_CSRRWI && inst[`RS1] == 5'h0); ex_lui <= inst[`OPCODE] == OP_LUI; ex_auipc <= inst[`OPCODE] == OP_AUIPC; ex_jal <= inst[`OPCODE] == OP_JAL; ex_jalr <= inst[`OPCODE] == OP_JALR; ex_branch <= inst[`OPCODE] == OP_BRANCH; ex_system <= (inst[`OPCODE] == OP_SYSTEM) && (inst[`FUNC3] == 3'b000); ex_system_op <= inst[`OPCODE] == OP_SYSTEM; ex_pc <= if_pc; ex_illegal <= !((inst[`OPCODE] == OP_AUIPC )|| (inst[`OPCODE] == OP_LUI )|| (inst[`OPCODE] == OP_JAL )|| (inst[`OPCODE] == OP_JALR )|| (inst[`OPCODE] == OP_BRANCH)|| ((inst[`OPCODE] == OP_LOAD ) && ((inst[`FUNC3] == OP_LB) || (inst[`FUNC3] == OP_LH) || (inst[`FUNC3] == OP_LW) || (inst[`FUNC3] == OP_LBU) || (inst[`FUNC3] == OP_LHU))) || ((inst[`OPCODE] == OP_STORE) && ((inst[`FUNC3] == OP_SB) || (inst[`FUNC3] == OP_SH) || (inst[`FUNC3] == OP_SW))) || (inst[`OPCODE] == OP_ARITHI)|| ((inst[`OPCODE] == OP_ARITHR) && (inst[`FUNC7] == 'h00 || inst[`FUNC7] == 'h20)) || ((inst[`OPCODE] == OP_ARITHR) && (inst[`FUNC7] == 'h01) && (RV32M == 1)) || (inst[`OPCODE] == OP_FENCE )|| (inst[`OPCODE] == OP_SYSTEM)); ex_mul <= (inst[`OPCODE] == OP_ARITHR) && (inst[`FUNC7] == 'h1) && (RV32M == 1); end end

stage 2 - EX

Branch Next PC Computation

`define IF_NEXT_PC (4) always @* begin branch_taken = !ex_flush; next_pc = fetch_pc + `IF_NEXT_PC; ex_ill_branch = 1'b0; case(1'b1) ex_jal : next_pc = {result_jal[31: 1], 1'b0}; // setting the least-signicant bit of the result to zero ex_jalr : next_pc = {result_jalr[31: 1], 1'b0}; // setting the least-signicant bit of the result to zero ex_branch: begin case(ex_alu_op) OP_BEQ : begin next_pc = (result_subs[32: 0] == 'd0) ? ex_pc + ex_imm : fetch_pc + `IF_NEXT_PC; if (result_subs[32: 0] != 'd0) branch_taken = 1'b0; end OP_BNE : begin next_pc = (result_subs[32: 0] != 'd0) ? ex_pc + ex_imm : fetch_pc + `IF_NEXT_PC; if (result_subs[32: 0] == 'd0) branch_taken = 1'b0; end OP_BLT : begin next_pc = result_subs[32] ? ex_pc + ex_imm : fetch_pc + `IF_NEXT_PC; if (!result_subs[32]) branch_taken = 1'b0; end OP_BGE : begin next_pc = !result_subs[32] ? ex_pc + ex_imm : fetch_pc + `IF_NEXT_PC; if (result_subs[32]) branch_taken = 1'b0; end OP_BLTU: begin next_pc = result_subu[32] ? ex_pc + ex_imm : fetch_pc + `IF_NEXT_PC; if (!result_subu[32]) branch_taken = 1'b0; end OP_BGEU: begin next_pc = !result_subu[32] ? ex_pc + ex_imm : fetch_pc + `IF_NEXT_PC; if (result_subu[32]) branch_taken = 1'b0; end default: begin next_pc = fetch_pc; ex_ill_branch = 1'b1; end endcase end default : begin next_pc = fetch_pc + `IF_NEXT_PC; branch_taken = 1'b0; end endcase end

Result Computation

always @* begin case(1'b1) ex_memwr: ex_result = alu_op2; ex_jal: ex_result = ex_pc + `EX_NEXT_PC; ex_jalr: ex_result = ex_pc + `EX_NEXT_PC; ex_lui: ex_result = ex_imm; ex_auipc: ex_result = ex_pc + ex_imm; ex_csr: ex_result = ex_csr_read; ex_mul: case(ex_alu_op) OP_MUL : ex_result = result_mul [31: 0]; OP_MULH : ex_result = result_mul [63:32]; OP_MULSU : ex_result = result_mulsu[63:32]; OP_MULU : ex_result = result_mulu [63:32]; OP_DIV : ex_result = result_div [31: 0]; OP_DIVU : ex_result = result_divu [31: 0]; OP_REM : ex_result = result_rem [31: 0]; // OP_REMU default : ex_result = result_remu [31: 0]; endcase ex_alu: case(ex_alu_op) OP_ADD : if (ex_subtype == 1'b0) ex_result = alu_op1 + alu_op2; else ex_result = alu_op1 - alu_op2; // In RISC-V ISA spec, only shift amount // held in lower 5 bits of register OP_SLL : ex_result = alu_op1 << alu_op2[4:0]; OP_SLT : ex_result = result_subs[32] ? 'd1 : 'd0; OP_SLTU: ex_result = result_subu[32] ? 'd1 : 'd0; OP_XOR : ex_result = alu_op1 ^ alu_op2; OP_SR : if (ex_subtype == 1'b0) // notes: shift more than 32 is undefined ex_result = alu_op1 >>> alu_op2[4:0]; else ex_result = $signed(alu_op1) >>> alu_op2[4:0]; OP_OR : ex_result = alu_op1 | alu_op2; // OP_AND default: ex_result = alu_op1 & alu_op2; endcase default: begin ex_result = 32'h0; end endcase end

stage 3 - WB

write back data

always @* begin case(wb_alu_op) OP_LB : begin case(wb_raddr[1:0]) 2'b00: wb_rdata[31: 0] = {{24{dmem_rdata[7]}}, dmem_rdata[ 7: 0]}; 2'b01: wb_rdata[31: 0] = {{24{dmem_rdata[15]}}, dmem_rdata[15: 8]}; 2'b10: wb_rdata[31: 0] = {{24{dmem_rdata[23]}}, dmem_rdata[23:16]}; 2'b11: wb_rdata[31: 0] = {{24{dmem_rdata[31]}}, dmem_rdata[31:24]}; endcase end OP_LH : begin wb_rdata = (wb_raddr[1]) ? {{16{dmem_rdata[31]}}, dmem_rdata[31:16]} : {{16{dmem_rdata[15]}}, dmem_rdata[15: 0]}; end OP_LW : begin wb_rdata = dmem_rdata; end OP_LBU : begin case(wb_raddr[1:0]) 2'b00: wb_rdata[31: 0] = {24'h0, dmem_rdata[7:0]}; 2'b01: wb_rdata[31: 0] = {24'h0, dmem_rdata[15:8]}; 2'b10: wb_rdata[31: 0] = {24'h0, dmem_rdata[23:16]}; 2'b11: wb_rdata[31: 0] = {24'h0, dmem_rdata[31:24]}; endcase end OP_LHU : begin wb_rdata = (wb_raddr[1]) ? {16'h0, dmem_rdata[31:16]} : {16'h0, dmem_rdata[15: 0]}; end default: begin wb_rdata = 32'h0; end endcase end


Control Signal

1. ex_imm_sel

Assignment

ex_imm_sel <= (inst[`OPCODE] == OP_JALR) || (inst[`OPCODE] == OP_LOAD) || (inst[`OPCODE] == OP_ARITHI);
  • ex_imm_sel=True, when the instruction is I-type format
  • ex_imm_sel=False, when the instruction is other format

Used Instruction: JALR, LB, LH, LW, LBU, LHU, ADDI, SLTI, SLTIU, XORI, ORI, ANDI, SLLI, SRLI, SRAI


2. ex_subtype


3. ex_memwr

Assignment

ex_memwr <= inst[`OPCODE] == OP_STORE;
  • ex_memwr <= True, when the instruction is LOAD format
  • ex_memwr <= False, when the instruction is other format

Used Instruction: LB, LH, LW, LBU, LHU


4. ex_alu

Assignment

ex_alu <= (inst[`OPCODE] == OP_ARITHI) || ((inst[`OPCODE] == OP_ARITHR) && (inst[`FUNC7] == 'h00 || inst[`FUNC7] == 'h20));
  • ex_alu <= True, when the instruction is ARITH format
  • ex_alu <= False, when the instruction is other format

Used Instruction: ADDI, SLTI, SLTIU, XORI, ORI, ANDI, SLLI, SRLI, SRAI, ADD, SUB, SLT, SLTU, XOR, OR, AND, SRL, SRA, MUL, MULH, MULSU, MULU, DIV, DIVU, REM, REMU


5. ex_lui

Assignment

ex_lui <= inst[`OPCODE] == OP_LUI;
  • ex_lui <= True, when the instruction is LUI
  • ex_lui <= False, when the instruction is other

Used Instruction: LUI


6. ex_auipc

Assignment

ex_auipc <= inst[`OPCODE] == OP_AUIPC;
  • ex_auipc <= True, when the instruction is AUIPC
  • ex_auipc <= False, when the instruction is other

Used Instruction: AUIPC


7. ex_jal

Assignment

ex_jal <= inst[`OPCODE] == OP_JAL;
  • ex_jal <= True, when the instruction is JAL
  • ex_jal <= False, when the instruction is other

Used Instruction: JAL


8. ex_jalr

Assignment

ex_jalr <= inst[`OPCODE] == OP_JALR;
  • ex_jalr <= True, when the instruction is JALR
  • ex_jalr <= False, when the instruction is other

Used Instruction: JALR


9. ex_branch

Assignment

ex_branch <= inst[`OPCODE] == OP_BRANCH;
  • ex_branch <= True, when the instruction is BRANCH format
  • ex_branch <= False, when the instruction is other

Used Instruction: BEQ, BNE, BLT, BGE, BLTU, BGEU


10. ex_mul

Assignment

ex_mul <= (inst[`OPCODE] == OP_ARITHR) && (inst[`FUNC7] == 'h1) && (RV32M == 1);
  • ex_mul <= True, when the instruction is MULTIPLE
  • ex_mul <= False, when the instruction is other

Used Instruction: MUL, MULH, MULSU, MULU, DIV, DIVU, REM, REMU


11. ex_system

Assignment

ex_system <= (inst[`OPCODE] == OP_SYSTEM) &&(inst[`FUNC3] == 3'b000);
  • ex_system <= True, when the instruction is ECALL, EBREAK, MRET
  • ex_system <= False, when the instruction is other

Used Instruction: ECALL, EBREAK, MRET


12. ex_system_op

Assignment

ex_system_op <= inst[`OPCODE] == OP_SYSTEM;
  • ex_system_op <= True, when the instruction is SYSTEM format
  • ex_system_op <= False, when the instruction is other

Used Instruction: ECALL, EBREAK, MRET, CSSRW, CSSRS, CSSRC, CSSRWI, CSSRSI, CSSRCI


13. ex_csr

Assignment

ex_csr <= (inst[`OPCODE] == OP_SYSTEM) && (inst[`FUNC3] != OP_ECALL);
  • ex_csr <= True, when the instruction is CSSRW, CSSRS, CSSRC, CSSRWI, CSSRSI, CSSRCI
  • ex_csr <= False, when the instruction is other

Used Instruction: CSSRW, CSSRS, CSSRC, CSSRWI, CSSRSI, CSSRCI


14. ex_csr_wr

Assignment

ex_csr_wr <= (inst[`OPCODE] == OP_SYSTEM) && (inst[`FUNC3] != OP_ECALL) && !(inst[`FUNC3] != OP_CSRRW && inst[`FUNC3] != OP_CSRRWI && inst[`RS1] == 5'h0);
  • ex_csr_wr <= True, when the instruction is CSRRW, CSRRWI, CSRRS, CSRRC
    (Only when the value of rs1 of CSRRS, CSRRC instruction is not equal to 0)
  • ex_csr_wr <= False, when the instruction is other

Used Instruction: CSSRW, CSSRS, CSSRC, CSSRWI


Conclusion

ex_imm_sel ex_subtype ex_memwr ex_alu ex_lui ex_auipc ex_jal ex_jalr ex_branch ex_mul ex_system ex_system_op ex_csr_wr ex_csr
LUI ✔️
AUIPC ✔️
JAL ✔️
JALR ✔️ ✔️
BEQ ✔️
BNE ✔️
BLT ✔️
BGE ✔️
BLTU ✔️
BGEU ✔️
LB ✔️ ✔️
LH ✔️ ✔️
LW ✔️ ✔️
LBU ✔️ ✔️
LHU ✔️ ✔️
SB
SH
SW
ADDI ✔️ ✔️
SLTI ✔️ ✔️
SLTIU ✔️ ✔️
XORI ✔️ ✔️
ORI ✔️ ✔️
ANDI ✔️ ✔️
SLLI ✔️ ✔️
SRAI ✔️ ✔️
SRAI ✔️ ✔️
ADD ✔️
SUB ✔️
SLL ✔️
SLT ✔️
SLTU ✔️
XOR ✔️
SRL ✔️
SRA ✔️
OR ✔️
AND ✔️
MUL ✔️ ✔️
MULH ✔️ ✔️
MULSU ✔️ ✔️
MULU ✔️ ✔️
DIV ✔️ ✔️
DIVU ✔️ ✔️
REM ✔️ ✔️
REMU ✔️ ✔️
ECALL ✔️ ✔️
EBREAK ✔️ ✔️
MERT ✔️ ✔️
CSRRW ✔️ ✔️ ✔️
CSRRS ✔️ ✔️ ✔️
CSRRC ✔️ ✔️ ✔️
CSRRWI ✔️ ✔️ ✔️
CSRRSI ✔️ ✔️
CSRRCI ✔️ ✔️


Implementation

Architecture

image

  1. Decode the instructions according to the opcode (inst[1:0])
    • If op2 equals to 11, then the instruction is base instruction
    • If op2 equals to 00, 01, or 10, then the instruction is c-extension instruction

    ex:
    If instruction is C.ADD, then the instruction information ALU gains should be ADD

  2. Execute instruction
  3. Write back data

op & func3 Define

// INST[1:0] = 2'b00 localparam [ 4: 0] OP_CADDI4SPN = 5'b00000, OP_CLW = 5'b01000, OP_CSW = 5'b11000; // INST[1:0] = 2'b01 localparam [ 4: 0] OP_CADDI = 5'b00001, OP_CJAL = 5'b00101, OP_CLI = 5'b01001, OP_CADDI16SP = 5'b01101, OP_CLUI = 5'b01101, OP_CSRLI = 5'b10001, OP_CSRAI = 5'b10001, OP_CANDI = 5'b10001, OP_CJ = 5'b10101, OP_CBEQZ = 5'b11001, OP_CBNEZ = 5'b11101; // INST[1:0] = 2'b01, no imm localparam [ 4: 0] OP_CSUB = 5'b10001, OP_CXOR = 5'b10001, OP_COR = 5'b10001, OP_CAND = 5'b10001; // INST[1:0] = 2'b10 localparam [ 4: 0] OP_CSLLI = 5'b00010, OP_CLWSP = 5'b01010, OP_CSWSP = 5'b11010; // INST[1:0] = 2'b10, no imm localparam [ 4: 0] OP_CJR = 5'b10010, OP_CMV = 5'b10010, OP_CJALR = 5'b10010, OP_CADD = 5'b10010, OP_CSYSTEM = 5'b10010;

This part is for instruction define, the parameter OP_XXX is composed of funct3 and op2 ({inst[15:13]})


Imm Decode

This section is modified from here.

always @* begin case(inst[`OPCODE]) OP_AUIPC : imm = {inst[31:12], 12'd0}; // U-type OP_LUI : imm = {inst[31:12], 12'd0}; // U-type OP_JAL : imm = {{12{inst[31]}}, inst[19:12], inst[20], inst[30:21], 1'b0}; // J-type OP_JALR : imm = {{20{inst[31]}}, inst[31:20]}; // I-Type OP_BRANCH: imm = {{20{inst[31]}}, inst[7], inst[30:25], inst[11:8], 1'b0}; // B-type OP_LOAD : imm = {{20{inst[31]}}, inst[31:20]}; // I-type OP_STORE : imm = {{20{inst[31]}}, inst[31:25], inst[11:7]}; // S-type OP_ARITHI: imm = (inst[`FUNC3] == OP_SLL || inst[`FUNC3] == OP_SR) ? {27'h0, inst[24:20]} : {{20{inst[31]}}, inst[31:20]}; // I-type OP_ARITHR: imm = 'd0; // R-type OP_FENCE : imm = 'd0; OP_SYSTEM: imm = {20'h0, inst[31:20]}; default : imm = 'd0; endcase // case for C-Extenstion case({inst[`CFUNC3], inst[`COPCODE]}) // CI-type + OP_CLI : imm = {26'b0, inst[12], inst[6:2]}; + OP_CADDI : imm = {26'b0, inst[12], inst[6:2]}; + OP_CSLLI : imm = {26'b0, inst[12], inst[6:2]}; // C.LUI & C.ADDI16SP + OP_CLUI : imm = (inst[`C5RD]==5'd2) ? {22'b0, inst[12], inst[4:3], inst[5], inst[2], inst[6], 4'b0} : {14'b0, inst[12], inst[6:2], 12'b0}; + OP_CLWSP : imm = {24'b0, inst[3:2], inst[12], inst[6:4], 2'b0}; // CSS-type + OP_CSWSP : imm = {24'b0, inst[8:7], inst[12:9], 2'b0}; // CIW-type + OP_CADDI4SPN : imm = {22'b0, inst[10:7], inst[12:11], inst[5], inst[6], 2'b0}; // CL-type + OP_CLW : imm = {25'b0, inst[5], inst[12:10], inst[6], 2'b0}; // CS-type + OP_CSW : imm = {25'b0, inst[5], inst[12:10], inst[6], 2'b0}; // CB-type + OP_CBEQZ : imm = {23'b0, inst[12], inst[6:5], inst[2], inst[11:10], inst[4:3], 1'b0}; + OP_CBNEZ : imm = {23'b0, inst[12], inst[6:5], inst[2], inst[11:10], inst[4:3], 1'b0}; + OP_CSRLI : imm = (inst[11:10]==2'b0) ? {27'b0, inst[6:2]} : + (inst[11:10]==2'b1) ? {26'b0, inst[12], inst[6:2]} : + {26'b0, inst[12], inst[6:2]}; // CJ-type + OP_CJ : imm = {20'b0, inst[12], inst[8], inst[10:9], inst[7], inst[6], inst[2], inst[11], inst[4:2], 1'b0}; + OP_CJAL : imm = {20'b0, inst[12], inst[8], inst[10:9], inst[7], inst[6], inst[2], inst[11], inst[4:2], 1'b0}; + OP_CSYSTEM : imm = (inst[`C5RD] == 0 && inst[`C5RS2] == 0) ? 32'b1 : 32'b0; + default : imm = 'd0; endcase end

The upper part is for base instructions, then the lower part is for c-extension instructions


Register

This section is modified from here

case(inst[`COPCODE]) + 2'b00: // CIW-type, CL-type, CS-type + begin + instc <= 1'b1; + ex_src1_sel <= {2'b1, inst[`C3RS1]}; + ex_src2_sel <= {2'b1, inst[`C3RS2]}; + ex_dst_sel <= {2'b1, inst[`C3RD]}; + end + 2'b01: + begin + case(inst[`CFUNC3]) + 3'b000, // CI-type + 3'b010, // CI-type + 3'b011: // CI-type + begin + instc <= 1'b1; + ex_src1_sel <= inst[`C5RS1]; + ex_src2_sel <= inst[`C5RS2]; + ex_dst_sel <= inst[`C5RD]; + end + 3'b001, // CJ-type + 3'b100, // CA-type, CB-type + 3'b101, // CJ-type + 3'b110, // CB-type + 3'b111: // CB-type + begin + instc <= 1'b1; + ex_src1_sel <= {2'b1, inst[`C3RS1]}; + ex_src2_sel <= {2'b1, inst[`C3RS2]}; + ex_dst_sel <= {2'b1, inst[`C3RD]}; + end + endcase + end + 2'b10: // CI-type, CSS-type + begin + instc <= 1'b1; + ex_src1_sel <= inst[`C5RS1]; + ex_src2_sel <= inst[`C5RS2]; + ex_dst_sel <= inst[`C5RD]; + end 2'b11: // base begin instc <= 1'b0; ex_src1_sel <= inst[`RS1]; ex_src2_sel <= inst[`RS2]; ex_dst_sel <= inst[`RD]; end endcase

Because CIW, CL, CS, CA, CB, and CJ format instruction can use only part of the RV32I registers, we have to map the rs1', rs2', and rd' to the corresponded register.


ALU OP

This section is modified from here

case(inst[`COPCODE]) 2'b11: ex_alu_op <= inst[`FUNC3]; default: begin // c-ext + case({inst[`CFUNC3], inst[`COPCODE]}) + OP_CLW: ex_alu_op <= OP_LW; + OP_CLWSP: ex_alu_op <= OP_LW; + OP_CSW: ex_alu_op <= OP_SW; + OP_CSWSP: ex_alu_op <= OP_SW; + OP_CBEQZ: ex_alu_op <= OP_BEQ; + OP_CBNEZ: ex_alu_op <= OP_BNE; + OP_CADD: ex_alu_op <= OP_ADD; + OP_COR: + begin + case(inst[6:5]) + 2'b00: ex_alu_op <= OP_ADD; + 2'b01: ex_alu_op <= OP_XOR; + 2'b10: ex_alu_op <= OP_OR; + 2'b11: ex_alu_op <= OP_AND; + endcase + end + default: ; endcase end endcase

This part is for instruction expanding.

If the instruction is based instruction, then set the ex_alu_op with funct3

If the instruction is c-extension instruction, then decode the instruction with op2 and funct3, and set the ex_alu_op with corresponded funct3 of based instruction.


Control Signal

1. ex_imm_sel

This section is modified from here.

ex_imm_sel <= (inst[`OPCODE] == OP_JALR ) || (inst[`OPCODE] == OP_LOAD ) || (inst[`OPCODE] == OP_ARITHI) || // c-ext + (({inst[`CFUNC3], inst[`COPCODE]} == OP_CJR) && (inst[12] == 1'b0) && (inst[`C5RS2] == 5'b0) && (inst[`C5RS1] != 5'b0)) || // C.JR + (({inst[`CFUNC3], inst[`COPCODE]} == OP_CJALR) && (inst[12] == 1'b1) && (inst[`C5RS2] == 5'b0) && (inst[`C5RS1] != 5'b0)) || // C.JALR + ({inst[`CFUNC3], inst[`COPCODE]} == OP_CLW) || // C.LW + ({inst[`CFUNC3], inst[`COPCODE]} == OP_CLWSP) || // C.LWSP + (({inst[`COPCODE], inst[`CFUNC3]} == OP_CADDI) && (inst[`C5RS1] != 5'b0)) || // C.ADDI + (({inst[`COPCODE], inst[`CFUNC3]} == OP_CLI) && (inst[`C5RS1] != 5'b0)) || // C.LI + (({inst[`COPCODE], inst[`CFUNC3]} == OP_CSLLI) && (inst[`C5RS1] != 5'b0)) || // C.SLLI + (({inst[`COPCODE], inst[`CFUNC3]} == OP_CSRLI) && (inst[`CFUNC2] == 2'b00)) || // C.SRLI + (({inst[`COPCODE], inst[`CFUNC3]} == OP_CSRAI) && (inst[`CFUNC2] == 2'b01)) || // C.SRAI + (({inst[`COPCODE], inst[`CFUNC3]} == OP_CANDI) && (inst[`CFUNC2] == 2'b10)); // C.SRAI

Add additional conditions for c instructions - C.JR, C.JALR, C.LW, C.LWSP, C.ADDI, C.LI, C.SLLI, C.SRLI, C.SRAI, C.ANDI


2. ex_subtype

3. ex_memwr

This section is modified from here

ex_memwr <= (inst[`OPCODE] == OP_STORE) || // c-ext + ({inst[`CFUNC3], inst[`COPCODE]} == OP_CSW) || // C.SW + ({inst[`CFUNC3], inst[`COPCODE]} == OP_CSWSP); // C.SWSP

Add additional instruction conditions for c instruction - C.SW, CSWSP


4. ex_alu

This section is modified from here

ex_alu <= (inst[`OPCODE] == OP_ARITHI) || ((inst[`OPCODE] == OP_ARITHR) && (inst[`FUNC7] == 'h00 || inst[`FUNC7] == 'h20)) || // c-ext + (({inst[`COPCODE], inst[`CFUNC3]} == OP_CADD) && (inst[12]) && (inst[`CRD] != 5'b0) && (inst[`C5RS2] != 5'b0)) || // C.ADD + (({inst[`COPCODE], inst[`CFUNC3]} == OP_CMV) && (!inst[12]) && (inst[`CRD] != 5'b0) && (inst[`C5RS2] != 5'b0)) || // C.MV + (({inst[`COPCODE], inst[`CFUNC3]} == OP_CSUB) && (inst[`CFUNC6] == 6'b100011)) || // C.SUB, C.XOR, C.OR, C.AND + (({inst[`COPCODE], inst[`CFUNC3]} == OP_CADDI) && (inst[`C5RS1] != 5'b0)) || // C.ADDI + (({inst[`COPCODE], inst[`CFUNC3]} == OP_CLI) && (inst[`C5RS1] != 5'b0)) || // C.LI + (({inst[`COPCODE], inst[`CFUNC3]} == OP_CSLLI) && (inst[`C5RS1] != 5'b0)) || // C.SLLI + (({inst[`COPCODE], inst[`CFUNC3]} == OP_CSRLI) && (inst[`CFUNC2] == 2'b00)) || // C.SRLI + (({inst[`COPCODE], inst[`CFUNC3]} == OP_CSRAI) && (inst[`CFUNC2] == 2'b01)) || // C.SRAI + (({inst[`COPCODE], inst[`CFUNC3]} == OP_CANDI) && (inst[`CFUNC2] == 2'b10)); // C.ANDI

Add additional conditions for c instructions - C.ADD, C.MV, C.SUB, C.XOR, C.OR, C.AND, C.ADDI, C.LI, C.SLLI, C.SRLI, C.SRAI, C.ANDI


5. ex_lui

This section is modified from here

ex_lui <= (inst[`OPCODE] == OP_LUI) || // c-ext + (({inst[`CFUNC3], inst[`COPCODE]} == OP_CLUI) && (inst[`RD] != 5'd0) && (inst[`RD] != 5'd1) && (inst[`RD] != 5'd2)); // C.LUI

Add additional conditions for c instruction - C.LUI


6. ex_jal

This section is modified from here

ex_jal <= (inst[`OPCODE] == OP_JAL) || // c-ext + ({inst[`CFUNC3], inst[`COPCODE]} == OP_CJ) || // C.J + ({inst[`CFUNC3], inst[`COPCODE]} == OP_CJAL); // C.JAL

Add additional conditions for c instructions - C.J, C.JAL


7. ex_jalr

This section is modified from here

ex_jalr <= (inst[`OPCODE] == OP_JALR) || // c-ext + (({inst[`CFUNC3], inst[`COPCODE]} == OP_CJR) && (!inst[12]) && (inst[`C5RS1] != 5'b0) && (inst[`C5RS2] == 5'b0)) || // C.JR + (({inst[`CFUNC3], inst[`COPCODE]} == OP_CJALR) && (inst[12]) && (inst[`C5RS1] != 5'b0) && (inst[`C5RS2] == 5'b0)) ; // C.JALR

Add additional conditions for c instructions - C.JR, C.JALR


8. ex_branch

This section is modified from here

ex_branch <= (inst[`OPCODE] == OP_BRANCH) || // c-ext + ({inst[`CFUNC3], inst[`COPCODE]} == OP_CBEQZ) || // C.BEQZ + ({inst[`CFUNC3], inst[`COPCODE]} == OP_CBNEZ); // C.BNEZ

Add additional conditions for c instructions - C.BEQZ, C.BNEZ


9. ex_system

This section is modified from here

ex_system <= ((inst[`OPCODE] == OP_SYSTEM) && (inst[`FUNC3] == 3'b000)) || // c-ext + (({inst[`CFUNC3], inst[`COPCODE]} == OP_CSYSTEM) && (inst[12]) && (inst[`CRD] == 5'b0) && (inst[`C5RS2] == 5'b0));

Add additional instruction conditions for c instruction - C.EBREAK


10. ex_system_op

This section is modified from here

ex_system_op <= (inst[`OPCODE] == OP_SYSTEM) || // c-ext + (({inst[`CFUNC3], inst[`COPCODE]} == OP_CSYSTEM) && (inst[12]) && (inst[`CRD] == 5'b0) && (inst[`C5RS2] == 5'b0));

Add additional conditions for c instruction - C.EBREAK


11. ex_csr

This section is modified from here

ex_csr <= ((inst[`OPCODE] == OP_SYSTEM) && (inst[`FUNC3] != OP_ECALL)) || // c-ext + (inst[`CINST] == 16'h9002);

Add additional conditions for c instruction - C.EBREAK


PC

Define

`define IF_NEXT_PC (4) `define EX_NEXT_PC (4) // c-ext pc +`define IF_NEXT_C_PC (2) +`define EX_NEXT_C_PC (2)

Because the c extension instruction is 16-byte long, the program counter (PC) should increment by 2 by step instead of by 4


Branch PC

This section is modified from here

always @* begin branch_taken = !ex_flush; + next_pc = (instc) ? (fetch_pc + `IF_NEXT_C_PC) : (fetch_pc + `IF_NEXT_PC); ex_ill_branch = 1'b0; case(1'b1) ex_jal : next_pc = {result_jal[31: 1], 1'b0}; // setting the least-signicant bit of the result to zero ex_jalr : next_pc = {result_jalr[31: 1], 1'b0}; // setting the least-signicant bit of the result to zero ex_branch: begin case(ex_alu_op) OP_BEQ : begin + next_pc = (result_subs[32: 0] == 'd0) ? + (ex_pc + ex_imm) : (instc) ? + (fetch_pc + `IF_NEXT_C_PC) : (fetch_pc + `IF_NEXT_PC); if (result_subs[32: 0] != 'd0) branch_taken = 1'b0; end OP_BNE : begin + next_pc = (result_subs[32: 0] != 'd0) ? + (ex_pc + ex_imm) : (instc) ? + (fetch_pc + `IF_NEXT_C_PC) : (fetch_pc + `IF_NEXT_PC); if (result_subs[32: 0] == 'd0) branch_taken = 1'b0; end OP_BLT : begin + next_pc = result_subs[32] ? + (ex_pc + ex_imm) : (instc) ? + (fetch_pc + `IF_NEXT_C_PC) : (fetch_pc + `IF_NEXT_PC); if (!result_subs[32]) branch_taken = 1'b0; end OP_BGE : begin + next_pc = !result_subs[32] ? + (ex_pc + ex_imm) : (instc) ? + (fetch_pc + `IF_NEXT_C_PC) : (fetch_pc + `IF_NEXT_PC); if (result_subs[32]) branch_taken = 1'b0; end OP_BLTU: begin + next_pc = result_subu[32] ? + (ex_pc + ex_imm) : (instc) ? + (fetch_pc + `IF_NEXT_C_PC) : (fetch_pc + `IF_NEXT_PC); if (!result_subu[32]) branch_taken = 1'b0; end OP_BGEU: begin + next_pc = !result_subu[32] ? + (ex_pc + ex_imm) : (instc) ? + (fetch_pc + `IF_NEXT_C_PC) : (fetch_pc + `IF_NEXT_PC); if (result_subu[32]) branch_taken = 1'b0; end default: begin + next_pc = fetch_pc; ex_ill_branch = 1'b1; end endcase end default : begin + next_pc = (instc) ? (fetch_pc + `IF_NEXT_C_PC) : (fetch_pc + `IF_NEXT_PC); branch_taken = 1'b0; end endcase end

This part is for BRANCH instruction

Use a control signal (instc) to determine whether the PC should increment by 2 or 4

  • If instc=0 (means base instruction), PC will increment by 4
  • If instc=0 (means C extension instruction), PC will increment by 2

The value of control signal instc is set at here


Jump PC

This section is modified from here

always @* begin case(1'b1) ex_memwr: ex_result = alu_op2; + ex_jal: ex_result = (instc) ? (ex_pc + `EX_NEXT_C_PC) : (ex_pc + `EX_NEXT_PC); + ex_jalr: ex_result = (instc) ? (ex_pc + `EX_NEXT_C_PC) : (ex_pc + `EX_NEXT_PC); ex_lui: ex_result = ex_imm; ex_auipc: ex_result = ex_pc + ex_imm; ex_csr: ex_result = ex_csr_read; ex_mul: (...) // Remaining code is the same

This part is for JUMP instruction

Use a control signal (instc) to determine whether the PC should increment by 2 or 4

  • If instc=0 (means base instruction), PC will increment by 4
  • If instc=0 (means C extension instruction), PC will increment by 2

The value of control signal instc is set at here


Test

The origin structure is in ~/test/srv32 directory
Our c-extension supported structure is in ~/repos/srv32

First, we test the original structure in RTL simulation
Type make all in folder srv32
image

Test out c-extension supported structure
image
The error message show Unsupport CSR register 0x0 at PC 0x00000010
Because the conversion of CSR instructions has not been successfully handled so far.

Problem analysis

  1. Some instructions might have been mistakenly identified as CSR instructions, resulting in illegal instructions.
  2. Since the c-extension instructions related to CSR only include c.ebreak, there might have been an error during the decoding of this instruction.

We should be able to figure it out within a few days.

Reference