diff --git a/scripts/presyn/.gitignore b/scripts/presyn/.gitignore new file mode 100644 index 0000000..4281b17 --- /dev/null +++ b/scripts/presyn/.gitignore @@ -0,0 +1,7 @@ +firmware.bin +firmware.elf +firmware.hex +firmware.map +picorv32_presyn.v +testbench.vcd +testbench.vvp diff --git a/scripts/presyn/Makefile b/scripts/presyn/Makefile new file mode 100644 index 0000000..d1c367e --- /dev/null +++ b/scripts/presyn/Makefile @@ -0,0 +1,22 @@ + +TOOLCHAIN_PREFIX = /opt/riscv32ic/bin/riscv32-unknown-elf- + +run: testbench.vvp firmware.hex + vvp -N testbench.vvp + +firmware.hex: firmware.S firmware.c firmware.lds + $(TOOLCHAIN_PREFIX)gcc -Os -ffreestanding -nostdlib -o firmware.elf firmware.S firmware.c \ + --std=gnu99 -Wl,-Bstatic,-T,firmware.lds,-Map,firmware.map,--strip-debug -lgcc + $(TOOLCHAIN_PREFIX)objcopy -O binary firmware.elf firmware.bin + python3 ../../firmware/makehex.py firmware.bin 4096 > firmware.hex + +picorv32_presyn.v: picorv32_presyn.ys picorv32_regs.txt ../../picorv32.v + yosys -v0 picorv32_presyn.ys + +testbench.vvp: testbench.v picorv32_presyn.v + iverilog -o testbench.vvp testbench.v picorv32_presyn.v + +clean: + rm -f firmware.bin firmware.elf firmware.hex firmware.map + rm -f picorv32_presyn.v testbench.vvp testbench.vcd + diff --git a/scripts/presyn/README b/scripts/presyn/README new file mode 100644 index 0000000..14aea33 --- /dev/null +++ b/scripts/presyn/README @@ -0,0 +1,5 @@ +A simple example for how to use Yosys to "pre-synthesize" PicoRV32 in +a way that can utilize an external memory module for the register file. + +See also: +https://github.com/cliffordwolf/picorv32/issues/30 diff --git a/scripts/presyn/firmware.S b/scripts/presyn/firmware.S new file mode 100644 index 0000000..ec5caaa --- /dev/null +++ b/scripts/presyn/firmware.S @@ -0,0 +1,47 @@ +.section .init +.global main + +entry: + +/* zero-initialize all registers */ +addi x1, zero, 0 +addi x2, zero, 0 +addi x3, zero, 0 +addi x4, zero, 0 +addi x5, zero, 0 +addi x6, zero, 0 +addi x7, zero, 0 +addi x8, zero, 0 +addi x9, zero, 0 +addi x10, zero, 0 +addi x11, zero, 0 +addi x12, zero, 0 +addi x13, zero, 0 +addi x14, zero, 0 +addi x15, zero, 0 +addi x16, zero, 0 +addi x17, zero, 0 +addi x18, zero, 0 +addi x19, zero, 0 +addi x20, zero, 0 +addi x21, zero, 0 +addi x22, zero, 0 +addi x23, zero, 0 +addi x24, zero, 0 +addi x25, zero, 0 +addi x26, zero, 0 +addi x27, zero, 0 +addi x28, zero, 0 +addi x29, zero, 0 +addi x30, zero, 0 +addi x31, zero, 0 + +/* set stack pointer */ +lui sp, %hi(16*1024) +addi sp, sp, %lo(16*1024) + +/* call main */ +jal ra, main + +/* break */ +ebreak diff --git a/scripts/presyn/firmware.c b/scripts/presyn/firmware.c new file mode 100644 index 0000000..6c62169 --- /dev/null +++ b/scripts/presyn/firmware.c @@ -0,0 +1,43 @@ +void putc(char c) +{ + *(volatile char*)0x10000000 = c; +} + +void puts(const char *s) +{ + while (*s) putc(*s++); +} + +void *memcpy(void *dest, const void *src, int n) +{ + while (n) { + n--; + ((char*)dest)[n] = ((char*)src)[n]; + } + return dest; +} + +void main() +{ + char message[] = "$Uryyb+Jbeyq!+Vs+lbh+pna+ernq+guvf+zrffntr+gura$gur+CvpbEI32+PCH" + "+frrzf+gb+or+jbexvat+whfg+svar.$$++++++++++++++++GRFG+CNFFRQ!$$"; + for (int i = 0; message[i]; i++) + switch (message[i]) + { + case 'a' ... 'm': + case 'A' ... 'M': + message[i] += 13; + break; + case 'n' ... 'z': + case 'N' ... 'Z': + message[i] -= 13; + break; + case '$': + message[i] = '\n'; + break; + case '+': + message[i] = ' '; + break; + } + puts(message); +} diff --git a/scripts/presyn/firmware.lds b/scripts/presyn/firmware.lds new file mode 100644 index 0000000..970000a --- /dev/null +++ b/scripts/presyn/firmware.lds @@ -0,0 +1,11 @@ +SECTIONS { + .memory : { + . = 0x000000; + *(.init); + *(.text); + *(*); + . = ALIGN(4); + end = .; + } +} + diff --git a/scripts/presyn/picorv32_presyn.ys b/scripts/presyn/picorv32_presyn.ys new file mode 100644 index 0000000..5855a21 --- /dev/null +++ b/scripts/presyn/picorv32_presyn.ys @@ -0,0 +1,5 @@ +read_verilog ../../picorv32.v +chparam -set COMPRESSED_ISA 1 picorv32 +prep -top picorv32 +memory_bram -rules picorv32_regs.txt +write_verilog -noattr picorv32_presyn.v diff --git a/scripts/presyn/picorv32_regs.txt b/scripts/presyn/picorv32_regs.txt new file mode 100644 index 0000000..1cfbbeb --- /dev/null +++ b/scripts/presyn/picorv32_regs.txt @@ -0,0 +1,16 @@ +bram picorv32_regs + init 0 + abits 5 + dbits 32 + groups 2 + ports 2 1 + wrmode 0 1 + enable 0 1 + transp 0 0 + clocks 1 1 + clkpol 1 1 +endbram + +match picorv32_regs + make_transp +endmatch diff --git a/scripts/presyn/testbench.v b/scripts/presyn/testbench.v new file mode 100644 index 0000000..59ff66b --- /dev/null +++ b/scripts/presyn/testbench.v @@ -0,0 +1,81 @@ +module testbench; + reg clk = 1; + always #5 clk = ~clk; + + reg resetn = 0; + always @(posedge clk) resetn <= 1; + + wire trap; + wire mem_valid; + wire mem_instr; + reg mem_ready; + wire [31:0] mem_addr; + wire [31:0] mem_wdata; + wire [3:0] mem_wstrb; + reg [31:0] mem_rdata; + + picorv32 UUT ( + .clk (clk ), + .resetn (resetn ), + .trap (trap ), + .mem_valid(mem_valid), + .mem_instr(mem_instr), + .mem_ready(mem_ready), + .mem_addr (mem_addr ), + .mem_wdata(mem_wdata), + .mem_wstrb(mem_wstrb), + .mem_rdata(mem_rdata) + ); + + // 4096 32bit words = 16kB memory + localparam MEM_SIZE = 4096; + + reg [31:0] memory [0:MEM_SIZE-1]; + initial $readmemh("firmware.hex", memory); + + always @(posedge clk) begin + mem_ready <= 0; + mem_rdata <= 'bx; + + if (resetn && mem_valid && !mem_ready) begin + mem_ready <= 1; + if (mem_wstrb) begin + if (mem_addr == 32'h1000_0000) begin + $write("%c", mem_wdata[7:0]); + $fflush; + end else begin + 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 + end else begin + mem_rdata <= memory[mem_addr >> 2]; + end + end + + if (resetn && trap) begin + $display("TRAP."); + $finish; + end + end + + initial begin + $dumpfile("testbench.vcd"); + $dumpvars(0, testbench); + end +endmodule + +module picorv32_regs ( + input [4:0] A1ADDR, A2ADDR, B1ADDR, + output reg [31:0] A1DATA, A2DATA, + input [31:0] B1DATA, + input B1EN, CLK1 +); + reg [31:0] memory [0:31]; + always @(posedge CLK1) begin + A1DATA <= memory[A1ADDR]; + A2DATA <= memory[A2ADDR]; + if (B1EN) memory[B1ADDR] <= B1DATA; + end +endmodule