diff --git a/fpga/serial/lattice/eb85/ice40_remotefpga_test/Makefile b/fpga/serial/lattice/eb85/ice40_remotefpga_test/Makefile new file mode 100644 index 0000000..04a0f2d --- /dev/null +++ b/fpga/serial/lattice/eb85/ice40_remotefpga_test/Makefile @@ -0,0 +1,123 @@ +# This file is part of the Universal Laboratory (uLab) +# +# © 2017 - 2019 Raptor Engineering, LLC +# All Rights Reserved +# +# Licensed under the terms of the AGPL v3 + +MAX_FPGA_ROUTE_PASSES = 100 + +SOURCE_FILES = main.v + +# Default seed +#ARACHNE_PNR_SEED = 1 + +# Selected seed from fastest placement search +# NOTE: Must be updated every time the Verilog source is modified, no matter how trivially! +# Does not need to be updated if firmware program (C) sources are modified +# 0 automatically uses the best placement result +ARACHNE_PNR_SEED = 0 +#ARACHNE_PNR_SEED = 1 + +YOSYS_ICE40_SIM_LIB = $(shell yosys-config --datdir/ice40/cells_sim.v) + +.PRECIOUS: guest_fpga_%.int + +guest_fpga_%.tmg: guest_fpga_%.int guest_fpga.pcf + echo "Total path delay: inf ns (0.0 MHz)" > $@ + -icetime -tmd hx8k -p guest_fpga.pcf -P ct256 $< > $@ 2>&1 + +guest_fpga_%.int: guest_fpga.blif guest_fpga.pcf + echo "" > $@ + -arachne-pnr -s $* -d 8k -P ct256 -m $(MAX_FPGA_ROUTE_PASSES) -p guest_fpga.pcf $< -o $@ + +guest_fpga.int: guest_fpga_1.tmg guest_fpga_2.tmg guest_fpga_3.tmg guest_fpga_4.tmg guest_fpga_5.tmg guest_fpga_6.tmg guest_fpga_7.tmg guest_fpga_8.tmg guest_fpga_9.tmg \ + guest_fpga_10.tmg guest_fpga_11.tmg guest_fpga_12.tmg guest_fpga_13.tmg guest_fpga_14.tmg guest_fpga_15.tmg guest_fpga_16.tmg guest_fpga_17.tmg guest_fpga_18.tmg guest_fpga_19.tmg \ + guest_fpga_20.tmg guest_fpga_21.tmg guest_fpga_22.tmg guest_fpga_23.tmg guest_fpga_24.tmg guest_fpga_25.tmg guest_fpga_26.tmg guest_fpga_27.tmg guest_fpga_28.tmg guest_fpga_29.tmg \ + guest_fpga_30.tmg guest_fpga_31.tmg guest_fpga_32.tmg guest_fpga_33.tmg guest_fpga_34.tmg guest_fpga_35.tmg guest_fpga_36.tmg guest_fpga_37.tmg guest_fpga_38.tmg guest_fpga_39.tmg \ + guest_fpga_40.tmg guest_fpga_41.tmg guest_fpga_42.tmg guest_fpga_43.tmg guest_fpga_44.tmg guest_fpga_45.tmg guest_fpga_46.tmg guest_fpga_47.tmg guest_fpga_48.tmg guest_fpga_49.tmg \ + guest_fpga_50.tmg guest_fpga_51.tmg guest_fpga_52.tmg guest_fpga_53.tmg guest_fpga_54.tmg guest_fpga_55.tmg guest_fpga_56.tmg guest_fpga_57.tmg guest_fpga_58.tmg guest_fpga_59.tmg \ + guest_fpga_60.tmg guest_fpga_61.tmg guest_fpga_62.tmg guest_fpga_63.tmg guest_fpga_64.tmg + BEST_TRIAL=0; \ + BEST_TRIAL_RESULT=0; \ + for trial in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64; do \ + CURRENT_TRIAL_RESULT=$$(cat guest_fpga_$${trial}.tmg | grep "Total path delay" | awk '{print $$6}' | sed 's/(//g'); \ + if [ "$$CURRENT_TRIAL_RESULT" != "" ]; then \ + echo "guest_fpga_$${trial}.tmg : $$CURRENT_TRIAL_RESULT"; \ + COMPARISON_RESULT=$$(echo "$$CURRENT_TRIAL_RESULT > $$BEST_TRIAL_RESULT" | bc -l); \ + if [ $$COMPARISON_RESULT -eq 1 ]; then \ + BEST_TRIAL=guest_fpga_$${trial}.tmg; \ + BEST_TRIAL_RESULT=$$CURRENT_TRIAL_RESULT; \ + fi; \ + fi; \ + done; \ + if [ "$$BEST_TRIAL_RESULT" -eq "0" ]; then \ + echo "Unable to determine fastest result. Selecting first run...."; \ + BEST_TRIAL=guest_fpga_1.tmg; \ + BEST_TRIAL_RESULT=0; \ + fi; \ + echo "Fastest result: $$BEST_TRIAL : $$BEST_TRIAL_RESULT"; \ + cp `echo $$BEST_TRIAL | sed 's/\.tmg/\.int/g'` guest_fpga.int; \ + cp $$BEST_TRIAL guest_fpga.tmg +ifneq ($(ARACHNE_PNR_SEED),0) + cp guest_fpga_$(ARACHNE_PNR_SEED).int guest_fpga.int + cp guest_fpga_$(ARACHNE_PNR_SEED).tmg guest_fpga.tmg +endif + cat guest_fpga.tmg + +guest_fpga.ex: guest_fpga.int + icebox_explain guest_fpga.int > guest_fpga.ex + +guest_fpga.blif: $(SOURCE_FILES) + yosys -l yosys.log -q -p "synth_ice40 -top guest_fpga_top -blif guest_fpga.blif" $(SOURCE_FILES) + +guest_fpga.bin: guest_fpga.int + icepack guest_fpga.int guest_fpga.bin + +blank.rom: + dd if=/dev/zero ibs=1k count=256 | tr "\000" "\377" > blank.rom + +guest_fpga.rom: blank.rom guest_fpga.bin + cp blank.rom guest_fpga.rom + dd if=guest_fpga.bin of=guest_fpga.rom conv=notrunc + +guest_fpga_test.vcd: $(SOURCE_FILES) testbench.v + rm -f guest_fpga_sim + rm -f guest_fpga.vcd + /usr/bin/iverilog -DSIMULATION -o guest_fpga_sim $(SOURCE_FILES) testbench.v + ./guest_fpga_sim + +simulate: guest_fpga_test.vcd + +simulate_view: guest_fpga_test.vcd + gtkwave guest_fpga_test.vcd + +all: guest_fpga.rom + +dump_toolchain_info: + -@echo "================================================================================" + -@echo "Base system:\t" + -@echo -n "Architecture:\t" + -@uname -m 2>/dev/null + -@echo -n "gcc:\t\t" + -@gcc -dumpversion 2>/dev/null + -@echo -n "clang:\t\t" + -@clang --version 2>/dev/null | head -n 1 + -@echo "\nFPGA toolchain:" + -@echo -n "Icarus verilog:\t" + -@iverilog -V 2>/dev/null | head -n 1 + -@echo -n "Yosys:\t\t" + -@yosys -V 2>/dev/null + -@echo -n "arachne-pnr:\t" + -@arachne-pnr -v 2>/dev/null + -@echo "================================================================================" + +test: guest_fpga.bin + iceprog -S guest_fpga.bin + +flash: guest_fpga.bin + iceprog guest_fpga.bin + +clean: + rm -f guest_fpga.blif guest_fpga.ex guest_fpga.int guest_fpga.tmg guest_fpga_*.int guest_fpga_*.tmg guest_fpga.bin yosys.log + diff --git a/fpga/serial/lattice/eb85/ice40_remotefpga_test/guest_fpga.pcf b/fpga/serial/lattice/eb85/ice40_remotefpga_test/guest_fpga.pcf new file mode 100644 index 0000000..00ee8d7 --- /dev/null +++ b/fpga/serial/lattice/eb85/ice40_remotefpga_test/guest_fpga.pcf @@ -0,0 +1,106 @@ +# This file is part of the Universal Laboratory (uLab) +# +# © 2017 - 2019 Raptor Engineering, LLC +# All Rights Reserved +# +# Licensed under the terms of the AGPL v3 + +# Main system clock +set_io clk J3 + +# Guest FPGA interface +set_io reset A16 + +set_io four_bit_output[3] C16 +set_io four_bit_output[2] D16 +set_io four_bit_output[1] E16 +set_io four_bit_output[0] F16 + +set_io four_bit_input[3] B16 +set_io four_bit_input[2] D14 +set_io four_bit_input[1] D15 +set_io four_bit_input[0] E14 + +set_io eight_bit_output[7] G16 +set_io eight_bit_output[6] H16 +set_io eight_bit_output[5] J15 +set_io eight_bit_output[4] G14 +set_io eight_bit_output[3] K14 +set_io eight_bit_output[2] K15 +set_io eight_bit_output[1] M16 +set_io eight_bit_output[0] N16 + +set_io eight_bit_input[7] F15 +set_io eight_bit_input[6] G15 +set_io eight_bit_input[5] H14 +set_io eight_bit_input[4] F14 +set_io eight_bit_input[3] J14 +set_io eight_bit_input[2] K16 +set_io eight_bit_input[1] L16 +set_io eight_bit_input[0] M15 + +set_io sixteen_bit_output[15] B1 +set_io sixteen_bit_output[14] C1 +set_io sixteen_bit_output[13] D1 +set_io sixteen_bit_output[12] E2 +set_io sixteen_bit_output[11] F2 +set_io sixteen_bit_output[10] G2 +set_io sixteen_bit_output[9] H2 +set_io sixteen_bit_output[8] J2 +set_io sixteen_bit_output[7] K3 +set_io sixteen_bit_output[6] L3 +set_io sixteen_bit_output[5] M2 +set_io sixteen_bit_output[4] N3 +set_io sixteen_bit_output[3] P1 +set_io sixteen_bit_output[2] B12 +set_io sixteen_bit_output[1] B13 +set_io sixteen_bit_output[0] A15 + +set_io sixteen_bit_input[15] B2 +set_io sixteen_bit_input[14] C2 +set_io sixteen_bit_input[13] D2 +set_io sixteen_bit_input[12] F1 +set_io sixteen_bit_input[11] G1 +set_io sixteen_bit_input[10] H1 +set_io sixteen_bit_input[9] R1 +set_io sixteen_bit_input[8] J1 +set_io sixteen_bit_input[7] K1 +set_io sixteen_bit_input[6] L1 +set_io sixteen_bit_input[5] M1 +set_io sixteen_bit_input[4] N2 +set_io sixteen_bit_input[3] P2 +set_io sixteen_bit_input[2] B11 +set_io sixteen_bit_input[1] B14 +set_io sixteen_bit_input[0] B15 + +set_io lcd_data_in_address[5] T11 +set_io lcd_data_in_address[4] N10 +set_io lcd_data_in_address[3] N12 +set_io lcd_data_in_address[2] T13 +set_io lcd_data_in_address[1] T15 +set_io lcd_data_in_address[0] R16 + +set_io lcd_data_in_data[7] R6 +set_io lcd_data_in_data[6] T8 +set_io lcd_data_in_data[5] R9 +set_io lcd_data_in_data[4] P9 +set_io lcd_data_in_data[3] R10 +set_io lcd_data_in_data[2] P10 +set_io lcd_data_in_data[1] M11 +set_io lcd_data_in_data[0] P13 + +set_io lcd_data_in_enable T14 + +set_io led_segment_bus[7] T1 +set_io led_segment_bus[6] R2 +set_io led_segment_bus[5] R3 +set_io led_segment_bus[4] T5 +set_io led_segment_bus[3] T6 +set_io led_segment_bus[2] T7 +set_io led_segment_bus[1] P8 +set_io led_segment_bus[0] T10 + +set_io led_digit_select[3] T2 +set_io led_digit_select[2] T3 +set_io led_digit_select[1] R4 +set_io led_digit_select[0] R5 diff --git a/fpga/serial/lattice/eb85/ice40_remotefpga_test/main.v b/fpga/serial/lattice/eb85/ice40_remotefpga_test/main.v new file mode 100644 index 0000000..3c7fa0f --- /dev/null +++ b/fpga/serial/lattice/eb85/ice40_remotefpga_test/main.v @@ -0,0 +1,104 @@ +// This file is part of the Universal Laboratory (uLab) +// +// © 2007 - 2019 Raptor Engineering, LLC +// All Rights Reserved +// +// Licensed under the terms of the AGPL v3 + +module guest_fpga_top(clk, reset, four_bit_input, four_bit_output, eight_bit_input, eight_bit_output, sixteen_bit_input, sixteen_bit_output, lcd_data_in_address, lcd_data_in_data, lcd_data_in_enable, led_segment_bus, led_digit_select); + input clk; + input reset; + + input [3:0] four_bit_input; + output reg [3:0] four_bit_output; + input [7:0] eight_bit_input; + output reg [7:0] eight_bit_output; + input [15:0] sixteen_bit_input; + output reg [15:0] sixteen_bit_output; + + output reg [5:0] lcd_data_in_address; + output reg [7:0] lcd_data_in_data; + output reg lcd_data_in_enable; + + output reg [7:0] led_segment_bus; + output reg [3:0] led_digit_select; + + reg [7:0] lcd_sample_counter = 48; // Create a sample LCD display counter register + reg [31:0] lcd_character_change_timer = 0; // Wait a certain number of cycles before loading a new character + reg [5:0] lcd_current_character = 0; // The current character's address + + always @(posedge clk) begin + four_bit_output = four_bit_input; // Loopback + eight_bit_output = eight_bit_input[3:0] + eight_bit_input[7:4]; // Sample adder + sixteen_bit_output = sixteen_bit_input[15:8] * sixteen_bit_input[7:0]; // Sample multiplier + + // Sample LCD display routine + lcd_data_in_address = lcd_current_character; // Character location on the LCD display + lcd_data_in_data = lcd_sample_counter; // Character code to display + lcd_data_in_enable = 1; // Enable data transmission + + // Cycle through all character positions + lcd_current_character = lcd_current_character + 1; + if (lcd_current_character > 31) begin + lcd_current_character = 16; + end + + // Cycle through the numbers 0 to 9 at one second intervals + lcd_character_change_timer = lcd_character_change_timer + 1; + if (lcd_character_change_timer > 6000000) begin // Wait one second in between character changes + lcd_character_change_timer = 0; + lcd_sample_counter = lcd_sample_counter + 1; + if (lcd_sample_counter > 57) begin // Character code for the digit 9 + lcd_sample_counter = 48; // Character code for the digit 0 + end + end + end + + // 7-segment LED display driver clock generator + reg sseg_clock; + reg [4:0] sseg_clock_counter; + + always @(posedge clk) begin + sseg_clock_counter = sseg_clock_counter + 1; + if (sseg_clock_counter > 16) begin + sseg_clock_counter = 0; + sseg_clock = ~sseg_clock; + end + end + + // 7-segment LED display driver + // led_segment_bus and led_digit_select are active low + // The bit sequence, MSB to LSB, is dp a b c d e f g + // Segment letters are taken from ug130.pdf page 15 + + // 0: 8'b10000001 + // 1: 8'b11001111 + // 2: 8'b10010010 + // 3: 8'b10000110 + reg [2:0] current_anode; + always @(posedge sseg_clock) begin + current_anode = current_anode + 1; + if (current_anode > 3) begin + current_anode = 0; + end + + case (current_anode) + 0: begin + led_digit_select = 4'b1110; + led_segment_bus = 8'b10000001; + end + 1: begin + led_digit_select = 4'b1101; + led_segment_bus = 8'b11001111; + end + 2: begin + led_digit_select = 4'b1011; + led_segment_bus = 8'b10010010; + end + 3: begin + led_digit_select = 4'b0111; + led_segment_bus = 8'b10000110; + end + endcase + end +endmodule