Initial commit
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
/obj_dir
|
||||||
|
/*.log
|
||||||
|
/log
|
||||||
@@ -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 $@
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[target.riscv32i-unknown-none-elf]
|
||||||
|
rustflags = ["-Clink-arg=-Tlink.ld"]
|
||||||
|
[build]
|
||||||
|
target = "riscv32i-unknown-none-elf"
|
||||||
|
[unstable]
|
||||||
|
build-std = ["core"]
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
Generated
+7
@@ -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"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "firmware"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
@@ -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*)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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);
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
Executable
+21
@@ -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("<I", word)[0]
|
||||||
|
fp.write(f"{word:x}\n")
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user