LLHICJMHRWCZVTXZOJ3MO3LX6RCYUN6HTRMMJMGVOEBUXW6YMDWQC // SPDX-License-Identifier: CERN-OHL-S-2.0// A simple dual-read, single-write register file`default_nettype none`timescale 1ps/1psmodule regfile(input bit clk, rst,// Write portinput wire wen,input wire [5:0] waddr,input wire [31:0] wdata,// Read portsinput wire [5:0] raddrA,output wire [31:0] rdataA,input wire [5:0] raddrB,output wire [31:0] rdataB);// r0 is always 0, so we can not implement itreg [31:0] registers [0:30];always_ff @(posedge clk, rst)if (rst)for (integer i = 0; i < 32; i++) beginregisters[i] <= 0;endelse if (wen)registers[~waddr[4:0]] <= wdata;assign rdataA = registers[~raddrA[4:0]];assign rdataB = registers[~raddrB[4:0]];endmodule
// SPDX-License-Identifier: CERN-OHL-S-2.0// A basic SOC with the core, ram, and uart// Default 16KB ram`default_nettype none`timescale 1ps/1psmodule soc#(parameter integer MEM_WORDS = 4096)(input bit clk,input bit rst,);// TODO: impl uartassign uart_tx = 0 & uart_rx & rst;mem memory();mem_impl memory_impl(clk, memory.impl);// synthesis translate offlogic [1000:0] mem_file;initial beginif ($test$plusargs("trace") != 0) begin$display("[%0t] Tracing to logs/vlt_dump.vcd...\n", $time);$dumpfile("logs/vlt_dump.vcd");$dumpvars();endend// synthesis translate onendmoduleinput wire uart_rx,output wire uart_tx
// SPDX-License-Identifier: CERN-OHL-S-2.0// A maxmimally simple core`default_nettype none`timescale 1ps/1psmodule basic_rv32i(mem.core mem,`ifdef RISCV_FORMALoutput reg rvfi_valid,output reg [63:0] rvfi_order,output reg [31:0] rvfi_insn,output reg rvfi_trap,output reg rvfi_halt,output reg rvfi_intr,output reg [ 1:0] rvfi_mode,output reg [ 1:0] rvfi_ixl,output reg [ 4:0] rvfi_rs1_addr,output reg [ 4:0] rvfi_rs2_addr,output reg [31:0] rvfi_rs1_rdata,output reg [31:0] rvfi_rs2_rdata,output reg [ 4:0] rvfi_rd_addr,output reg [31:0] rvfi_rd_wdata,output reg [31:0] rvfi_pc_rdata,output reg [31:0] rvfi_pc_wdata,output reg [31:0] rvfi_mem_addr,output reg [ 3:0] rvfi_mem_rmask,output reg [ 3:0] rvfi_mem_wmask,output reg [31:0] rvfi_mem_rdata,output reg [31:0] rvfi_mem_wdata,output reg [63:0] rvfi_csr_mcycle_rmask,output reg [63:0] rvfi_csr_mcycle_wmask,output reg [63:0] rvfi_csr_mcycle_rdata,output reg [63:0] rvfi_csr_mcycle_wdata,output reg [63:0] rvfi_csr_minstret_rmask,output reg [63:0] rvfi_csr_minstret_wmask,output reg [63:0] rvfi_csr_minstret_rdata,output reg [63:0] rvfi_csr_minstret_wdata,`endifinput bit clk, rst);endmodule
// SPDX-License-Identifier: CERN-OHL-S-2.0// A simple valid-ready memory interface that can handle a single memory transfer at a time`default_nettype none`timescale 1ps/1ps// The core initiates a transfer by asserting valid, which stays high until the// peer asserts ready. All core outputs are stable over the valid period.// If the transfer is an instruction fetch, the core asserts instr.interface mem;bit valid;bit ready;bit instr;enum bit[3:0] {READ = 'b0000,WRITE_BYTE0 = 'b0001,WRITE_BYTE1 = 'b0010,WRITE_BYTE2 = 'b0100,WRITE_BYTE3 = 'b1000,WRITE_HWORD0 = 'b0011,WRITE_HWORD1 = 'b1100,WRITE_WORD = 'b1111} mode;wire [31:0] addr;wire [31:0] rdata;wire [31:0] wdata;modport core (output valid,input ready,output instr,output mode,output addr,input rdata,output wdata);modport impl (input valid,output ready,input instr,input mode,input addr,output rdata,input wdata);endinterface/* verilator lint_off DECLFILENAME */module mem_impl#(parameter integer MEM_WORDS = 4096)(input bit clk,mem.impl mem);always_ff @(posedge clk) beginmem.ready <= '0;if (mem.valid) beginmem.rdata <= memory[mem.addr];if (wen[0]) memory[mem.addr][ 7: 0] <= mem.wdata[ 7: 0];if (wen[1]) memory[mem.addr][15: 8] <= mem.wdata[15: 8];if (wen[2]) memory[mem.addr][23:16] <= mem.wdata[23:16];if (wen[3]) memory[mem.addr][31:24] <= mem.wdata[31:24];endend// synthesis translate offlogic [200:0] mem_file;initial beginif ($value$plusargs("mem", mem_file)) begin$display("[%0t] Initializing memory\n", $time);$readmemh(mem_file, memory);endendphys_mem_addr: assert property(@(posedge clk) mem.addr < (4*MEM_WORDS));// synthesis translate onendmodulereg [31:0] memory [0:MEM_WORDS-1];reg [3:0] wen = mem.mode;
// SPDX-License-Identifier: CERN-OHL-S-2.0// A basic valid-ready ram, default 16KiB`default_nettype none`timescale 1ps/1psmodule uart(input logic clk_i,input logic rst_ni,input logic uart_i,output logic uart_o);// TODO: implementendmodule
// SPDX-License-Identifier: CERN-OHL-S-2.0`default_nettype none`timescale 1ps/1pspackage soc_pkg;parameter int unsigned MEM_WORDS = 4096;typedef struct packed {logic valid;logic [ 7:0] wen;logic [63:0] addr;logic [63:0] wdata;} mem_in_t;typedef struct packed {logic ready;logic [63:0] rdata;} mem_out_t;endpackage
// SPDX-License-Identifier: CERN-OHL-S-2.0// A basic SOC with the core, ram, and uart// Default 32KiB ram`default_nettype none`timescale 1ps/1psmodule soc(input logic clk_i,input logic rst_ni,input logic uart_i,output logic uart_o);uart uart_impl(.clk_i, .rst_ni, .uart_i, .uart_o);soc_pkg::mem_in_t mem_in;soc_pkg::mem_out_t mem_out;mem ram(.clk_i, .core_i(mem_in), .core_o(mem_out));`ifndef SYNTHESISinitial beginif ($test$plusargs("trace") != 0) begin$display("[%0t] Tracing to logs/vlt_dump.vcd...\n", $time);$dumpfile("logs/vlt_dump.vcd");$dumpvars();endend`endifendmodule
// SPDX-License-Identifier: CERN-OHL-S-2.0// A basic valid-ready ram, default 32KiB`default_nettype none`timescale 1ps/1ps// The core initiates a transfer by asserting valid, which stays high until the// peer asserts ready. All core outputs are stable over the valid period.module mem(input logic clk_i,input soc_pkg::mem_in_t core_i,output soc_pkg::mem_out_t core_o);logic [63:0] memory [0:soc_pkg::MEM_WORDS-1];always_ff @(posedge clk_i) begincore_o.ready <= '0;if (core_i.valid) beginMemAddrFitsIntoPhys: assert(core_i.addr < (8*soc_pkg::MEM_WORDS));core_o.rdata <= memory[core_i.addr];core_o.ready <= 1'b1;if (core_i.wen[0]) memory[core_i.addr][ 7: 0] <= core_i.wdata[ 7: 0];if (core_i.wen[1]) memory[core_i.addr][15: 8] <= core_i.wdata[15: 8];if (core_i.wen[2]) memory[core_i.addr][23:16] <= core_i.wdata[23:16];if (core_i.wen[3]) memory[core_i.addr][31:24] <= core_i.wdata[31:24];endend`ifndef SYNTHESISlogic [200:0] mem_file;initial beginif ($value$plusargs("mem", mem_file)) begin$display("[%0t] Initializing memory\n", $time);$readmemh(mem_file, memory);endend`endifendmodule
// SPDX-License-Identifier: CERN-OHL-S-2.0`default_nettype none`timescale 1ps/1pspackage core_pkg;// The core initiates a transfer by asserting valid, which stays high until the// peer asserts ready. All core outputs are stable over the valid period.typedef struct packed {logic valid;logic [ 3:0] wen;logic [31:0] addr;logic [31:0] wdata;} core_out_t;typedef struct packed {logic ready;logic [31:0] rdata;} core_in_t;endpackage
A toolchain will need to be compiled from source, as the default extensions for RISC-V toolchains are GC, and the `ilp32` ABI used is not compatible with the ABI they use.
A toolchain will need to be compiled from source, as the default extensions for RISC-V toolchains are GC, and the `lp64` ABI used is not compatible with the ABI they use.
VERILATOR_FLAGS += -j $(nproc)
VERILATOR_COMMON_FLAGS += -j $(JOBS)# Check assertionsVERILATOR_COMMON_FLAGS += --assert# Generate coverage analysisVERILATOR_COMMON_FLAGS += --coverage# Look in the rtl directoryVERILATOR_COMMON_FLAGS += -Irtl/soc -Irtl/core
VERILATOR_FLAGS += --output-split-cfuncs 50 --output-split-ctrace 50# Warn about lint issuesVERILATOR_FLAGS += -Wall# Check assertionsVERILATOR_FLAGS += --assert# Generate coverage analysisVERILATOR_FLAGS += --coverage
VERILATOR_GENERATION_FLAGS += --output-split-cfuncs 50 --output-split-ctrace 50
$(MAKE) -j -C obj_dir -f Vsoc.mk
$(MAKE) -j $(JOBS) -C obj_dir -f Vsoc.mksoc-lint-verilator:$(VERILATOR) $(VERILATOR_COMMON_FLAGS) --lint-only -Wall -Wpedantic $(SOC_RTLS)soc-lint-slang:$(SLANG) -j $(JOBS) -Irtl/soc -Irtl/core --allow-dup-initial-drivers $(SOC_RTLS)