From 098157d5bb4687e0131ee117b75845ed19a4b6bc Mon Sep 17 00:00:00 2001 From: Yann Herklotz Date: Thu, 24 Nov 2022 18:52:37 +0000 Subject: Add initial files for icestorm --- Makefile | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.org | 16 +++++++++ example.pcf | 9 ++++++ example.v | 80 +++++++++++++++++++++++++++++++++++++++++++++ example_tb.v | 30 +++++++++++++++++ firmware.S | 12 +++++++ firmware.c | 58 +++++++++++++++++++++++++++++++++ firmware.lds | 11 +++++++ 8 files changed, 320 insertions(+) create mode 100644 Makefile create mode 100644 example.pcf create mode 100644 example.v create mode 100644 example_tb.v create mode 100644 firmware.S create mode 100644 firmware.c create mode 100644 firmware.lds diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7672b41 --- /dev/null +++ b/Makefile @@ -0,0 +1,104 @@ +TOOLCHAIN_PREFIX = riscv32-unknown-elf- + +ICE40_SIM_CELLS=$(shell yosys-config --datdir/ice40/cells_sim.v) + +# set to 4 for simulation +FIRMWARE_COUNTER_BITS=18 + +all: example.bin + +## ------------------- +## firmware generation + +firmware.elf: firmware.S firmware.c firmware.lds + $(TOOLCHAIN_PREFIX)gcc \ + -DSHIFT_COUNTER_BITS=$(FIRMWARE_COUNTER_BITS) \ + -march=rv32i -Os -ffreestanding -nostdlib \ + -o $@ firmware.S firmware.c \ + --std=gnu99 -Wl,-Bstatic,-T,firmware.lds,-Map,firmware.map,--strip-debug + chmod -x $@ + +firmware.bin: firmware.elf + $(TOOLCHAIN_PREFIX)objcopy -O binary $< $@ + chmod -x $@ + +firmware.hex: firmware.bin + python3 ../../firmware/makehex.py $< 128 > $@ + +## ------------------------------ +## main flow: synth/p&r/bitstream + +synth.json: example.v ../../picorv32.v firmware.hex + yosys -v3 -l synth.log -p 'synth_ice40 -top top -json $@; write_verilog -attr2comment synth.v' $(filter %.v, $^) + +example.asc: synth.json example.pcf + nextpnr-ice40 --hx8k --package ct256 --json $< --pcf example.pcf --asc $@ + +example.bin: example.asc + icepack $< $@ + +## ----------------- +## icarus simulation + +example_tb.vvp: example.v example_tb.v ../../picorv32.v firmware.hex + iverilog -o $@ -s testbench $(filter %.v, $^) + chmod -x $@ + +example_sim: example_tb.vvp + vvp -N $< + +example_sim_vcd: example_tb.vvp + vvp -N $< +vcd + +## --------------------- +## post-synth simulation + +synth_tb.vvp: example_tb.v synth.json + iverilog -o $@ -s testbench synth.v example_tb.v $(ICE40_SIM_CELLS) + chmod -x $@ + +synth_sim: synth_tb.vvp + vvp -N $< + +synth_sim_vcd: synth_tb.vvp + vvp -N $< +vcd + +## --------------------- +## post-route simulation + +route.v: example.asc example.pcf + icebox_vlog -L -n top -sp example.pcf $< > $@ + +route_tb.vvp: route.v example_tb.v + iverilog -o $@ -s testbench $^ $(ICE40_SIM_CELLS) + chmod -x $@ + +route_sim: route_tb.vvp + vvp -N $< + +route_sim_vcd: route_tb.vvp + vvp -N $< +vcd + +## --------------------- +## miscellaneous targets + +prog_sram: example.bin + iceprog -S $< + +timing: example.asc example.pcf + icetime -c 62 -tmd hx8k -P ct256 -p example.pcf -t $< + +view: example.vcd + gtkwave $< example.gtkw + +## ------ +## el fin + +clean: + rm -f firmware.elf firmware.map firmware.bin firmware.hex + rm -f synth.log synth.v synth.json route.v example.asc example.bin + rm -f example_tb.vvp synth_tb.vvp route_tb.vvp example.vcd + +.PHONY: all prog_sram view clean +.PHONY: example_sim synth_sim route_sim timing +.PHONY: example_sim_vcd synth_sim_vcd route_sim_vcd diff --git a/README.org b/README.org index cb96c43..9c549b7 100644 --- a/README.org +++ b/README.org @@ -1,3 +1,19 @@ #+title: ButterStick CPU #+author: Yann Herklotz +To build the example LED-blinking firmware for an HX8K Breakout Board and get +a timing report (checked against the default 12MHz oscillator): + +#+begin_src shell +$ make clean example.bin timing +#+end_src + +To run all the simulation tests: + +#+begin_src shell +$ make clean example_sim synth_sim route_sim FIRMWARE_COUNTER_BITS=4 +#+end_src + +(You must run the `clean` target to rebuild the firmware with the updated +`FIRMWARE_COUNTER_BITS` parameter; the firmware source must be recompiled for +simulation vs hardware, but this is not tracked as a Makefile dependency.) diff --git a/example.pcf b/example.pcf new file mode 100644 index 0000000..a5c7398 --- /dev/null +++ b/example.pcf @@ -0,0 +1,9 @@ +set_io clk J3 +set_io LED0 B5 +set_io LED1 B4 +set_io LED2 A2 +set_io LED3 A1 +set_io LED4 C5 +set_io LED5 C4 +set_io LED6 B3 +set_io LED7 C3 diff --git a/example.v b/example.v new file mode 100644 index 0000000..e1c64b4 --- /dev/null +++ b/example.v @@ -0,0 +1,80 @@ +`timescale 1 ns / 1 ps + +module top ( + input clk, + output reg LED0, LED1, LED2, LED3, LED4, LED5, LED6, LED7 +); + // ------------------------------- + // Reset Generator + + reg [7:0] resetn_counter = 0; + wire resetn = &resetn_counter; + + always @(posedge clk) begin + if (!resetn) + resetn_counter <= resetn_counter + 1; + end + + + // ------------------------------- + // PicoRV32 Core + + wire mem_valid; + wire [31:0] mem_addr; + wire [31:0] mem_wdata; + wire [3:0] mem_wstrb; + + reg mem_ready; + reg [31:0] mem_rdata; + + picorv32 #( + .ENABLE_COUNTERS(0), + .LATCHED_MEM_RDATA(1), + .TWO_STAGE_SHIFT(0), + .TWO_CYCLE_ALU(1), + .CATCH_MISALIGN(0), + .CATCH_ILLINSN(0) + ) cpu ( + .clk (clk ), + .resetn (resetn ), + .mem_valid(mem_valid), + .mem_ready(mem_ready), + .mem_addr (mem_addr ), + .mem_wdata(mem_wdata), + .mem_wstrb(mem_wstrb), + .mem_rdata(mem_rdata) + ); + + + // ------------------------------- + // Memory/IO Interface + + // 128 32bit words = 512 bytes memory + localparam MEM_SIZE = 128; + reg [31:0] memory [0:MEM_SIZE-1]; + initial $readmemh("firmware.hex", memory); + + always @(posedge clk) begin + mem_ready <= 0; + if (resetn && mem_valid && !mem_ready) begin + (* parallel_case *) + case (1) + !mem_wstrb && (mem_addr >> 2) < MEM_SIZE: begin + mem_rdata <= memory[mem_addr >> 2]; + mem_ready <= 1; + end + |mem_wstrb && (mem_addr >> 2) < MEM_SIZE: 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]; + mem_ready <= 1; + end + |mem_wstrb && mem_addr == 32'h1000_0000: begin + {LED7, LED6, LED5, LED4, LED3, LED2, LED1, LED0} <= mem_wdata; + mem_ready <= 1; + end + endcase + end + end +endmodule diff --git a/example_tb.v b/example_tb.v new file mode 100644 index 0000000..f04f8f8 --- /dev/null +++ b/example_tb.v @@ -0,0 +1,30 @@ +`timescale 1 ns / 1 ps + +module testbench; + reg clk = 1; + always #5 clk = ~clk; + wire LED0, LED1, LED2, LED3, LED4, LED5, LED6, LED7; + + top uut ( + .clk(clk), + .LED0(LED0), + .LED1(LED1), + .LED2(LED2), + .LED3(LED3), + .LED4(LED4), + .LED5(LED5), + .LED6(LED6), + .LED7(LED7) + ); + + initial begin + if ($test$plusargs("vcd")) begin + $dumpfile("example.vcd"); + $dumpvars(0, testbench); + end + + $monitor(LED7, LED6, LED5, LED4, LED3, LED2, LED1, LED0); + repeat (10000) @(posedge clk); + $finish; + end +endmodule diff --git a/firmware.S b/firmware.S new file mode 100644 index 0000000..d19783d --- /dev/null +++ b/firmware.S @@ -0,0 +1,12 @@ +.section .init +.global main + +/* set stack pointer */ +lui sp, %hi(512) +addi sp, sp, %lo(512) + +/* call main */ +jal ra, main + +/* break */ +ebreak diff --git a/firmware.c b/firmware.c new file mode 100644 index 0000000..80a4661 --- /dev/null +++ b/firmware.c @@ -0,0 +1,58 @@ +#include + +#ifndef SHIFT_COUNTER_BITS +#error SHIFT_COUNTER_BITS must be defined as 4 (for simulation) or 18 (for hardware bitstreams)! +#endif + +void output(uint8_t c) +{ + *(volatile char*)0x10000000 = c; +} + +uint8_t gray_encode_simple(uint8_t c) +{ + return c ^ (c >> 1); +} + +uint8_t gray_encode_bitwise(uint8_t c) +{ + unsigned int in_buf = c, out_buf = 0, bit = 1; + for (int i = 0; i < 8; i++) { + if ((in_buf & 1) ^ ((in_buf >> 1) & 1)) + out_buf |= bit; + in_buf = in_buf >> 1; + bit = bit << 1; + } + return out_buf; +} + +uint8_t gray_decode(uint8_t c) +{ + uint8_t t = c >> 1; + while (t) { + c = c ^ t; + t = t >> 1; + } + return c; +} + +void gray(uint8_t c) +{ + uint8_t gray_simple = gray_encode_simple(c); + uint8_t gray_bitwise = gray_encode_bitwise(c); + uint8_t gray_decoded = gray_decode(gray_simple); + + if (gray_simple != gray_bitwise || gray_decoded != c) + while (1) asm volatile ("ebreak"); + + output(gray_simple); +} + +void main() +{ + for (uint32_t counter = (2+4+32+64) << SHIFT_COUNTER_BITS;; counter++) { + asm volatile ("" : : "r"(counter)); + if ((counter & ~(~0 << SHIFT_COUNTER_BITS)) == 0) + gray(counter >> SHIFT_COUNTER_BITS); + } +} diff --git a/firmware.lds b/firmware.lds new file mode 100644 index 0000000..970000a --- /dev/null +++ b/firmware.lds @@ -0,0 +1,11 @@ +SECTIONS { + .memory : { + . = 0x000000; + *(.init); + *(.text); + *(*); + . = ALIGN(4); + end = .; + } +} + -- cgit