diff --git a/wb-tut4/Makefile b/wb-tut4/Makefile new file mode 100644 index 0000000..b598dc5 --- /dev/null +++ b/wb-tut4/Makefile @@ -0,0 +1,68 @@ +SIM_TARGET = build/top +BIN_TARGET = build/top.bin +PCF = constraints/iceFUN.pcf +TIMING = constraints/timing.py +YOSYS = yosys +PNR = nextpnr-ice40 +IPACK = icepack +BURN = iceFUNprog +SBY = sby + +VERILATOR=verilator +VERILATOR_ROOT ?= $(shell bash -c 'verilator -V|grep VERILATOR_ROOT | head -1 | sed -e "s/^.*=\s*//"') +VINC := $(VERILATOR_ROOT)/include + +RTL_SRC := $(wildcard rtl/*.v) +SIM_SRC := $(wildcard sim/*.cc) +FV_SRC := sim/top.sby + +BUILD_DIR := ./build + +define colorecho + @tput setaf 6 + @echo $1 + @tput sgr0 +endef + +.PHONY: all burn fv clean +all: $(SIM_TARGET) $(BIN_TARGET) + +$(BUILD_DIR)/Vtop.cc: $(RTL_SRC) + $(call colorecho, "Running verilator") + mkdir -p $(BUILD_DIR) + $(VERILATOR) --trace -Wall -cc $^ --top-module top\ + --Mdir $(BUILD_DIR) --timescale-override 10ns/1ns + +$(BUILD_DIR)/Vtop__ALL.a: $(BUILD_DIR)/Vtop.cc + make --no-print-directory -C $(BUILD_DIR) -f Vtop.mk + +# std=c++11 flag is needed as of verilator v4.100 +$(SIM_TARGET): $(SIM_SRC) $(BUILD_DIR)/Vtop__ALL.a + $(call colorecho, "Compiling simulation executable") + g++ -I$(VINC) -I$(BUILD_DIR) -std=c++14 $(VINC)/verilated.cpp\ + $(VINC)/verilated_vcd_c.cpp $^ -o $@ + echo "Run simulation with ./$(SIM_TARGET)" + +$(BUILD_DIR)/top.json: $(RTL_SRC) + $(call colorecho, "Synthesizing ...") + mkdir -p $(BUILD_DIR) + $(YOSYS) -p "synth_ice40 -top top -json build/top.json" -q $^ + +$(BIN_TARGET): $(BUILD_DIR)/top.json $(PCF) $(TIMING) + $(call colorecho, "Routing and building binary stream ...") + $(PNR) -r --hx8k --json $< --package cb132 \ + --asc $(BUILD_DIR)/top.asc --opt-timing --pcf $(PCF) \ + --pre-pack $(TIMING) -l $(BUILD_DIR)/pnr_report.txt -q + $(IPACK) $(BUILD_DIR)/top.asc $@ + $(call colorecho, "Done!") + +burn: $(BIN_TARGET) + $(BURN) $< + +fv: + $(SBY) -f $(FV_SRC) -d $(BUILD_DIR)/fv + +clean: + rm -rf $(BUILD_DIR) + +$V.SILENT: diff --git a/wb-tut4/constraints/iceFUN.pcf b/wb-tut4/constraints/iceFUN.pcf new file mode 100644 index 0000000..7ebdbe7 --- /dev/null +++ b/wb-tut4/constraints/iceFUN.pcf @@ -0,0 +1,14 @@ +# For iceFUN board + +set_io --warn-no-port i_clk P7 +set_io --warn-no-port i_request A5 + +set_io --warn-no-port o_led_row_0 A12 +set_io --warn-no-port o_led[0] C10 +set_io --warn-no-port o_led[1] A10 +set_io --warn-no-port o_led[2] D7 +set_io --warn-no-port o_led[3] D6 +set_io --warn-no-port o_led[4] A7 +set_io --warn-no-port o_led[5] C7 +# set_io --warn-no-port o_led[6] A4 +set_io --warn-no-port o_busy C4 diff --git a/wb-tut4/constraints/timing.py b/wb-tut4/constraints/timing.py new file mode 100644 index 0000000..f949a2c --- /dev/null +++ b/wb-tut4/constraints/timing.py @@ -0,0 +1 @@ +ctx.addClock("i_clk", 100) diff --git a/wb-tut4/rtl/clk_gen.v b/wb-tut4/rtl/clk_gen.v new file mode 100644 index 0000000..491320f --- /dev/null +++ b/wb-tut4/rtl/clk_gen.v @@ -0,0 +1,13 @@ +`default_nettype none +// dummy clock generator, should be replaced by a PLL clock gen eventually +module clk_gen( + input wire i_clk, + output wire o_clk +); + +assign o_clk = i_clk; + +endmodule +// Local Variables: +// verilog-library-directories:(".." "./rtl" ".") +// End: diff --git a/wb-tut4/rtl/top.v b/wb-tut4/rtl/top.v new file mode 100644 index 0000000..542666e --- /dev/null +++ b/wb-tut4/rtl/top.v @@ -0,0 +1,70 @@ +`default_nettype none + +module top(i_clk, + i_cyc, i_stb, i_we, i_addr, i_data, + o_stall, o_ack, o_data, + o_led, o_led_row_0); +input wire i_clk; +// +// Our wishbone bus interface +input wire i_cyc, i_stb, i_we; +input wire i_addr; +input wire [31:0] i_data; +// +output wire o_stall; +output reg o_ack; +output wire [31:0] o_data; +// +// The output LED +output wire o_led_row_0; +output reg [5:0] o_led; + +wire busy; +reg [3:0] state; + +initial state = 0; +always @(posedge i_clk) begin + if ((i_stb)&&(i_we)&&(!o_stall)) + state <= 4'h1; + else if (state >= 4'd11) + state <= 4'h0; + else if (state != 0) + state <= state + 1'b1; +end + +always @(posedge i_clk) begin + case(state) + 4'h1: o_led <= 6'b00_0001; + 4'h2: o_led <= 6'b00_0010; + 4'h3: o_led <= 6'b00_0100; + 4'h4: o_led <= 6'b00_1000; + 4'h5: o_led <= 6'b01_0000; + 4'h6: o_led <= 6'b10_0000; + 4'h7: o_led <= 6'b01_0000; + 4'h8: o_led <= 6'b00_1000; + 4'h9: o_led <= 6'b00_0100; + 4'ha: o_led <= 6'b00_0010; + 4'hb: o_led <= 6'b00_0001; + default: o_led <= 6'b00_0000; + endcase +end + +assign busy = (state != 0); + +initial o_ack = 1'b0; +always @(posedge i_clk) + o_ack <= (i_stb)&&(!o_stall); + +assign o_stall = (busy)&&(i_we); +assign o_data = { 28'h0, state }; +assign o_led_row_0 = 0; + +// Verilator lint_off UNUSED +wire [33:0] unused; +assign unused = { i_cyc, i_addr, i_data }; +// Verilator lint_on UNUSED +// +endmodule +// Local Variables: +// verilog-library-directories:(".." "./rtl" ".") +// End: diff --git a/wb-tut4/sim/top.cc b/wb-tut4/sim/top.cc new file mode 100644 index 0000000..28ad4d8 --- /dev/null +++ b/wb-tut4/sim/top.cc @@ -0,0 +1,118 @@ +#include +#include +#include "Vtop.h" +#include "verilated.h" +#include "verilated_vcd_c.h" + +int tickcount = 0; +Vtop *tb; +VerilatedVcdC *tfp; + +void tick(void) { + tickcount++; + + tb->eval(); + if (tfp) + tfp->dump(tickcount * 10 - 2); + tb->i_clk = 1; + tb->eval(); + if (tfp) + tfp->dump(tickcount * 10); + tb->i_clk = 0; + tb->eval(); + if (tfp) { + tfp->dump(tickcount * 10 + 5); + tfp->flush(); + } +} + +unsigned wb_read(unsigned a) { + tb->i_cyc = tb->i_stb = 1; + tb->i_we = 0; + tb->eval(); + tb->i_addr= a; + // Make the request + while(tb->o_stall) + tick(); + tick(); + tb->i_stb = 0; + // Wait for the ACK + while(!tb->o_ack) + tick(); + // Idle the bus, and read the response + tb->i_cyc = 0; + return tb->o_data; +} + +void wb_write(unsigned a, unsigned v) { + tb->i_cyc = tb->i_stb = 1; + tb->i_we = 1; + tb->eval(); + tb->i_addr= a; + tb->i_data= v; + // if busy, keep ticking + while(tb->o_stall) + tick(); + // Then, make the bus request + tick(); + // and pull stb down + tb->i_stb = 0; + // Wait for the acknowledgement + while(!tb->o_ack) + tick(); + // Idle the bus and return + tb->i_cyc = tb->i_stb = 0; +} + +int main(int argc, char **argv) { + int last_led, last_state = 0, state = 0; + + // Call commandArgs first! + Verilated::commandArgs(argc, argv); + + // Instantiate our design + tb = new Vtop; + + // Generate a trace + Verilated::traceEverOn(true); + tfp = new VerilatedVcdC; + tb->trace(tfp, 99); + tfp->open("build/waveform.vcd"); + + last_led = tb->o_led; + + // Read from the current state + printf("Initial state is: 0x%02x\n", + wb_read(0)); + + for(int cycle=0; cycle<2; cycle++) { + // Wait five clocks + for(int i=0; i<5; i++) + tick(); + + // Start the LEDs cycling + wb_write(0,0); + tick(); + + while((state = wb_read(0))!=0) { + if ((state != last_state) + ||(tb->o_led != last_led)) { + printf("%6d: State #%2d ", + tickcount, state); + for(int j=0; j<6; j++) { + if(tb->o_led & (1<o_led; + } + } + + tfp->close(); + delete tfp; + delete tb; +} diff --git a/wb-tut4/sim/top.sby b/wb-tut4/sim/top.sby new file mode 100644 index 0000000..3d0b7f6 --- /dev/null +++ b/wb-tut4/sim/top.sby @@ -0,0 +1,13 @@ +[options] +mode prove + +[engines] +smtbmc + +[script] +read -formal *.v +prep -top top + +[files] +rtl/top.v +rtl/clk_gen.v