Zicsr: implement register operand instructions

This commit is contained in:
2025-09-03 18:18:39 +03:00
parent 97ae2dd172
commit 6a42df4da6
11 changed files with 521 additions and 98 deletions
+95 -7
View File
@@ -1,27 +1,115 @@
.global __entry .global __entry
.global __vector
.global exception_stack_top
.pushsection .text.entry .pushsection .text.entry
.option push .option push
.option norvc .option norvc
__entry: __entry:
__reset: j fw_entry __reset: j fw_entry
__exception: j fw_exception_entry
fw_entry: fw_entry:
la sp, stack_top la sp, stack_top
jal {firmware_main} jal {firmware_main}
fw_exception_entry:
mv tp, sp
la sp, exception_stack_top
jal {firmware_exception}
j .
.option pop .option pop
.popsection // .text.entry .popsection // .text.entry
// ra+gp, 7 tN, 12 sN, 8 aN
.set GP_REGS_SIZE, ((2 + 7 + 12 + 8) * 4)
.set CTL_REGS_SIZE, (6 * 8)
.set SAVED_FRAME_SIZE, (GP_REGS_SIZE + CTL_REGS_SIZE)
.pushsection .text.vectors, "ax" .pushsection .text.vectors, "ax"
.global __vector
__vector: __vector:
// Switch to exception stack
csrrw sp, mscratch, sp
// Store register state
addi sp, sp, -SAVED_FRAME_SIZE
sw ra, 0 * 4(sp)
sw gp, 1 * 4(sp)
sw t0, 2 * 4(sp)
sw t1, 3 * 4(sp)
sw t2, 4 * 4(sp)
sw t3, 5 * 4(sp)
sw t4, 6 * 4(sp)
sw t5, 7 * 4(sp)
sw t6, 8 * 4(sp)
sw s0, 9 * 4(sp)
sw s1, 10 * 4(sp)
sw s2, 11 * 4(sp)
sw s3, 12 * 4(sp)
sw s4, 13 * 4(sp)
sw s5, 14 * 4(sp)
sw s6, 15 * 4(sp)
sw s7, 16 * 4(sp)
sw s8, 17 * 4(sp)
sw s9, 18 * 4(sp)
sw s10, 19 * 4(sp)
sw s11, 20 * 4(sp)
sw a0, 21 * 4(sp)
sw a1, 22 * 4(sp)
sw a2, 23 * 4(sp)
sw a3, 24 * 4(sp)
sw a4, 25 * 4(sp)
sw a5, 26 * 4(sp)
sw a6, 27 * 4(sp)
sw a7, 28 * 4(sp)
csrr t0, mtval
csrr t1, mepc
csrr t2, mcause
csrr t3, mscratch
sw t0, 29 * 4(sp)
sw t1, 30 * 4(sp)
sw t2, 31 * 4(sp)
sw t3, 32 * 4(sp)
mv a0, sp
jal {firmware_exception}
// Restore state
lw ra, 0 * 4(sp)
lw gp, 1 * 4(sp)
lw t0, 2 * 4(sp)
lw t1, 3 * 4(sp)
lw t2, 4 * 4(sp)
lw t3, 5 * 4(sp)
lw t4, 6 * 4(sp)
lw t5, 7 * 4(sp)
lw t6, 8 * 4(sp)
lw s0, 9 * 4(sp)
lw s1, 10 * 4(sp)
lw s2, 11 * 4(sp)
lw s3, 12 * 4(sp)
lw s4, 13 * 4(sp)
lw s5, 14 * 4(sp)
lw s6, 15 * 4(sp)
lw s7, 16 * 4(sp)
lw s8, 17 * 4(sp)
lw s9, 18 * 4(sp)
lw s10, 19 * 4(sp)
lw s11, 20 * 4(sp)
lw a0, 21 * 4(sp)
lw a1, 22 * 4(sp)
lw a2, 23 * 4(sp)
lw a3, 24 * 4(sp)
lw a4, 25 * 4(sp)
lw a5, 26 * 4(sp)
lw a6, 27 * 4(sp)
lw a7, 28 * 4(sp)
addi sp, sp, SAVED_FRAME_SIZE
csrrw sp, mscratch, sp
mret
j . j .
.popsection // .text.vectors .popsection // .text.vectors
+32 -5
View File
@@ -24,25 +24,52 @@ impl fmt::Write for D {
} }
unsafe extern "C" fn firmware_main() -> ! { unsafe extern "C" fn firmware_main() -> ! {
unsafe extern "C" {
static __vector: u8;
static exception_stack_top: u8;
}
let vector_address = (&raw const __vector).addr();
core::arch::asm!("csrw mtvec, {val}", val = in(reg) vector_address);
let exception_stack_address = (&raw const exception_stack_top).addr();
core::arch::asm!("csrw mscratch, {val}", val = in(reg) exception_stack_address);
use fmt::Write; use fmt::Write;
let mut d = D; let mut d = D;
for i in 0..10 {
write!(d, "Hello {i}").ok(); writeln!(d, "Set mtvec={vector_address:#x}").ok();
write!(d, "\n").ok();
for i in 0..20 {
writeln!(d, "Hello {i:#x}").ok();
} }
loop { loop {
// TODO pause/system/fence instruction not implemented // TODO pause/system/fence instruction not implemented
// core::hint::spin_loop(); // core::hint::spin_loop();
core::arch::asm!("ebreak"); core::arch::asm!("ecall");
} }
} }
unsafe extern "C" fn firmware_exception() { #[repr(C)]
struct ExceptionFrame {
regs: [u32; 29],
mtval: u32,
mepc: u32,
mcause: u32,
mscratch: u32,
}
unsafe extern "C" fn firmware_exception(frame: &ExceptionFrame) {
use fmt::Write; use fmt::Write;
let mut d = D; let mut d = D;
writeln!(d, "In exception handler").ok(); writeln!(d, "In exception handler").ok();
writeln!(
d,
"mepc={:x}, mcause={:x}, mscratch={:x}",
frame.mepc, frame.mcause, frame.mscratch
)
.ok();
} }
global_asm!( global_asm!(
-4
View File
@@ -33,7 +33,6 @@ module rvx0_control (
end end
end end
// TODO handle pslverr
always @(negedge clk_i) begin always @(negedge clk_i) begin
if (~rst_i) begin if (~rst_i) begin
case (control_state_o) case (control_state_o)
@@ -98,7 +97,6 @@ module rvx0_control (
end end
CSTATE_EXEC: begin CSTATE_EXEC: begin
if (exec_stall_i) begin if (exec_stall_i) begin
$display("control: exec_stall_i @ %x", pc_value_i);
control_state_o <= CSTATE_FETCH; control_state_o <= CSTATE_FETCH;
end else if (exec_ready_i) begin end else if (exec_ready_i) begin
control_state_o <= CSTATE_WRITE; control_state_o <= CSTATE_WRITE;
@@ -115,8 +113,6 @@ module rvx0_control (
apb_master.pwrite <= 1; apb_master.pwrite <= 1;
apb_master.penable <= 1; apb_master.penable <= 1;
$display("WRITE %x -> %x", memory_write_i, memory_address_i);
if (apb_master.pslverr) begin if (apb_master.pslverr) begin
apb_master.penable <= 0; apb_master.penable <= 0;
fault_memory_access_o <= 1; fault_memory_access_o <= 1;
+115 -24
View File
@@ -20,6 +20,12 @@ module rvx0_core #(
wire [31:0] csr_mtvec; wire [31:0] csr_mtvec;
wire [31:0] csr_mepc; wire [31:0] csr_mepc;
wire csr_clk;
wire csr_write;
wire [11:0] csr_index;
wire [31:0] csr_read_value;
wire undefined_csr;
wire csr_write_fault;
// Exception generation // Exception generation
@@ -66,11 +72,14 @@ module rvx0_core #(
wire [4:0] rd; wire [4:0] rd;
wire v1src; wire v1src;
wire [1:0] v2src; wire [1:0] v2src;
wire [1:0] vdsrc; wire [2:0] vdsrc;
wire [31:0] imm; wire [31:0] imm;
wire [3:0] aluop; wire [3:0] aluop;
wire write_pc; wire write_pc;
wire [2:0] funct3; wire [2:0] funct3;
wire instruction_multi_cycle;
wire instruction_zicsr;
wire exception_return;
// Into ALU // Into ALU
@@ -93,6 +102,22 @@ module rvx0_core #(
wire [31:0] memory_write_output; wire [31:0] memory_write_output;
wire memory_access_partial; wire memory_access_partial;
// "Slow" datapath test
logic regfile_clk;
logic advance_pc;
// Zicsr extension
logic zicsr_clk_gate;
wire zicsr_clk;
wire zicsr_exec_ready;
wire zicsr_regfile_clk;
wire zicsr_instruction_fault;
wire [31:0] zicsr_read_value;
wire [31:0] zicsr_write_value;
wire zicsr_write;
rvx0_pc #( rvx0_pc #(
.RESET_VECTOR (RESET_VECTOR) .RESET_VECTOR (RESET_VECTOR)
) pc ( ) pc (
@@ -129,7 +154,11 @@ module rvx0_core #(
.conditional_o (conditional), .conditional_o (conditional),
.raise_ecall_o (raise_ecall), .raise_ecall_o (raise_ecall),
.raise_ebreak_o (raise_ebreak) .raise_ebreak_o (raise_ebreak),
.exception_return_o (exception_return),
.instruction_multi_cycle_o (instruction_multi_cycle),
.instruction_zicsr_o (instruction_zicsr)
); );
rvx0_regfile regfile ( rvx0_regfile regfile (
@@ -195,13 +224,18 @@ module rvx0_core #(
.rst_i (rst_i), .rst_i (rst_i),
.mepc_i (mepc_write_value), .mepc_i (mepc_write_value),
.mepc_write_i (fault), .mepc_write_i (csr_write_fault),
.mcause_i (mcause_write_value), .mcause_i (mcause_write_value),
.mcause_write_i (fault), .mcause_write_i (csr_write_fault),
.mtval_i (mtval_write_value), .mtval_i (mtval_write_value),
.mtval_write_i (fault), .mtval_write_i (csr_write_fault),
.mtvec_o (csr_mtvec),
.mtvec_o (csr_mtvec) .csr_index_i (csr_index),
.csr_write_value_i (zicsr_write_value),
.csr_read_value_o (csr_read_value),
.csr_write_i (csr_write),
.undefined_csr_o (undefined_csr)
); );
rvx0_fault_encoder fault_encoder ( rvx0_fault_encoder fault_encoder (
@@ -227,7 +261,30 @@ module rvx0_core #(
.mepc_write_value_o (mepc_write_value) .mepc_write_value_o (mepc_write_value)
); );
assign fault_instruction = fault_instruction_decode || (fault_unsupported_size && (need_memory_read || need_memory_write)); rvx0_zicsr zicsr (
.clk_i (zicsr_clk),
.rst_i (rst_i),
.funct3_i (funct3),
.rs1_value_i (rs1_value),
.rd_i (rd),
.imm_i (imm),
.exec_ready_o (zicsr_exec_ready),
.regfile_clk_o (zicsr_regfile_clk),
.csr_index_o (csr_index),
.csr_read_output_o (zicsr_read_value),
.csr_write_output_o (zicsr_write_value),
.csr_value_i (csr_read_value),
.csr_write_o (zicsr_write),
.undefined_csr_i (undefined_csr),
.instruction_fault_o (zicsr_instruction_fault)
);
assign csr_write = (zicsr_write && zicsr_clk_gate) && state_exec;
assign fault_instruction = fault_instruction_decode || (fault_unsupported_size && (need_memory_read || need_memory_write)) || (zicsr_instruction_fault && instruction_zicsr);
assign fault_memory_align = fault_address_align && (need_memory_write || need_memory_read); assign fault_memory_align = fault_address_align && (need_memory_write || need_memory_read);
assign memory_write_input = rs2_value; assign memory_write_input = rs2_value;
@@ -236,12 +293,20 @@ module rvx0_core #(
assign alu_value1 = v1src == V1SRC_ZERO ? 0 : rs1_value; assign alu_value1 = v1src == V1SRC_ZERO ? 0 : rs1_value;
assign state_exec = control_state == CSTATE_EXEC; assign state_exec = control_state == CSTATE_EXEC;
assign pc_clk = (state_exec || rst_i) && clk_i; assign pc_clk = ((state_exec && (advance_pc || fault)) || rst_i) && clk_i;
assign zicsr_clk = ((state_exec && zicsr_clk_gate) || rst_i) && clk_i;
assign write_rd = (vdsrc != RDSRC_NONE) && state_exec && ~fault; assign write_rd = (vdsrc != RDSRC_NONE) && state_exec && ~fault;
assign write_pc_and_taken = ((conditional ? branch_taken : 1) && write_pc) || fault; assign write_pc_and_taken = ((conditional ? branch_taken : 1) && write_pc) || fault;
assign pc_write_value = fault ? csr_mtvec : alu_output;
assign zicsr_clk_gate = instruction_zicsr && state_exec;
assign exec_stall = fault && state_exec;
assign csr_write_fault = fault && state_exec;
// Value mux // Value mux
always_comb begin always_comb begin
case (vdsrc) case (vdsrc)
@@ -249,6 +314,7 @@ module rvx0_core #(
RDSRC_ALU: rd_write_value = alu_output; RDSRC_ALU: rd_write_value = alu_output;
RDSRC_MEM: rd_write_value = memory_read_output; RDSRC_MEM: rd_write_value = memory_read_output;
RDSRC_NONE: rd_write_value = 0; RDSRC_NONE: rd_write_value = 0;
RDSRC_CSR: rd_write_value = zicsr_read_value;
endcase endcase
case (v2src) case (v2src)
@@ -256,34 +322,59 @@ module rvx0_core #(
V2SRC_PC: alu_value2 = pc_value; V2SRC_PC: alu_value2 = pc_value;
V2SRC_RS2: alu_value2 = rs2_value; V2SRC_RS2: alu_value2 = rs2_value;
endcase endcase
if (fault) begin
pc_write_value = csr_mtvec;
end else begin
pc_write_value = alu_output;
end
end end
always @(posedge clk_i) begin always @(posedge clk_i) begin
advance_pc = 0;
case (control_state) case (control_state)
CSTATE_EXEC: begin CSTATE_EXEC: begin
exec_ready = 0; exec_ready = 0;
exec_stall = 0; regfile_clk = 0;
`ifdef RVX0_DEBUGGING
$display("[%x] %x, rs1 (r%d)=%x, rs2 (r%d)=%x, v1src=%d, v2src=%d, vdsrc=%d", pc_value, instruction, rs1, rs1_value, rs2, rs2_value, v1src, v2src, vdsrc);
$display("\talu_value1=%x, alu_value2=%x, imm=%x, rd_write_value=%x", alu_value1, alu_value2, imm, rd_write_value);
$display("\tmri=%x, mro=%x, mwi=%x, mwo=%x", memory_read_input, memory_read_output, memory_write_input, memory_write_output);
`endif
if (fault) begin if (fault) begin
$display("Take exception mcause=%x, mepc=%x, mtval=%x to %x", mcause_write_value, mepc_write_value, mtval_write_value, csr_mtvec); $display("Take exception mcause=%x, mepc=%x, mtval=%x to %x", mcause_write_value, mepc_write_value, mtval_write_value, csr_mtvec);
$display("Instruction: %x", instruction); $display("Instruction: %x", instruction);
`ifdef RVX0_CRASH_ON_EXCEPTION if (fault_instruction) begin
regfile.dump_state; $display("Instruction decode fault:");
$finish; if (fault_instruction_decode) begin
$display("\tfault_instruction_decode");
end
if (fault_unsupported_size && (need_memory_read || need_memory_write)) begin
$display("\tfault_unsupported_size");
end
if (zicsr_instruction_fault && instruction_zicsr) begin
$display("\tzicsr_instruction_fault");
end
end
fault_encoder.dump_fault;
`ifndef RVX0_CRASH_ON_EXCEPTION
if (raise_ebreak) begin
`endif `endif
exec_stall = 1; regfile.dump_state;
csr.dump_state;
$finish;
`ifndef RVX0_CRASH_ON_EXCEPTION
end
`endif
end else if (exception_return) begin
$error("TODO: exception return (mret/sret)");
end else if (instruction_zicsr) begin
regfile_clk = zicsr_regfile_clk;
advance_pc = zicsr_exec_ready;
exec_ready = zicsr_exec_ready;
end else if (instruction_multi_cycle) begin
// "Slow" instruction datapath, allowing multi-cycle
// instructions like mul/div, etc
end else begin end else begin
`ifdef RVX0_DEBUGGING regfile_clk = 1;
$display("[%x] %x, rs1 (r%d)=%x, rs2 (r%d)=%x, v1src=%d, v2src=%d, vdsrc=%d", pc_value, instruction, rs1, rs1_value, rs2, rs2_value, v1src, v2src, vdsrc); advance_pc = 1;
$display("\talu_value1=%x, alu_value2=%x, imm=%x, rd_write_value=%x", alu_value1, alu_value2, imm, rd_write_value);
$display("\tmri=%x, mro=%x, mwi=%x, mwo=%x", memory_read_input, memory_read_output, memory_write_input, memory_write_output);
`endif
exec_ready = 1; exec_ready = 1;
end end
end end
+79 -32
View File
@@ -11,42 +11,89 @@ module rvx0_csr (
input wire mcause_write_i, input wire mcause_write_i,
input wire mtval_write_i, input wire mtval_write_i,
output wire [31:0] misa_o, // Hardwired output wire [31:0] mtvec_o,
output wire [31:0] mvendorid_o, // Hardwired
output wire [31:0] marchid_o, // Hardwired // CSR access
output wire [31:0] mimpid_o, // Hardwired input wire csr_write_i,
output wire [31:0] mhartid_o, // Hardwired input wire [11:0] csr_index_i,
output reg [31:0] mstatus_o, // TODO input wire [31:0] csr_write_value_i,
output reg [31:0] mstatush_o, // TODO output logic [31:0] csr_read_value_o,
output reg [31:0] mtvec_o, output logic undefined_csr_o
output reg [31:0] mepc_o,
output reg [31:0] mcause_o,
output reg [31:0] mtval_o // TODO
); );
// Add extensions here :) const logic [3:0] IDX_MISA = 0;
assign misa_o = MISA_MXLEN_32; const logic [3:0] IDX_MVENDORID = 1;
assign mvendorid_o = 0; const logic [3:0] IDX_MARCHID = 2;
assign marchid_o = 0; const logic [3:0] IDX_MIMPID = 3;
assign mimpid_o = 0; const logic [3:0] IDX_MHARTID = 4;
assign mhartid_o = 0; const logic [3:0] IDX_MSTATUS = 5;
const logic [3:0] IDX_MSTATUSH = 6;
const logic [3:0] IDX_MTVEC = 7;
const logic [3:0] IDX_MEPC = 8;
const logic [3:0] IDX_MCAUSE = 9;
const logic [3:0] IDX_MTVAL = 10;
const logic [3:0] IDX_MSCRATCH = 11;
logic [31:0] csr_values [0:15];
logic [3:0] selected_csr;
wire non_insn_write;
assign mtvec_o = csr_values[IDX_MTVEC];
assign non_insn_write = mepc_write_i || mtval_write_i || mcause_write_i;
assign csr_read_value_o = csr_values[selected_csr];
function void dump_state;
$display("CSR state:");
$display(
"\tmtvec=%x, mtval=%x, mepc=%x, mcause=%x",
csr_values[IDX_MTVEC], csr_values[IDX_MTVAL],
csr_values[IDX_MEPC], csr_values[IDX_MCAUSE]
);
$display("\tmscratch=%x", csr_values[IDX_MSCRATCH]);
endfunction
always_comb begin
undefined_csr_o = 0;
selected_csr = 0;
case (csr_index_i)
// Machine trap setup
'h305: selected_csr = IDX_MTVEC;
// Machine trap handling
'h340: selected_csr = IDX_MSCRATCH;
'h341: selected_csr = IDX_MEPC;
'h342: selected_csr = IDX_MCAUSE;
'h343: selected_csr = IDX_MTVAL;
default: undefined_csr_o = 1;
endcase
end
always @(posedge clk_i) begin always @(posedge clk_i) begin
if (rst_i) begin if (rst_i) begin
// TODO set from CPU csr_values[IDX_MTVEC] <= 0;
mtvec_o = 'h00001004; csr_values[IDX_MEPC] <= 0;
mepc_o = 0; csr_values[IDX_MSTATUS] <= 0;
mstatus_o = 0; csr_values[IDX_MSTATUSH] <= 0;
mstatush_o = 0; end else begin
end if (non_insn_write) begin
// Non-Zicsr writes take precedence (likely from an exception)
if (mepc_write_i) begin if (mepc_write_i) begin
mepc_o <= mepc_i; $display("CSR write mepc <= %x", mepc_i);
end csr_values[IDX_MEPC] <= mepc_i;
if (mcause_write_i) begin end
mcause_o <= mcause_i; if (mcause_write_i) begin
end csr_values[IDX_MCAUSE] <= mcause_i;
if (mtval_write_i) begin end
mtval_o <= mtval_i; if (mtval_write_i) begin
csr_values[IDX_MTVAL] <= mtval_i;
end
end else if (csr_write_i && ~undefined_csr_o) begin
$display("CSR write: %d (%x) <= %x", selected_csr, csr_index_i, csr_write_value_i);
if (selected_csr >= IDX_MSTATUS) begin
csr_values[selected_csr] <= csr_write_value_i;
end
end
end end
end end
endmodule endmodule
+26 -1
View File
@@ -22,6 +22,32 @@ module rvx0_fault_encoder (
output logic [31:0] mepc_write_value_o, output logic [31:0] mepc_write_value_o,
output logic fault_o output logic fault_o
); );
function void dump_fault;
$display("Fault:");
if (fault_instruction_align_i) begin
$display("\tfault_instruction_align_i");
end
if (fault_instruction_fetch_i) begin
$display("\tfault_instruction_fetch_i");
end
if (fault_instruction_decode_i) begin
$display("\tfault_instruction_decode_i");
end
if (fault_memory_align_i) begin
$display("\tfault_memory_align_i");
end
if (fault_memory_access_i) begin
$display("\tfault_memory_access_i");
end
if (raise_ecall_i) begin
$display("\traise_ecall_i");
end
if (raise_ebreak_i) begin
$display("\traise_ebreak_i");
end
endfunction
assign fault_o = fault_instruction_align_i || assign fault_o = fault_instruction_align_i ||
fault_instruction_fetch_i || fault_instruction_fetch_i ||
fault_instruction_decode_i || fault_instruction_decode_i ||
@@ -67,5 +93,4 @@ module rvx0_fault_encoder (
mcause_write_value_o = MCAUSE_INTR_EXT_MMODE | MCAUSE_INTERRUPT; mcause_write_value_o = MCAUSE_INTR_EXT_MMODE | MCAUSE_INTERRUPT;
end end
end end
endmodule endmodule
+119
View File
@@ -0,0 +1,119 @@
module rvx0_zicsr (
input wire clk_i,
input wire rst_i,
input wire [2:0] funct3_i,
input wire [31:0] rs1_value_i,
input wire [4:0] rd_i,
input wire [31:0] imm_i,
input wire [31:0] csr_value_i,
input wire undefined_csr_i,
output logic exec_ready_o,
output logic regfile_clk_o,
// CSR access
output logic instruction_fault_o,
output logic [31:0] csr_read_output_o,
output logic [31:0] csr_write_output_o,
output logic [11:0] csr_index_o,
output logic csr_write_o,
output logic csr_clk_o
);
logic need_csr_read;
logic need_csr_write;
logic single_cycle;
logic [31:0] value1;
logic [31:0] value2;
logic [31:0] rs1_value_latch;
logic [31:0] csr_value_latch;
logic [1:0] latch_state;
wire [31:0] csrrs_output;
wire [31:0] csrrc_output;
assign csr_index_o = imm_i[11:0];
assign csrrs_output = value1 | value2;
assign csrrc_output = value1 & ~value2;
assign exec_ready_o = single_cycle || latch_state == 2;
assign csr_write_o = single_cycle ? need_csr_write : latch_state == 2;
assign regfile_clk_o = single_cycle ? need_csr_read : latch_state == 2;
assign value1 = single_cycle ? csr_value_i : csr_value_latch;
assign value2 = single_cycle ? rs1_value_i : rs1_value_latch;
assign csr_read_output_o = single_cycle ? csr_value_i : csr_value_latch;
always_comb begin
instruction_fault_o = undefined_csr_i;
need_csr_read = 0;
single_cycle = 0;
csr_write_output_o = 0;
case (funct3_i)
3'b001: begin // csrrw
need_csr_read = rd_i != 0;
need_csr_write = 1;
csr_write_output_o = value2;
end
3'b010: begin // csrrs
need_csr_read = 1;
need_csr_write = rs1_value_i != 0;
csr_write_output_o = csrrs_output;
end
3'b011: begin // csrrc
need_csr_read = 1;
need_csr_write = rs1_value_i != 0;
csr_write_output_o = csrrc_output;
end
// TODO csrrwi, csrrsi, csrrci
default: instruction_fault_o = 1;
endcase
if ((need_csr_read && ~need_csr_write) || (~need_csr_read && need_csr_write)) begin
single_cycle = 1;
end
end
always @(posedge clk_i) begin
if (rst_i || instruction_fault_o) begin
latch_state <= 0;
end else begin
if (~need_csr_read && ~need_csr_write) begin
$error("TODO: no-op zicsr instruction?");
end
if (single_cycle) begin
latch_state <= 0;
if (need_csr_read) begin
$display("CSR read: csr=%x, csr_read_output_o=%x", csr_index_o, csr_read_output_o);
end else begin
$display("CSR write: csr=%x, csr_write_output_o=%x", csr_index_o, csr_write_output_o);
end
end else begin
// need_csr_read && need_csr_write
case (latch_state)
0: begin
// Latch CSR and RS1 values
csr_value_latch <= csr_value_i;
rs1_value_latch <= rs1_value_i;
$display("Latched values: csr_value_latch=%x, rs1_value_latch=%x", csr_value_latch, rs1_value_latch);
latch_state <= 1;
end
1: begin
// Writeback
latch_state <= 2;
end
2: begin
latch_state <= 0;
end
endcase
end
end
end
endmodule
+42 -17
View File
@@ -8,17 +8,19 @@ module rvx0_decoder (
output logic write_mem_o, output logic write_mem_o,
output logic conditional_o, output logic conditional_o,
output logic is_system_o,
output logic raise_ecall_o, output logic raise_ecall_o,
output logic raise_ebreak_o, output logic raise_ebreak_o,
output logic instruction_multi_cycle_o,
output logic instruction_zicsr_o,
output logic exception_return_o,
output logic instruction_fault_o, output logic instruction_fault_o,
output logic [6:0] opcode_o, output logic [6:0] opcode_o,
output wire [31:0] imm_o, output wire [31:0] imm_o,
output wire v1src_o, output wire v1src_o,
output wire [1:0] v2src_o, output wire [1:0] v2src_o,
output wire [1:0] vdsrc_o, output wire [2:0] vdsrc_o,
output wire [3:0] aluop_o, output wire [3:0] aluop_o,
output wire [2:0] funct3_o, output wire [2:0] funct3_o,
output wire [6:0] funct7_o, output wire [6:0] funct7_o,
@@ -55,7 +57,7 @@ module rvx0_decoder (
wire base_write_mem; wire base_write_mem;
wire base_v1src; wire base_v1src;
wire [1:0] base_v2src; wire [1:0] base_v2src;
wire [1:0] base_vdsrc; wire [2:0] base_vdsrc;
wire base_conditional; wire base_conditional;
wire [3:0] base_aluop; wire [3:0] base_aluop;
wire [31:0] base_imm; wire [31:0] base_imm;
@@ -85,16 +87,13 @@ module rvx0_decoder (
); );
always_comb begin always_comb begin
is_system_o = 0;
case (opcode_o)
'b0001111: is_system_o = 1;
'b1110011: is_system_o = 1;
endcase
raise_ecall_o = 0; raise_ecall_o = 0;
raise_ebreak_o = 0; raise_ebreak_o = 0;
instruction_multi_cycle_o = 0;
instruction_zicsr_o = 0;
exception_return_o = 0;
write_pc_o = 0; write_pc_o = 0;
write_mem_o = 0; write_mem_o = 0;
conditional_o = 0; conditional_o = 0;
@@ -106,14 +105,40 @@ module rvx0_decoder (
vdsrc_o = RDSRC_NONE; vdsrc_o = RDSRC_NONE;
aluop_o = ALUOP_ADD; aluop_o = ALUOP_ADD;
if (rs1_o == 0 && funct3_o == 0 && rd_o == 0 && opcode_o == 'b1110011) begin if (opcode_o == 'b1110011) begin
case (instruction_i[31:20]) case (funct3_o)
0: raise_ecall_o = 1; 0: begin
1: raise_ebreak_o = 1; if (rd_o == 0 && rs1_o == 0) begin
default: instruction_fault_o = 1; case (instruction_i[31:20])
0: raise_ecall_o = 1;
1: raise_ebreak_o = 1;
'h302: if (rs2_o == 2) begin
exception_return_o = 1;
end else begin
instruction_fault_o = 1;
end
default: instruction_fault_o = 1;
endcase
end else begin
instruction_fault_o = 1;
end
end
4: instruction_fault_o = 1;
default: begin
instruction_zicsr_o = 1;
instruction_multi_cycle_o = 1;
vdsrc_o = RDSRC_CSR;
imm_o = { 20'b0, instruction_i[31:20] };
end
endcase endcase
if (instruction_fault_o) begin
$display("instruction_fault_o on SYSTEM");
$display("\timm=%b, rs2=%d, rs1=%d, funct3=%b, rd=%d", instruction_i[31:20], rs2_o, rs1_o, funct3_o, rd_o);
end
end else if (rs1_o == 0 && funct3_o == 0 && opcode_o == 'b0001111) begin end else if (rs1_o == 0 && funct3_o == 0 && opcode_o == 'b0001111) begin
// Nice // Nothing
end else begin end else begin
instruction_fault_o = base_instruction_fault; instruction_fault_o = base_instruction_fault;
+1 -1
View File
@@ -19,7 +19,7 @@ module rvx0_decoder_i (
output wire [31:0] imm_o, output wire [31:0] imm_o,
output wire v1src_o, output wire v1src_o,
output wire [1:0] v2src_o, output wire [1:0] v2src_o,
output wire [1:0] vdsrc_o, output wire [2:0] vdsrc_o,
output wire [3:0] aluop_o output wire [3:0] aluop_o
); );
always_comb begin always_comb begin
+10 -5
View File
@@ -1,13 +1,18 @@
`ifndef __RVX0_DEFS_SVH `ifndef __RVX0_DEFS_SVH
`define __RVX0_DEFS_SVH `define __RVX0_DEFS_SVH
`define RVX0_DEBUGGING 1 // `define RVX0_DEBUGGING 1
// `define RVX0_CRASH_ON_EXCEPTION 1 // `define RVX0_CRASH_ON_EXCEPTION 1
`define RVX0_ZICSR 1
const logic [1:0] RDSRC_ALU = 0; const logic [2:0] RDSRC_NONE = 0;
const logic [1:0] RDSRC_MEM = 1; const logic [2:0] RDSRC_ALU = 1;
const logic [1:0] RDSRC_PC = 2; const logic [2:0] RDSRC_MEM = 2;
const logic [1:0] RDSRC_NONE = 3; const logic [2:0] RDSRC_PC = 3;
const logic [2:0] RDSRC_CSR = 4;
const logic [2:0] RDSRC_MALU = 5; // TODO will be used for M extension
const logic [2:0] RDSRC_RES2 = 6;
const logic [2:0] RDSRC_RES3 = 7;
const logic V1SRC_ZERO = 0; const logic V1SRC_ZERO = 0;
const logic V1SRC_RS1 = 1; const logic V1SRC_RS1 = 1;
+2 -2
View File
@@ -10,10 +10,10 @@ module rvx0_simple_ram (
if (apb_slave.penable) begin if (apb_slave.penable) begin
if (apb_slave.pwrite) begin if (apb_slave.pwrite) begin
words[apb_slave.paddr[22:2]] <= apb_slave.pwdata; words[apb_slave.paddr[22:2]] <= apb_slave.pwdata;
$display("RAM write [%x] <= %x", apb_slave.paddr, apb_slave.pwdata); // $display("RAM write [%x] <= %x", apb_slave.paddr, apb_slave.pwdata);
end else begin end else begin
apb_slave.prdata <= words[apb_slave.paddr[22:2]]; apb_slave.prdata <= words[apb_slave.paddr[22:2]];
$display("RAM read %x <= [%x]", words[apb_slave.paddr[22:2]], apb_slave.paddr); // $display("RAM read %x <= [%x]", words[apb_slave.paddr[22:2]], apb_slave.paddr);
end end
apb_slave.pready <= 1; apb_slave.pready <= 1;