From ad08edd2e54494e4894c4534cf5f125ac61ba46e Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 1 Oct 2017 15:45:46 +0200 Subject: [PATCH] Add PICORV32_REGS mechanism for ASIC sram instantiation --- picorv32.v | 68 +++++++++++++++++++++++++++++++++++++++++++++- picosoc/.gitignore | 1 + picosoc/Makefile | 7 ++++- picosoc/picosoc.v | 67 +++++++++++++++++++++++++++++++++++++-------- 4 files changed, 130 insertions(+), 13 deletions(-) diff --git a/picorv32.v b/picorv32.v index fbf6bbb..f78ec9b 100644 --- a/picorv32.v +++ b/picorv32.v @@ -42,6 +42,14 @@ `define assert(assert_expr) empty_statement `endif +// uncomment this for register file in extra module +// `define PICORV32_REGS picorv32_regs + +// this macro can be used to check if the verilog files in your +// design are read in the correct order. +`define PICORV32_V + + /*************************************************************** * picorv32 ***************************************************************/ @@ -149,7 +157,6 @@ module picorv32 #( reg [63:0] count_cycle, count_instr; reg [31:0] reg_pc, reg_next_pc, reg_op1, reg_op2, reg_out; - reg [31:0] cpuregs [0:regfile_size-1]; reg [4:0] reg_sh; reg [31:0] next_insn_opcode; @@ -175,6 +182,9 @@ module picorv32 #( reg [31:0] irq_pending; reg [31:0] timer; +`ifndef PICORV32_REGS + reg [31:0] cpuregs [0:regfile_size-1]; + integer i; initial begin if (REGS_INIT_ZERO) begin @@ -182,6 +192,7 @@ module picorv32 #( cpuregs[i] = 0; end end +`endif task empty_statement; // This task is used by the `assert directive in non-formal mode to @@ -1300,6 +1311,7 @@ module picorv32 #( end end +`ifndef PICORV32_REGS always @(posedge clk) begin if (resetn && cpuregs_write && latched_rd) cpuregs[latched_rd] <= cpuregs_wrdata; @@ -1325,6 +1337,37 @@ module picorv32 #( cpuregs_rs2 = cpuregs_rs1; end end +`else + wire[31:0] cpuregs_rdata1; + wire[31:0] cpuregs_rdata2; + + wire [5:0] cpuregs_waddr = latched_rd; + wire [5:0] cpuregs_raddr1 = ENABLE_REGS_DUALPORT ? decoded_rs1 : decoded_rs; + wire [5:0] cpuregs_raddr2 = ENABLE_REGS_DUALPORT ? decoded_rs2 : 0; + + `PICORV32_REGS cpuregs ( + .clk(clk), + .wen(resetn && cpuregs_write && latched_rd), + .waddr(cpuregs_waddr), + .raddr1(cpuregs_raddr1), + .raddr2(cpuregs_raddr2), + .wdata(cpuregs_wrdata), + .rdata1(cpuregs_rdata1), + .rdata2(cpuregs_rdata2) + ); + + always @* begin + decoded_rs = 'bx; + if (ENABLE_REGS_DUALPORT) begin + cpuregs_rs1 = decoded_rs1 ? cpuregs_rdata1 : 0; + cpuregs_rs2 = decoded_rs2 ? cpuregs_rdata2 : 0; + end else begin + decoded_rs = (cpu_state == cpu_state_ld_rs2) ? decoded_rs2 : decoded_rs1; + cpuregs_rs1 = decoded_rs ? cpuregs_rdata1 : 0; + cpuregs_rs2 = cpuregs_rs1; + end + end +`endif assign launch_next_insn = cpu_state == cpu_state_fetch && decoder_trigger && (!ENABLE_IRQ || irq_delay || irq_active || !(irq_pending & ~irq_mask)); @@ -2051,6 +2094,29 @@ module picorv32 #( `endif endmodule +// This is a simple example implementation of PICORV32_REGS. +// Use the PICORV32_REGS mechanism if you want to use custom +// memory resources to implement the processor register file. +// Note that your implementation must match the requirements of +// the PicoRV32 configuration. (e.g. QREGS, etc) +module picorv32_regs ( + input clk, wen, + input [5:0] waddr, + input [5:0] raddr1, + input [5:0] raddr2, + input [31:0] wdata, + output [31:0] rdata1, + output [31:0] rdata2 +); + reg [31:0] regs [0:30]; + + always @(posedge clk) + if (wen) regs[~waddr[4:0]] <= wdata; + + assign rdata1 = regs[~raddr1[4:0]]; + assign rdata2 = regs[~raddr2[4:0]]; +endmodule + /*************************************************************** * picorv32_pcpi_mul diff --git a/picosoc/.gitignore b/picosoc/.gitignore index c09322d..4a2e42e 100644 --- a/picosoc/.gitignore +++ b/picosoc/.gitignore @@ -12,3 +12,4 @@ /hx8kdemo_syn_tb.vvp /hx8kdemo_tb.vvp /testbench.vcd +/cmos.log diff --git a/picosoc/Makefile b/picosoc/Makefile index 835cc05..39e3982 100644 --- a/picosoc/Makefile +++ b/picosoc/Makefile @@ -52,11 +52,16 @@ spiflash_tb: spiflash_tb.vvp firmware.hex spiflash_tb.vvp: spiflash.v spiflash_tb.v iverilog -s testbench -o $@ $^ +# ---- ASIC Synthesis Tests ---- + +cmos.log: spimemio.v simpleuart.v picosoc.v ../picorv32.v + yosys -l cmos.log -p 'synth -top picosoc; abc -g cmos2; opt -fast; stat' $^ + # ---- Clean ---- clean: rm -f testbench.vvp testbench.vcd spiflash_tb.vvp spiflash_tb.vcd - rm -f firmware.elf firmware.hex firmware.bin + rm -f firmware.elf firmware.hex firmware.bin cmos.log rm -f hx8kdemo.blif hx8kdemo.log hx8kdemo.asc hx8kdemo.rpt hx8kdemo.bin rm -f hx8kdemo_syn.v hx8kdemo_syn_tb.vvp hx8kdemo_tb.vvp diff --git a/picosoc/picosoc.v b/picosoc/picosoc.v index 0402749..0f82df5 100644 --- a/picosoc/picosoc.v +++ b/picosoc/picosoc.v @@ -17,6 +17,12 @@ * */ +`ifdef PICORV32_V +`error "picosoc.v must be read before picorv32.v!" +`endif + +`define PICORV32_REGS picosoc_regs + module picosoc ( input clk, input resetn, @@ -82,7 +88,7 @@ module picosoc ( wire [31:0] spimem_rdata; reg ram_ready; - reg [31:0] ram_rdata; + wire [31:0] ram_rdata; assign iomem_valid = mem_valid && (mem_addr[31:24] > 8'h 01); assign iomem_wstrb = mem_wstrb; @@ -178,17 +184,56 @@ module picosoc ( .reg_dat_wait(simpleuart_reg_dat_wait) ); - reg [31:0] memory [0:MEM_WORDS-1]; + always @(posedge clk) + ram_ready <= mem_valid && !mem_ready && mem_addr < 4*MEM_WORDS; + + picosoc_mem #(.WORDS(MEM_WORDS)) memory ( + .clk(clk), + .wen((mem_valid && !mem_ready && mem_addr < 4*MEM_WORDS) ? mem_wstrb : 4'b0), + .addr(mem_addr[23:2]), + .wdata(mem_wdata), + .rdata(ram_rdata) + ); +endmodule + +// Implementation note: +// Replace the following two modules with wrappers for your SRAM cells. + +module picosoc_regs ( + input clk, wen, + input [5:0] waddr, + input [5:0] raddr1, + input [5:0] raddr2, + input [31:0] wdata, + output [31:0] rdata1, + output [31:0] rdata2 +); + reg [31:0] regs [0:31]; + + always @(posedge clk) + if (wen) regs[waddr[4:0]] <= wdata; + + assign rdata1 = regs[raddr1[4:0]]; + assign rdata2 = regs[raddr2[4:0]]; +endmodule + +module picosoc_mem #( + parameter integer WORDS = 256 +) ( + input clk, + input [3:0] wen, + input [21:0] addr, + input [31:0] wdata, + output reg [31:0] rdata +); + reg [31:0] mem [0:WORDS-1]; always @(posedge clk) begin - ram_ready <= 0; - if (mem_valid && !mem_ready && mem_addr < 4*MEM_WORDS) begin - ram_ready <= 1; - ram_rdata <= memory[mem_addr >> 2]; - if (mem_wstrb[0]) memory[mem_addr >> 2][ 7: 0] <= mem_wdata[ 7: 0]; - if (mem_wstrb[1]) memory[mem_addr >> 2][15: 8] <= mem_wdata[15: 8]; - if (mem_wstrb[2]) memory[mem_addr >> 2][23:16] <= mem_wdata[23:16]; - if (mem_wstrb[3]) memory[mem_addr >> 2][31:24] <= mem_wdata[31:24]; - end + rdata <= mem[addr]; + if (wen[0]) mem[addr][ 7: 0] <= wdata[ 7: 0]; + if (wen[1]) mem[addr][15: 8] <= wdata[15: 8]; + if (wen[2]) mem[addr][23:16] <= wdata[23:16]; + if (wen[3]) mem[addr][31:24] <= wdata[31:24]; end endmodule +