Skip to content

Commit

Permalink
Add scripts/presyn/ example
Browse files Browse the repository at this point in the history
  • Loading branch information
cliffordwolf committed Feb 9, 2017
1 parent a2107ed commit 42b4397
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 0 deletions.
7 changes: 7 additions & 0 deletions scripts/presyn/.gitignore
@@ -0,0 +1,7 @@
firmware.bin
firmware.elf
firmware.hex
firmware.map
picorv32_presyn.v
testbench.vcd
testbench.vvp
22 changes: 22 additions & 0 deletions 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

5 changes: 5 additions & 0 deletions 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
47 changes: 47 additions & 0 deletions 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
43 changes: 43 additions & 0 deletions 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);
}
11 changes: 11 additions & 0 deletions scripts/presyn/firmware.lds
@@ -0,0 +1,11 @@
SECTIONS {
.memory : {
. = 0x000000;
*(.init);
*(.text);
*(*);
. = ALIGN(4);
end = .;
}
}

5 changes: 5 additions & 0 deletions 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
16 changes: 16 additions & 0 deletions 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
81 changes: 81 additions & 0 deletions 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

0 comments on commit 42b4397

Please sign in to comment.