commit 3087975833e4d435f7b95dc7e56b4b3d705c068a Author: Mark Poliakov Date: Wed Sep 3 14:56:28 2025 +0300 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..38e8f3b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/obj_dir +/*.log +/log diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..357be16 --- /dev/null +++ b/Makefile @@ -0,0 +1,33 @@ +SRC_ALL=$(wildcard src/**/*.sv) +SRC_MODULE=$(filter-out %_top.sv,$(filter-out %_tb.sv,$(SRC_ALL))) +DEF_MODULE=$(wildcard src/*.svh) + +FIRMWARE_SRC=firmware/src/entry.S \ + firmware/src/main.rs \ + firmware/link.ld \ + firmware/Cargo.toml + +MAIN_TOP=src/rvx0_soc_top.sv + +all: obj_dir/rvx0 + +obj_dir/apb0_memory.hex: obj_dir/firmware.bin tool/makebin.py + ./tool/makebin.py obj_dir/firmware.bin $@ + +obj_dir/firmware.bin: firmware/target/riscv32i-unknown-none-elf/release/firmware + llvm-objcopy -O binary $< $@ + +firmware/target/riscv32i-unknown-none-elf/release/firmware: $(FIRMWARE_SRC) + cd firmware && cargo build --release + +obj_dir/rvx0: $(SRC_MODULE) $(DEF_MODULE) $(MAIN_TOP) obj_dir/apb0_memory.hex + mkdir -p obj_dir + verilator --assert --binary -Isrc -o rvx0 $(MAIN_TOP) $(SRC_MODULE) +# +# obj_dir/firmware.elf: $(FIRMWARE_OBJ) src/firmware.ld +# +# obj_dir/apb0_memory.hex: src/apb0_memory.S tool/makebin.py +# mkdir -p obj_dir +# riscv64-elf-gcc -c -o obj_dir/apb0_memory.o src/apb0_memory.S +# llvm-objcopy -O binary obj_dir/apb0_memory.o obj_dir/apb0_memory.bin +# ./tool/makebin.py obj_dir/apb0_memory.bin $@ diff --git a/firmware/.cargo/config.toml b/firmware/.cargo/config.toml new file mode 100644 index 0000000..17ca093 --- /dev/null +++ b/firmware/.cargo/config.toml @@ -0,0 +1,6 @@ +[target.riscv32i-unknown-none-elf] +rustflags = ["-Clink-arg=-Tlink.ld"] +[build] +target = "riscv32i-unknown-none-elf" +[unstable] +build-std = ["core"] diff --git a/firmware/.gitignore b/firmware/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/firmware/.gitignore @@ -0,0 +1 @@ +/target diff --git a/firmware/Cargo.lock b/firmware/Cargo.lock new file mode 100644 index 0000000..a50f075 --- /dev/null +++ b/firmware/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "firmware" +version = "0.1.0" diff --git a/firmware/Cargo.toml b/firmware/Cargo.toml new file mode 100644 index 0000000..678580a --- /dev/null +++ b/firmware/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "firmware" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/firmware/link.ld b/firmware/link.ld new file mode 100644 index 0000000..79cecd1 --- /dev/null +++ b/firmware/link.ld @@ -0,0 +1,35 @@ +ENTRY(__entry); + +SECTIONS { + . = 0x1000; + + .text : { + *(.text.entry) + *(.text*) + } + + . = ALIGN(4); + + .rodata : { + *(.rodata*) + . = ALIGN(4); + } + + . = 0x20000; + + .vectors : { + *(.text.vectors) + } + + . = 0x20000000; + + .data : { + *(.data*) + } + + . = ALIGN(16); + + .bss : { + *(.bss*) + } +} diff --git a/firmware/src/entry.S b/firmware/src/entry.S new file mode 100644 index 0000000..cb18f62 --- /dev/null +++ b/firmware/src/entry.S @@ -0,0 +1,22 @@ +.global __entry + +.pushsection .text.entry +.option push +.option norvc +__entry: + la sp, stack_top + jal {firmware_main} + +.option pop +.popsection // .text.entry + +.pushsection .text.vectors +__vector: + j . +.popsection // .text.vectors + +.pushsection .bss +stack_bottom: + .skip 2048 +stack_top: +.popsection // .bss diff --git a/firmware/src/main.rs b/firmware/src/main.rs new file mode 100644 index 0000000..a8b2587 --- /dev/null +++ b/firmware/src/main.rs @@ -0,0 +1,42 @@ +#![allow(unsafe_op_in_unsafe_fn)] +#![no_std] +#![no_main] + +use core::{arch::global_asm, fmt, panic::PanicInfo}; + +#[panic_handler] +fn panic_handler(_pi: &PanicInfo) -> ! { + loop {} +} + +struct D; + +const DEBUG_BASE: usize = 0x1000_0000; + +impl fmt::Write for D { + fn write_str(&mut self, s: &str) -> fmt::Result { + let ptr: *mut u32 = core::ptr::with_exposed_provenance_mut(DEBUG_BASE); + for byte in s.bytes() { + unsafe { ptr.write_volatile(byte as u32) }; + } + Ok(()) + } +} + +unsafe extern "C" fn firmware_main() -> ! { + use fmt::Write; + + let mut d = D; + for i in 0..10 { + write!(d, "Hello {i}").ok(); + write!(d, "\n").ok(); + } + + loop { + // TODO pause/system/fence instruction not implemented + // core::hint::spin_loop(); + core::arch::asm!("nop"); + } +} + +global_asm!(include_str!("entry.S"), firmware_main = sym firmware_main); diff --git a/src/core/rvx0_alu.sv b/src/core/rvx0_alu.sv new file mode 100644 index 0000000..4521f27 --- /dev/null +++ b/src/core/rvx0_alu.sv @@ -0,0 +1,40 @@ +module rvx0_alu ( + input wire [3:0] aluop_i, + input wire [31:0] value1_i, + input wire [31:0] value2_i, + input wire [31:0] imm_i, + + output logic [31:0] output_o +); + +wire [31:0] value1; +wire [31:0] value2; +wire [4:0] value2_lo; + +wire signed [31:0] value1_signed; +wire signed [31:0] value2_signed; + +assign value1 = value1_i; +assign value2 = value2_i + imm_i; + +assign value1_signed = value1; +assign value2_signed = value2; + +assign value2_lo = value2[4:0]; + +always_comb begin + case (aluop_i) + ALUOP_ADD: output_o = value1 + value2; + ALUOP_SLL: output_o = value1 << value2_lo; + ALUOP_SLT: output_o = 32'(value1_signed < value2_signed); + ALUOP_SLTU: output_o = 32'(value1 < value2); + ALUOP_XOR: output_o = value1 ^ value2; + ALUOP_SRL: output_o = value1 >> value2_lo; + ALUOP_OR: output_o = value1 | value2; + ALUOP_AND: output_o = value1 & value2; + ALUOP_SUB: output_o = value1 - value2; + ALUOP_SRA: output_o = value1 >>> value2_lo; + endcase +end + +endmodule diff --git a/src/core/rvx0_brancher.sv b/src/core/rvx0_brancher.sv new file mode 100644 index 0000000..9bf0b38 --- /dev/null +++ b/src/core/rvx0_brancher.sv @@ -0,0 +1,28 @@ +`include "rvx0_defs.svh" + +module rvx0_brancher ( + input wire [31:0] rs1_value_i, + input wire [31:0] rs2_value_i, + + input wire [2:0] funct3_i, + + output logic branch_taken_o +); + wire signed [31:0] rs1_value_signed; + wire signed [31:0] rs2_value_signed; + + assign rs1_value_signed = rs1_value_i; + assign rs2_value_signed = rs2_value_i; + + always_comb begin + case (funct3_i) + COND_EQ: branch_taken_o = rs1_value_i == rs2_value_i; + COND_NE: branch_taken_o = rs1_value_i != rs2_value_i; + COND_LT: branch_taken_o = rs1_value_signed < rs2_value_signed; + COND_GE: branch_taken_o = rs1_value_signed >= rs2_value_signed; + COND_LTU: branch_taken_o = rs1_value_i < rs2_value_i; + COND_GEU: branch_taken_o = rs1_value_i >= rs2_value_i; + default: branch_taken_o = 0; + endcase + end +endmodule diff --git a/src/core/rvx0_control.sv b/src/core/rvx0_control.sv new file mode 100644 index 0000000..1837155 --- /dev/null +++ b/src/core/rvx0_control.sv @@ -0,0 +1,133 @@ +`include "rvx0_defs.svh" + +module rvx0_control ( + input wire clk_i, + input wire rst_i, + + input wire need_memory_read_i, + input wire need_memory_write_i, + input wire exec_stall_i, + input wire exec_ready_i, + + input wire instruction_fault_i, + input wire intr_ext_i, + + input wire [31:0] memory_address_i, + input wire [31:0] memory_write_i, + input wire [31:0] pc_value_i, + + rvx0_apb.master apb_master, + + output reg [1:0] control_state_o, + output reg [31:0] instruction_o, + output reg [31:0] memory_read_o, + + output reg fault_instruction_align_o, + output reg fault_instruction_fetch_o, + output reg fault_memory_access_o +); + + always @(posedge clk_i) begin + if (rst_i) begin + control_state_o <= CSTATE_FETCH; + end + end + + // TODO handle pslverr + always @(negedge clk_i) begin + if (~rst_i) begin + case (control_state_o) + CSTATE_FETCH: begin + fault_instruction_fetch_o <= 0; + fault_instruction_align_o <= 0; + + if (intr_ext_i) begin + control_state_o <= CSTATE_EXEC; + instruction_o <= 0; + end else if (pc_value_i[1:0] != 0) begin + fault_instruction_align_o <= 1; + instruction_o <= 0; + + control_state_o <= CSTATE_EXEC; + end else begin + apb_master.paddr <= pc_value_i; + apb_master.pwrite <= 0; + apb_master.penable <= 1; + + if (apb_master.pslverr) begin + instruction_o <= 0; + fault_instruction_fetch_o <= 1; + + apb_master.penable <= 0; + + control_state_o <= CSTATE_EXEC; + end else if (apb_master.pready) begin + instruction_o <= apb_master.prdata; + apb_master.penable <= 0; + + control_state_o <= CSTATE_READ; + end + end + end + CSTATE_READ: begin + fault_memory_access_o <= 0; + + if (intr_ext_i) begin + control_state_o <= CSTATE_EXEC; + end else if (~need_memory_read_i || instruction_fault_i) begin + control_state_o <= CSTATE_EXEC; + end else begin + apb_master.paddr <= memory_address_i; + apb_master.pwrite <= 0; + apb_master.penable <= 1; + + if (apb_master.pslverr) begin + memory_read_o <= 0; + apb_master.penable <= 0; + + fault_memory_access_o <= 1; + + control_state_o <= CSTATE_EXEC; + end else if (apb_master.pready) begin + memory_read_o <= apb_master.prdata; + apb_master.penable <= 0; + + control_state_o <= CSTATE_EXEC; + end + end + end + CSTATE_EXEC: begin + if (exec_stall_i) begin + $display("control: exec_stall_i @ %x", pc_value_i); + control_state_o <= CSTATE_FETCH; + end else if (exec_ready_i) begin + control_state_o <= CSTATE_WRITE; + end + end + CSTATE_WRITE: begin + fault_memory_access_o <= 0; + + if (~need_memory_write_i) begin + control_state_o <= CSTATE_FETCH; + end else begin + apb_master.paddr <= memory_address_i; + apb_master.pwdata <= memory_write_i; + apb_master.pwrite <= 1; + apb_master.penable <= 1; + + $display("WRITE %x -> %x", memory_write_i, memory_address_i); + + if (apb_master.pslverr) begin + apb_master.penable <= 0; + fault_memory_access_o <= 1; + control_state_o <= CSTATE_EXEC; + end else if (apb_master.pready) begin + apb_master.penable <= 0; + control_state_o <= CSTATE_FETCH; + end + end + end + endcase + end + end +endmodule diff --git a/src/core/rvx0_core.sv b/src/core/rvx0_core.sv new file mode 100644 index 0000000..e176b15 --- /dev/null +++ b/src/core/rvx0_core.sv @@ -0,0 +1,301 @@ +/* verilator lint_off PINMISSING */ +/* verilator lint_off MULTIDRIVEN */ + +`include "rvx0_defs.svh" + +module rvx0_core #( + parameter RESET_VECTOR +) ( + input wire clk_i, + input wire rst_i, + + input wire intr_ext_i, + + rvx0_apb.master apb_master +); + wire [31:0] pc_value; + logic [31:0] pc_write_value; + wire fault; + + // CSRs + + wire [31:0] csr_mtvec; + wire [31:0] csr_mepc; + + // Exception generation + + logic [31:0] mcause_write_value; + logic [31:0] mepc_write_value; + logic [31:0] mtval_write_value; + + // Faults + + wire fault_memory_align; + wire fault_instruction; + wire fault_instruction_align; + wire fault_instruction_fetch; + wire fault_memory_access; + + // Generated faults + wire fault_instruction_decode; + wire fault_unsupported_size; + wire fault_address_align; + + // Control + + wire need_memory_read; + wire need_memory_write; + logic exec_ready; + logic exec_stall; + wire [1:0] control_state; + wire [31:0] instruction; + wire state_exec; + + // Regfile/control + + wire [31:0] rs1_value; + wire [31:0] rs2_value; + logic [31:0] rd_write_value; + + // Decoder + + wire conditional; + wire [4:0] rs1; + wire [4:0] rs2; + wire [4:0] rd; + wire v1src; + wire [1:0] v2src; + wire [1:0] vdsrc; + wire [31:0] imm; + wire [3:0] aluop; + wire write_pc; + wire [2:0] funct3; + + // Into ALU + + wire [31:0] alu_value1; + logic [31:0] alu_value2; + wire [31:0] alu_output; + + // Branch unit + + wire write_pc_and_taken; + wire branch_taken; + wire write_rd; + wire pc_clk; + + // Memword + + wire [31:0] memory_read_input; + wire [31:0] memory_read_output; + wire [31:0] memory_write_input; + wire [31:0] memory_write_output; + wire memory_access_partial; + + rvx0_pc #( + .RESET_VECTOR (RESET_VECTOR) + ) pc ( + .rst_i (rst_i), + .clk_i (pc_clk), + .pc_value_i (pc_write_value), + .write_pc_i (write_pc_and_taken), + .pc_value_o (pc_value) + ); + + rvx0_brancher brancher ( + .rs1_value_i (rs1_value), + .rs2_value_i (rs2_value), + .funct3_i (funct3), + .branch_taken_o (branch_taken) + ); + + rvx0_decoder decoder ( + .instruction_i (instruction), + + .v1src_o (v1src), + .v2src_o (v2src), + .vdsrc_o (vdsrc), + .rs1_o (rs1), + .rs2_o (rs2), + .rd_o (rd), + .imm_o (imm), + .aluop_o (aluop), + .write_mem_o (need_memory_write), + .write_pc_o (write_pc), + .funct3_o (funct3), + .instruction_fault_o (fault_instruction_decode), + .conditional_o (conditional) + ); + + rvx0_regfile regfile ( + .clk_i (clk_i), + .rst_i (rst_i), + + .rs1_i (rs1), + .rs2_i (rs2), + .rd_i (rd), + .write_value_i (rd_write_value), + .rd_write_i (write_rd), + + .rs1_o (rs1_value), + .rs2_o (rs2_value) + ); + + rvx0_alu alu ( + .aluop_i (aluop), + .value1_i (alu_value1), + .value2_i (alu_value2), + .imm_i (imm), + .output_o (alu_output) + ); + + // Control + + rvx0_control control ( + .clk_i (clk_i), + .rst_i (rst_i), + .apb_master (apb_master), + .control_state_o (control_state), + .instruction_o (instruction), + .instruction_fault_i (fault_instruction), + .pc_value_i (pc_value), + .memory_address_i (alu_output), + .need_memory_read_i (need_memory_read), + .need_memory_write_i (need_memory_write), + .exec_ready_i (exec_ready), + .exec_stall_i (exec_stall), + .memory_read_o (memory_read_input), + .memory_write_i (memory_write_output), + .fault_instruction_align_o (fault_instruction_align), + .fault_instruction_fetch_o (fault_instruction_fetch), + .fault_memory_access_o (fault_memory_access) + ); + + rvx0_memword memword ( + .memory_read_i (memory_read_input), + .memory_write_i (memory_write_input), + .memory_address_i (alu_output), + + .funct3_i (funct3), + + .memory_read_o (memory_read_output), + .memory_write_o (memory_write_output), + .memory_access_partial_o (memory_access_partial), + .alignment_fault_o (fault_address_align), + .unsupported_size_fault_o (fault_unsupported_size) + ); + + rvx0_csr csr ( + .clk_i (clk_i), + .rst_i (rst_i), + + .mepc_i (mepc_write_value), + .mepc_write_i (fault), + .mcause_i (mcause_write_value), + .mcause_write_i (fault), + .mtval_i (mtval_write_value), + .mtval_write_i (fault), + + .mtvec_o (csr_mtvec) + ); + + assign fault = fault_instruction_align || + fault_instruction_fetch || + fault_instruction || + fault_memory_align || + fault_memory_access || + intr_ext_i; + + assign fault_instruction = fault_instruction_decode || (fault_unsupported_size && (need_memory_read || need_memory_write)); + assign fault_memory_align = fault_address_align && (need_memory_write || need_memory_read); + + assign memory_write_input = rs2_value; + + assign need_memory_read = (vdsrc == RDSRC_MEM) || (need_memory_write && memory_access_partial); + assign alu_value1 = v1src == V1SRC_ZERO ? 0 : rs1_value; + assign state_exec = control_state == CSTATE_EXEC; + + assign pc_clk = (state_exec || rst_i) && clk_i; + + assign write_rd = (vdsrc != RDSRC_NONE) && state_exec && ~fault; + + assign write_pc_and_taken = ((conditional ? branch_taken : 1) && write_pc) || fault; + + // Value mux + always_comb begin + case (vdsrc) + RDSRC_PC: rd_write_value = pc_value + 4; + RDSRC_ALU: rd_write_value = alu_output; + RDSRC_MEM: rd_write_value = memory_read_output; + RDSRC_NONE: rd_write_value = 0; + endcase + + case (v2src) + V2SRC_ZERO: alu_value2 = 0; + V2SRC_PC: alu_value2 = pc_value; + V2SRC_RS2: alu_value2 = rs2_value; + endcase + + if (fault) begin + pc_write_value = csr_mtvec; + end else begin + pc_write_value = alu_output; + end + end + + // Exception parameter encoding + always_comb begin + mcause_write_value = 0; + mtval_write_value = 0; + mepc_write_value = pc_value; + + if (fault_instruction_align) begin + mcause_write_value = MCAUSE_INSTRUCTION_ADDRESS_MISALIGN; + end else if (fault_instruction_fetch) begin + mcause_write_value = MCAUSE_INSTRUCTION_ACCESS_FAULT; + mtval_write_value = pc_value; + end else if (fault_instruction) begin + mcause_write_value = MCAUSE_ILLEGAL_INSTRUCTION; + mtval_write_value = instruction; + end else if (~need_memory_write && fault_memory_align) begin + mcause_write_value = MCAUSE_LOAD_ADDRESS_MISALIGNED; + mtval_write_value = alu_output; + end else if (~need_memory_write && fault_memory_access) begin + mcause_write_value = MCAUSE_LOAD_ACCESS_FAULT; + end else if (fault_memory_align) begin + mcause_write_value = MCAUSE_STORE_ADDRESS_MISALIGNED; + mtval_write_value = alu_output; + end else if (fault_memory_access) begin + mcause_write_value = MCAUSE_STORE_ACCESS_FAULT; + // Because this happens at write pipeline stage and PC has already + // been incremented + mepc_write_value = pc_value - 4; + mtval_write_value = alu_output; + end else if (intr_ext_i) begin + mcause_write_value = MCAUSE_INTR_EXT_MMODE | MCAUSE_INTERRUPT; + end + end + + always @(posedge clk_i) begin + case (control_state) + CSTATE_EXEC: begin + exec_ready = 0; + exec_stall = 0; + + 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); + regfile.dump_state; + $finish; + exec_stall = 1; + end else begin +`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 + exec_ready = 1; + end + end + endcase + end +endmodule diff --git a/src/core/rvx0_csr.sv b/src/core/rvx0_csr.sv new file mode 100644 index 0000000..4a85208 --- /dev/null +++ b/src/core/rvx0_csr.sv @@ -0,0 +1,52 @@ +// TODO Zicsr +module rvx0_csr ( + input wire clk_i, + input wire rst_i, + + input wire [31:0] mepc_i, + input wire [31:0] mcause_i, + input wire [31:0] mtval_i, + + input wire mepc_write_i, + input wire mcause_write_i, + input wire mtval_write_i, + + output wire [31:0] misa_o, // Hardwired + output wire [31:0] mvendorid_o, // Hardwired + output wire [31:0] marchid_o, // Hardwired + output wire [31:0] mimpid_o, // Hardwired + output wire [31:0] mhartid_o, // Hardwired + output reg [31:0] mstatus_o, // TODO + output reg [31:0] mstatush_o, // TODO + output reg [31:0] mtvec_o, + output reg [31:0] mepc_o, + output reg [31:0] mcause_o, + output reg [31:0] mtval_o // TODO +); + // Add extensions here :) + assign misa_o = MISA_MXLEN_32; + assign mvendorid_o = 0; + assign marchid_o = 0; + assign mimpid_o = 0; + assign mhartid_o = 0; + + always @(posedge clk_i) begin + if (rst_i) begin + // TODO set from CPU + mtvec_o = 'h00020000; + mepc_o = 0; + mstatus_o = 0; + mstatush_o = 0; + end + + if (mepc_write_i) begin + mepc_o <= mepc_i; + end + if (mcause_write_i) begin + mcause_o <= mcause_i; + end + if (mtval_write_i) begin + mtval_o <= mtval_i; + end + end +endmodule diff --git a/src/core/rvx0_memword.sv b/src/core/rvx0_memword.sv new file mode 100644 index 0000000..1f547bc --- /dev/null +++ b/src/core/rvx0_memword.sv @@ -0,0 +1,70 @@ +module rvx0_memword ( + input wire [31:0] memory_read_i, + input wire [31:0] memory_write_i, + input wire [31:0] memory_address_i, + + input wire [2:0] funct3_i, + + output logic [31:0] memory_write_o, + output logic [31:0] memory_read_o, + output wire memory_access_partial_o, + output logic alignment_fault_o, + output logic unsupported_size_fault_o +); + wire sign_extend; + wire [4:0] shift; + wire signed [31:0] memory_read_signed; + wire [31:0] wmask_8b; + wire [31:0] wmask_16b; + logic [31:0] memory_read_unsigned; + + assign sign_extend = ~funct3_i[2]; + assign shift = memory_address_i[1:0] << 3; + + assign memory_access_partial_o = funct3_i[1:0] != 2'b10; + assign memory_read_signed = memory_read_unsigned; + + assign wmask_8b = 32'hFF << shift; + assign wmask_16b = 32'hFFFF << shift; + + always_comb begin + memory_read_unsigned = 0; + memory_write_o = 0; + alignment_fault_o = 0; + unsupported_size_fault_o = 0; + + case (funct3_i[1:0]) + 2'b00: begin + memory_read_unsigned = (memory_read_i >> shift) & 32'hFF; + + memory_write_o = (memory_read_i & ~wmask_8b) | ((memory_write_i & 32'hFF) << shift); + end + 2'b01: begin + memory_read_unsigned = (memory_read_i >> shift) & 32'hFFFF; + + memory_write_o = (memory_read_i & ~wmask_16b) | ((memory_write_i & 32'hFFFF) << shift); + + if (memory_address_i[0] != 0) begin + alignment_fault_o = 1; + end + end + 2'b10: begin + memory_read_unsigned = memory_read_i; + memory_write_o = memory_write_i; + + if (memory_address_i[1:0] != 0) begin + alignment_fault_o = 1; + end + end + 2'b11: begin + unsupported_size_fault_o = 1; + end + endcase + + if (sign_extend) begin + memory_read_o = memory_read_signed; + end else begin + memory_read_o = memory_read_unsigned; + end + end +endmodule diff --git a/src/core/rvx0_pc.sv b/src/core/rvx0_pc.sv new file mode 100644 index 0000000..67389a5 --- /dev/null +++ b/src/core/rvx0_pc.sv @@ -0,0 +1,20 @@ +module rvx0_pc #( + parameter logic [31:0] RESET_VECTOR +) ( + input wire clk_i, + input wire rst_i, + input wire write_pc_i, + input wire [31:0] pc_value_i, + + output reg [31:0] pc_value_o +); + always @(posedge clk_i) begin + if (rst_i) begin + pc_value_o <= RESET_VECTOR; + end else if (write_pc_i) begin + pc_value_o <= pc_value_i; + end else begin + pc_value_o <= pc_value_o + 4; + end + end +endmodule diff --git a/src/core/rvx0_regfile.sv b/src/core/rvx0_regfile.sv new file mode 100644 index 0000000..66f2a6f --- /dev/null +++ b/src/core/rvx0_regfile.sv @@ -0,0 +1,108 @@ +module rvx0_regfile ( + input wire clk_i, + input wire rst_i, + + input wire [4:0] rs1_i, + input wire [4:0] rs2_i, + input wire [4:0] rd_i, + + input wire [31:0] write_value_i, + input wire rd_write_i, + + output wire [31:0] rs1_o, + output wire [31:0] rs2_o +); + // Debugger friendly names + wire [31:0] ra; + wire [31:0] sp; + wire [31:0] gp; + wire [31:0] tp; + wire [31:0] t0; + wire [31:0] t1; + wire [31:0] t2; + wire [31:0] s0; + wire [31:0] s1; + wire [31:0] a0; + wire [31:0] a1; + wire [31:0] a2; + wire [31:0] a3; + wire [31:0] a4; + wire [31:0] a5; + wire [31:0] a6; + wire [31:0] a7; + wire [31:0] s2; + wire [31:0] s3; + wire [31:0] s4; + wire [31:0] s5; + wire [31:0] s6; + wire [31:0] s7; + wire [31:0] s8; + wire [31:0] s9; + wire [31:0] s10; + wire [31:0] s11; + wire [31:0] t3; + wire [31:0] t4; + wire [31:0] t5; + wire [31:0] t6; + + assign ra = regs[0]; + assign sp = regs[1]; + assign gp = regs[2]; + assign tp = regs[3]; + assign t0 = regs[4]; + assign t1 = regs[5]; + assign t2 = regs[6]; + assign s0 = regs[7]; + assign s1 = regs[8]; + assign a0 = regs[9]; + assign a1 = regs[10]; + assign a2 = regs[11]; + assign a3 = regs[12]; + assign a4 = regs[13]; + assign a5 = regs[14]; + assign a6 = regs[15]; + assign a7 = regs[16]; + assign s2 = regs[17]; + assign s3 = regs[18]; + assign s4 = regs[19]; + assign s5 = regs[20]; + assign s6 = regs[21]; + assign s7 = regs[22]; + assign s8 = regs[23]; + assign s9 = regs[24]; + assign s10 = regs[25]; + assign s11 = regs[26]; + assign t3 = regs[27]; + assign t4 = regs[28]; + assign t5 = regs[29]; + assign t6 = regs[30]; + + function void dump_state; + $display("ra=%x sp=%x gp=%x tp=%x", ra, sp, gp, tp); + $display("t0=%x t1=%x t2=%x s0=%x", t0, t1, t2, s0); + $display("s1=%x a0=%x a1=%x a2=%x", s1, a0, a1, a2); + $display("a3=%x a4=%x a5=%x a6=%x", a3, a4, a5, a6); + $display("a7=%x s2=%x s3=%x s4=%x", a7, s2, s3, s4); + $display("s5=%x s6=%x s7=%x s8=%x", s5, s6, s7, s8); + $display("s9=%x s10=%x s11=%x t3=%x", s9, s10, s11, t3); + $display("t4=%x t5=%x t6=%x", t4, t5, t6); + endfunction + + reg [31:0] regs [0:30]; + + assign rs1_o = rs1_i == 0 ? 0 : regs[rs1_i - 1]; + assign rs2_o = rs2_i == 0 ? 0 : regs[rs2_i - 1]; + + integer i; + + always @(posedge clk_i) begin + if (rst_i) begin + for (i = 0; i < 31; ++i) + regs[i] <= 0; + end else begin + if (rd_write_i && rd_i > 0) begin + regs[rd_i - 1] <= write_value_i; + end + end + end +endmodule diff --git a/src/decoder/rvx0_decoder.sv b/src/decoder/rvx0_decoder.sv new file mode 100644 index 0000000..5301e41 --- /dev/null +++ b/src/decoder/rvx0_decoder.sv @@ -0,0 +1,68 @@ +`include "rvx0_defs.svh" + +// Top-level instruction decoder module +module rvx0_decoder ( + input wire [31:0] instruction_i, + + output logic write_pc_o, + output logic write_mem_o, + output logic conditional_o, + + output logic instruction_fault_o, + output wire [31:0] imm_o, + output wire v1src_o, + output wire [1:0] v2src_o, + output wire [1:0] vdsrc_o, + output wire [3:0] aluop_o, + output wire [2:0] funct3_o, + output wire [6:0] funct7_o, + output wire [4:0] rs1_o, + output wire [4:0] rs2_o, + output wire [4:0] rd_o +); + wire [6:0] opcode; + + wire signed [11:0] imm_i_type; + wire signed [11:0] imm_s_type; + wire signed [12:0] imm_b_type; + wire [19:0] imm_u_type; + wire signed [20:0] imm_j_type; + + assign opcode = instruction_i[6:0]; + assign funct3_o = instruction_i[14:12]; + assign funct7_o = instruction_i[31:25]; + + assign imm_i_type = instruction_i[31:20]; + assign imm_s_type = { instruction_i[31:25], instruction_i[11:7] }; + assign imm_b_type = { instruction_i[31], instruction_i[7], instruction_i[30:25], instruction_i[11:8], 1'b0 }; + assign imm_u_type = instruction_i[31:12]; + assign imm_j_type = { instruction_i[31], instruction_i[19:12], instruction_i[20], instruction_i[30:21], 1'b0 }; + + assign rs1_o = instruction_i[19:15]; + assign rs2_o = instruction_i[24:20]; + assign rd_o = instruction_i[11:7]; + + rvx0_decoder_i decoder_i ( + .instruction_i (instruction_i), + + .opcode (opcode), + .funct3 (funct3_o), + + .imm_i_type (imm_i_type), + .imm_s_type (imm_s_type), + .imm_b_type (imm_b_type), + .imm_u_type (imm_u_type), + .imm_j_type (imm_j_type), + + .write_pc_o (write_pc_o), + .write_mem_o (write_mem_o), + .conditional_o (conditional_o), + + .instruction_fault_o (instruction_fault_o), + .imm_o (imm_o), + .v1src_o (v1src_o), + .v2src_o (v2src_o), + .vdsrc_o (vdsrc_o), + .aluop_o (aluop_o) + ); +endmodule diff --git a/src/decoder/rvx0_decoder_i.sv b/src/decoder/rvx0_decoder_i.sv new file mode 100644 index 0000000..565dc22 --- /dev/null +++ b/src/decoder/rvx0_decoder_i.sv @@ -0,0 +1,116 @@ +// Base rv32i instruction set decoder +module rvx0_decoder_i ( + input wire [31:0] instruction_i, + + input wire [6:0] opcode, + input wire [2:0] funct3, + + input wire signed [11:0] imm_i_type, + input wire signed [11:0] imm_s_type, + input wire signed [12:0] imm_b_type, + input wire [19:0] imm_u_type, + input wire signed [20:0] imm_j_type, + + output logic write_pc_o, + output logic write_mem_o, + output logic conditional_o, + + output logic instruction_fault_o, + output wire [31:0] imm_o, + output wire v1src_o, + output wire [1:0] v2src_o, + output wire [1:0] vdsrc_o, + output wire [3:0] aluop_o +); + always_comb begin + write_pc_o = 0; + write_mem_o = 0; + conditional_o = 0; + instruction_fault_o = 0; + aluop_o = 0; + + case (opcode) + 7'b0110111: begin // lui + v1src_o = V1SRC_ZERO; + v2src_o = V2SRC_ZERO; + vdsrc_o = RDSRC_ALU; + imm_o = { imm_u_type, 12'b0 }; + end + 7'b0010111: begin // auipc + v1src_o = V1SRC_ZERO; + v2src_o = V2SRC_PC; + vdsrc_o = RDSRC_ALU; + imm_o = { imm_u_type, 12'b0 }; + end + 7'b1101111: begin // jal + v1src_o = V1SRC_ZERO; + v2src_o = V2SRC_PC; + vdsrc_o = RDSRC_PC; + write_pc_o = 1; + imm_o = 32'(signed'(imm_j_type)); + end + 7'b1100111: begin // jalr + v1src_o = V1SRC_RS1; + v2src_o = V2SRC_ZERO; + vdsrc_o = RDSRC_PC; + write_pc_o = 1; + imm_o = 32'(signed'(imm_i_type)); + end + 7'b1100011: begin // b.??? + v1src_o = V1SRC_ZERO; + v2src_o = V2SRC_PC; + vdsrc_o = RDSRC_NONE; + write_pc_o = 1; + conditional_o = 1; + imm_o = 32'(signed'(imm_b_type)); + end + 7'b0000011: begin // load + v1src_o = V1SRC_RS1; + v2src_o = V2SRC_ZERO; + vdsrc_o = RDSRC_MEM; + imm_o = 32'(signed'(imm_i_type)); + end + 7'b0100011: begin // store + v1src_o = V1SRC_RS1; + v2src_o = V2SRC_ZERO; + vdsrc_o = RDSRC_NONE; + write_mem_o = 1; + imm_o = 32'(signed'(imm_s_type)); + end + 7'b0010011: begin // alu imm + v1src_o = V1SRC_RS1; + v2src_o = V2SRC_ZERO; + vdsrc_o = RDSRC_ALU; + case (funct3) + 3'b001: begin + aluop_o = ALUOP_SLL; + imm_o = { 27'b0, instruction_i[24:20] }; + end + 3'b101: begin + aluop_o = { instruction_i[30], funct3 }; + imm_o = { 27'b0, instruction_i[24:20] }; + end + default: begin + aluop_o = { 1'b0, funct3 }; + imm_o = 32'(signed'(imm_i_type)); + end + endcase + end + 7'b0110011: begin + v1src_o = V1SRC_RS1; + v2src_o = V2SRC_RS2; + vdsrc_o = RDSRC_ALU; + aluop_o = { instruction_i[30], funct3 }; + imm_o = 0; + end + default: begin + v1src_o = V1SRC_ZERO; + v2src_o = V2SRC_ZERO; + vdsrc_o = RDSRC_NONE; + instruction_fault_o = 1; + imm_o = 0; + end + endcase + + end +endmodule diff --git a/src/decoder/rvx0_decoder_tb.sv b/src/decoder/rvx0_decoder_tb.sv new file mode 100644 index 0000000..c8ad29f --- /dev/null +++ b/src/decoder/rvx0_decoder_tb.sv @@ -0,0 +1,122 @@ +/* verilator lint_off PINMISSING */ + +`include "rvx0_defs.svh" + +module rvx0_decoder_tb (); + reg [31:0] instruction; + + rvx0_decoder dut ( + .instruction_i (instruction) + ); + + initial begin + // lui sp, 0x12345 + instruction = 'h12345137; + #1 + assert(dut.imm_o == 'h12345000); + assert(dut.write_pc_o == 0); + assert(dut.v1src_o == V1SRC_ZERO); + assert(dut.v2src_o == V2SRC_ZERO); + assert(dut.vdsrc_o == RDSRC_ALU); + assert(dut.rd_o == 2); + assert(~dut.instruction_fault_o); + + // auipc ra, 0xFEEF1 + #1 + instruction = 'hFEEF1097; + #1 + assert(dut.imm_o == 'hFEEF1000); + assert(dut.write_pc_o == 0); + assert(dut.v1src_o == V1SRC_ZERO); + assert(dut.v2src_o == V2SRC_PC); + assert(dut.vdsrc_o == RDSRC_ALU); + assert(dut.rd_o == 1); + assert(~dut.instruction_fault_o); + + // j . -> jal zero, 0 + #1 + instruction = 'h0000006f; + #1 + assert(dut.imm_o == 0); + assert(dut.write_pc_o == 1); + assert(dut.v1src_o == V1SRC_ZERO); + assert(dut.v2src_o == V2SRC_PC); + assert(dut.vdsrc_o == RDSRC_PC); + assert(dut.rd_o == 0); + assert(~dut.instruction_fault_o); + + // jalr x2, x3, 0x123 + #1 + instruction = 'hEDD18167; + #1 + assert(dut.imm_o == -'h123); + assert(dut.write_pc_o == 1); + assert(dut.v1src_o == V1SRC_RS1); + assert(dut.v2src_o == V2SRC_ZERO); + assert(dut.vdsrc_o == RDSRC_PC); + assert(dut.rd_o == 2); + assert(dut.rs1_o == 3); + assert(~dut.instruction_fault_o); + + // bne sp, gp, 0x24 + #1 + instruction = 'h02311263; + #1 + assert(dut.imm_o == 'h24); + assert(dut.write_pc_o == 1); + assert(dut.conditional_o == 1); + assert(dut.v1src_o == V1SRC_ZERO); + assert(dut.v2src_o == V2SRC_PC); + assert(dut.vdsrc_o == RDSRC_NONE); + assert(dut.rs1_o == 2); + assert(dut.rs2_o == 3); + assert(dut.funct3_o == 'b001); + assert(~dut.instruction_fault_o); + + // lw t0, 0x10(t1) + #1 + instruction = 'h01032283; + #1 + assert(dut.imm_o == 'h10); + assert(dut.write_pc_o == 0); + assert(dut.write_mem_o == 0); + assert(dut.v1src_o == V1SRC_RS1); + assert(dut.v2src_o == V2SRC_ZERO); + assert(dut.vdsrc_o == RDSRC_MEM); + assert(dut.rs1_o == 6); + assert(dut.rd_o == 5); + assert(dut.funct3_o == 'b010); + assert(~dut.instruction_fault_o); + + // sh t0, -0x10(t1) + #1 + instruction = 'hFE531823; + #1 + assert(dut.imm_o == -'h10); + assert(dut.write_pc_o == 0); + assert(dut.write_mem_o == 1); + assert(dut.v1src_o == V1SRC_RS1); + assert(dut.v2src_o == V2SRC_ZERO); + assert(dut.vdsrc_o == RDSRC_NONE); + assert(dut.rs1_o == 6); + assert(dut.rs2_o == 5); + assert(dut.funct3_o == 'b001); + assert(~dut.instruction_fault_o); + + // xori t0, t2, 0xC + #1 + instruction = 'h00C3C293; + #1 + assert(dut.imm_o == 'hC); + assert(dut.write_pc_o == 0); + assert(dut.write_mem_o == 0); + assert(dut.v1src_o == V1SRC_RS1); + assert(dut.v2src_o == V2SRC_ZERO); + assert(dut.vdsrc_o == RDSRC_ALU); + assert(dut.rd_o == 5); + assert(dut.rs1_o == 7); + assert(dut.funct3_o == 'b100); + assert(dut.aluop_o == 'b0100); + assert(~dut.instruction_fault_o); + end +endmodule diff --git a/src/rvx0_apb.sv b/src/rvx0_apb.sv new file mode 100644 index 0000000..2200289 --- /dev/null +++ b/src/rvx0_apb.sv @@ -0,0 +1,25 @@ +/* verilator lint_off UNOPTFLAT */ + +interface rvx0_apb (); + logic pclk; + logic prstn; + logic [31:0] paddr; + logic pwrite; + logic penable; + logic [31:0] pwdata; + logic psel; + + logic pready; + logic [31:0] prdata; + logic pslverr; + + modport master ( + input pready, prdata, pslverr, + output pclk, prstn, paddr, penable, pwrite, pwdata + ); + + modport slave ( + input pclk, prstn, paddr, pwrite, penable, pwdata, psel, + output pready, prdata, pslverr + ); +endinterface diff --git a/src/rvx0_apb_debug.sv b/src/rvx0_apb_debug.sv new file mode 100644 index 0000000..75f6cf8 --- /dev/null +++ b/src/rvx0_apb_debug.sv @@ -0,0 +1,20 @@ +module rvx0_apb_debug ( + rvx0_apb.slave apb_slave +); + integer fd; + + initial begin + fd = $fopen("debug.log", "w"); + end + + always @(posedge apb_slave.pclk) begin + if (apb_slave.prstn && apb_slave.penable) begin + if (apb_slave.pwrite) begin + $fwrite(fd, "%c", apb_slave.pwdata[7:0]); + $fflush(fd); + end + + apb_slave.pready <= 1; + end + end +endmodule diff --git a/src/rvx0_busmux.sv b/src/rvx0_busmux.sv new file mode 100644 index 0000000..f230e81 --- /dev/null +++ b/src/rvx0_busmux.sv @@ -0,0 +1,98 @@ +module rvx0_busmux ( + // Uplink to core + rvx0_apb.slave apb_slave, + + // Downlinks to peripherals/memory + rvx0_apb.master apb0_master, + rvx0_apb.master apb1_master, + rvx0_apb.master apb2_master, + rvx0_apb.master apb3_master +); + // ROM + const logic [31:0] APB0_BASE = 'h00001000; + const logic [31:0] APB0_SIZE = 'h00020000; + + // RAM + const logic [31:0] APB1_BASE = 'h20000000; + const logic [31:0] APB1_SIZE = 'h00001000; + + // Debug + const logic [31:0] APB2_BASE = 'h10000000; + const logic [31:0] APB2_SIZE = 'h00001000; + + // Forward pclk/prstn + assign apb0_master.pclk = apb_slave.pclk; + assign apb1_master.pclk = apb_slave.pclk; + assign apb2_master.pclk = apb_slave.pclk; + assign apb3_master.pclk = apb_slave.pclk; + + assign apb0_master.prstn = apb_slave.prstn; + assign apb1_master.prstn = apb_slave.prstn; + assign apb2_master.prstn = apb_slave.prstn; + assign apb3_master.prstn = apb_slave.prstn; + + always_comb begin + apb0_master.penable = 0; + apb1_master.penable = 0; + apb2_master.penable = 0; + apb3_master.penable = 0; + + apb0_master.pwrite = 0; + apb1_master.pwrite = 0; + apb2_master.pwrite = 0; + apb3_master.pwrite = 0; + + apb0_master.pwdata = 0; + apb1_master.pwdata = 0; + apb2_master.pwdata = 0; + apb3_master.pwdata = 0; + + apb0_master.paddr = 0; + apb1_master.paddr = 0; + apb2_master.paddr = 0; + apb3_master.paddr = 0; + + apb_slave.pready = 0; + apb_slave.pslverr = 0; + apb_slave.prdata = 0; + + if (apb_slave.prstn && apb_slave.penable) begin + if (apb_slave.paddr >= APB0_BASE && apb_slave.paddr < APB0_BASE + APB0_SIZE) begin + // Connect to apb0 + apb0_master.paddr = apb_slave.paddr - APB0_BASE; + apb0_master.pwdata = apb_slave.pwdata; + apb0_master.pwrite = apb_slave.pwrite; + apb0_master.penable = apb_slave.penable; + + apb_slave.pready = apb0_master.pready && apb_slave.penable; + apb_slave.pslverr = apb0_master.pslverr; + apb_slave.prdata = apb0_master.prdata; + end else if (apb_slave.paddr >= APB1_BASE && apb_slave.paddr < APB1_BASE + APB1_SIZE) begin + // Connect to apb1 + apb1_master.paddr = apb_slave.paddr - APB1_BASE; + apb1_master.pwdata = apb_slave.pwdata; + apb1_master.pwrite = apb_slave.pwrite; + apb1_master.penable = apb_slave.penable; + + apb_slave.pready = apb1_master.pready && apb_slave.penable; + apb_slave.pslverr = apb1_master.pslverr; + apb_slave.prdata = apb1_master.prdata; + end else if (apb_slave.paddr >= APB2_BASE && apb_slave.paddr < APB2_BASE + APB2_SIZE) begin + // Connect to apb2 + apb2_master.paddr = apb_slave.paddr - APB2_BASE; + apb2_master.pwdata = apb_slave.pwdata; + apb2_master.pwrite = apb_slave.pwrite; + apb2_master.penable = apb_slave.penable; + + apb_slave.pready = apb2_master.pready && apb_slave.penable; + apb_slave.pslverr = apb2_master.pslverr; + apb_slave.prdata = apb2_master.prdata; + end else begin + // Raise bus error + apb_slave.pslverr = 1; + end + end else begin + apb_slave.pslverr = 0; + end + end +endmodule diff --git a/src/rvx0_defs.svh b/src/rvx0_defs.svh new file mode 100644 index 0000000..0e1f65c --- /dev/null +++ b/src/rvx0_defs.svh @@ -0,0 +1,61 @@ +`ifndef __RVX0_DEFS_SVH +`define __RVX0_DEFS_SVH + +`define RVX0_DEBUGGING 1 + +const logic [1:0] RDSRC_ALU = 0; +const logic [1:0] RDSRC_MEM = 1; +const logic [1:0] RDSRC_PC = 2; +const logic [1:0] RDSRC_NONE = 3; + +const logic V1SRC_ZERO = 0; +const logic V1SRC_RS1 = 1; + +const logic [1:0] V2SRC_ZERO = 0; +const logic [1:0] V2SRC_RS2 = 1; +const logic [1:0] V2SRC_PC = 2; + +const logic [3:0] ALUOP_ADD = 4'b0000; +const logic [3:0] ALUOP_SLL = 4'b0001; +const logic [3:0] ALUOP_SLT = 4'b0010; +const logic [3:0] ALUOP_SLTU = 4'b0011; +const logic [3:0] ALUOP_XOR = 4'b0100; +const logic [3:0] ALUOP_SRL = 4'b0101; +const logic [3:0] ALUOP_OR = 4'b0110; +const logic [3:0] ALUOP_AND = 4'b0111; +const logic [3:0] ALUOP_SUB = 4'b1000; +const logic [3:0] ALUOP_SRA = 4'b1101; + +const logic [2:0] COND_EQ = 3'b000; +const logic [2:0] COND_NE = 3'b001; +const logic [2:0] COND_LT = 3'b100; +const logic [2:0] COND_GE = 3'b101; +const logic [2:0] COND_LTU = 3'b110; +const logic [2:0] COND_GEU = 3'b111; + +const logic [1:0] CSTATE_FETCH = 0; +const logic [1:0] CSTATE_READ = 1; +const logic [1:0] CSTATE_EXEC = 2; +const logic [1:0] CSTATE_WRITE = 3; + +const logic [31:0] MISA_MXLEN_32 = 1 << 30; + +const logic [31:0] MCAUSE_INSTRUCTION_ADDRESS_MISALIGN = 0; +const logic [31:0] MCAUSE_INSTRUCTION_ACCESS_FAULT = 1; +const logic [31:0] MCAUSE_ILLEGAL_INSTRUCTION = 2; +const logic [31:0] MCAUSE_BREAKPOINT = 3; +const logic [31:0] MCAUSE_LOAD_ADDRESS_MISALIGNED = 4; +const logic [31:0] MCAUSE_LOAD_ACCESS_FAULT = 5; +const logic [31:0] MCAUSE_STORE_ADDRESS_MISALIGNED = 6; +const logic [31:0] MCAUSE_STORE_ACCESS_FAULT = 7; +const logic [31:0] MCAUSE_ECALL_UMODE = 8; +const logic [31:0] MCAUSE_ECALL_SMODE = 9; +const logic [31:0] MCAUSE_ECALL_MMODE = 11; +const logic [31:0] MCAUSE_INSTRUCTION_PAGE_FAULT = 12; +const logic [31:0] MCAUSE_LOAD_PAGE_FAULT = 13; +const logic [31:0] MCAUSE_STORE_PAGE_FAULT = 15; + +const logic [31:0] MCAUSE_INTR_EXT_MMODE = 11; +const logic [31:0] MCAUSE_INTERRUPT = 1 << 31; + +`endif // __RVX0_DEFS_SVH diff --git a/src/rvx0_simple_ram.sv b/src/rvx0_simple_ram.sv new file mode 100644 index 0000000..e6f5b29 --- /dev/null +++ b/src/rvx0_simple_ram.sv @@ -0,0 +1,30 @@ +module rvx0_simple_ram ( + rvx0_apb.slave apb_slave +); + reg [31:0] words [0:1023]; + + integer i; + + always @(posedge apb_slave.pclk) begin + if (apb_slave.prstn) begin + if (apb_slave.penable) begin + if (apb_slave.pwrite) begin + words[apb_slave.paddr[11:2]] <= apb_slave.pwdata; + $display("RAM write [%x] <= %x", apb_slave.paddr, apb_slave.pwdata); + end else begin + apb_slave.prdata <= words[apb_slave.paddr[11:2]]; + $display("RAM read %x <= [%x]", words[apb_slave.paddr[11:2]], apb_slave.paddr); + end + + apb_slave.pready <= 1; + end else begin + apb_slave.pready <= 0; + end + end else begin + // for (i = 0; i < 1024; ++i) + // words[i] <= 0; + + words[0] <= 'h11223344; + end + end +endmodule diff --git a/src/rvx0_simple_rom.sv b/src/rvx0_simple_rom.sv new file mode 100644 index 0000000..eb19a2e --- /dev/null +++ b/src/rvx0_simple_rom.sv @@ -0,0 +1,15 @@ +module rvx0_simple_rom ( + rvx0_apb.slave apb_slave +); + // 1 page + reg [31:0] words [0:32768 - 1]; + + always_comb begin + apb_slave.pready = apb_slave.penable; + apb_slave.prdata = words[apb_slave.paddr[16:2]]; + end + + initial begin + $readmemh("obj_dir/apb0_memory.hex", words); + end +endmodule diff --git a/src/rvx0_soc_top.sv b/src/rvx0_soc_top.sv new file mode 100644 index 0000000..e5c14b3 --- /dev/null +++ b/src/rvx0_soc_top.sv @@ -0,0 +1,67 @@ +`include "rvx0_defs.svh" + +/* verilator lint_off PINMISSING */ + +module rvx0_soc_top (); + logic clk; + logic rst; + logic intr_ext; + + rvx0_apb apb (); + + rvx0_apb apb0 (); + rvx0_apb apb1 (); + rvx0_apb apb2 (); + rvx0_apb apb3 (); + + rvx0_core #( + .RESET_VECTOR ('h00001000) + ) core ( + .clk_i (clk), + .rst_i (rst), + .intr_ext_i (intr_ext), + .apb_master (apb) + ); + + rvx0_simple_rom rom ( + .apb_slave (apb0) + ); + + rvx0_simple_ram ram ( + .apb_slave (apb1) + ); + + rvx0_apb_debug debug ( + .apb_slave (apb2) + ); + + rvx0_busmux busmux ( + .apb_slave (apb), + + .apb0_master (apb0), + .apb1_master (apb1), + .apb2_master (apb2), + .apb3_master (apb3) + ); + + always #10 clk <= ~clk; + + assign apb.pclk = clk; + assign apb.prstn = ~rst; + + initial begin + #0 + intr_ext = 0; + rst = 1; + + #20 + rst = 0; + + // #50000 + + // // Dump state + // $display("Finish with pc=%x", core.pc_value); + // core.regfile.dump_state; + // $finish; + end +endmodule diff --git a/tool/makebin.py b/tool/makebin.py new file mode 100755 index 0000000..3c4b9b3 --- /dev/null +++ b/tool/makebin.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 + +import sys +import struct + +if __name__ == "__main__": + if len(sys.argv) != 3: + print(f"Usage: {sys.argv[0]} SOURCE.BIN OUTPUT.HEX", file=sys.stderr) + sys.exit(2) + + data = None + with open(sys.argv[1], "rb") as fp: + data = fp.read() + + with open(sys.argv[2], "w") as fp: + for i in range(0, len(data), 4): + word = data[i:i + 4] + word = struct.unpack("