diff --git a/boards/ulx3s-universal-make/clocks/clk_200M_48M.v b/boards/ulx3s-universal-make/clocks/clk_200M_48M.v
new file mode 100644
index 0000000..2e9bb80
--- /dev/null
+++ b/boards/ulx3s-universal-make/clocks/clk_200M_48M.v
@@ -0,0 +1,75 @@
+/* Verilog netlist generated by SCUBA Diamond (64-bit) 3.7.0.96.1 */
+/* Module Version: 5.7 */
+/* /mt/lattice/diamond/3.7_x64/ispfpga/bin/lin64/scuba -w -n clk_200M_48M -lang verilog -synth synplify -bus_exp 7 -bb -arch sa5p00 -type pll -fin 200.00 -fclkop 48.00 -fclkop_tol 0.0 -phase_cntl STATIC -fb_mode 1 -fdc /home/guest/src/fpga/usbserial-core/TinyFPGA-Bootloader/boards/ulx3s/clock/clk_200M_48M/clk_200M_48M.fdc */
+/* Wed Jul 11 00:10:22 2018 */
+
+
+`timescale 1 ns / 1 ps
+module clk_200M_48M (CLKI, CLKOP, LOCK)/* synthesis NGD_DRC_MASK=1 */;
+ input wire CLKI;
+ output wire CLKOP;
+ output wire LOCK;
+
+ wire REFCLK;
+ wire CLKOP_t;
+ wire scuba_vhi;
+ wire scuba_vlo;
+
+ VHI scuba_vhi_inst (.Z(scuba_vhi));
+
+ VLO scuba_vlo_inst (.Z(scuba_vlo));
+
+ defparam PLLInst_0.PLLRST_ENA = "DISABLED" ;
+ defparam PLLInst_0.INTFB_WAKE = "DISABLED" ;
+ defparam PLLInst_0.STDBY_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.DPHASE_SOURCE = "DISABLED" ;
+ defparam PLLInst_0.CLKOS3_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS3_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_CPHASE = 11 ;
+ defparam PLLInst_0.PLL_LOCK_MODE = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.CLKOP_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOP_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXD = "DIVD" ;
+ defparam PLLInst_0.CLKOS3_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXC = "DIVC" ;
+ defparam PLLInst_0.CLKOS2_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXB = "DIVB" ;
+ defparam PLLInst_0.CLKOS_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXA = "DIVA" ;
+ defparam PLLInst_0.CLKOP_ENABLE = "ENABLED" ;
+ defparam PLLInst_0.CLKOS3_DIV = 1 ;
+ defparam PLLInst_0.CLKOS2_DIV = 1 ;
+ defparam PLLInst_0.CLKOS_DIV = 1 ;
+ defparam PLLInst_0.CLKOP_DIV = 12 ;
+ defparam PLLInst_0.CLKFB_DIV = 6 ;
+ defparam PLLInst_0.CLKI_DIV = 25 ;
+ defparam PLLInst_0.FEEDBK_PATH = "CLKOP" ;
+ EHXPLLL PLLInst_0 (.CLKI(CLKI), .CLKFB(CLKOP_t), .PHASESEL1(scuba_vlo),
+ .PHASESEL0(scuba_vlo), .PHASEDIR(scuba_vlo), .PHASESTEP(scuba_vlo),
+ .PHASELOADREG(scuba_vlo), .STDBY(scuba_vlo), .PLLWAKESYNC(scuba_vlo),
+ .RST(scuba_vlo), .ENCLKOP(scuba_vlo), .ENCLKOS(scuba_vlo), .ENCLKOS2(scuba_vlo),
+ .ENCLKOS3(scuba_vlo), .CLKOP(CLKOP_t), .CLKOS(), .CLKOS2(), .CLKOS3(),
+ .LOCK(LOCK), .INTLOCK(), .REFCLK(REFCLK), .CLKINTFB())
+ /* synthesis FREQUENCY_PIN_CLKOP="48.000000" */
+ /* synthesis FREQUENCY_PIN_CLKI="200.000000" */
+ /* synthesis ICP_CURRENT="5" */
+ /* synthesis LPF_RESISTOR="16" */;
+
+ assign CLKOP = CLKOP_t;
+
+
+ // exemplar begin
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKOP 48.000000
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKI 200.000000
+ // exemplar attribute PLLInst_0 ICP_CURRENT 5
+ // exemplar attribute PLLInst_0 LPF_RESISTOR 16
+ // exemplar end
+
+endmodule
diff --git a/boards/ulx3s-universal-make/clocks/clk_25M_200M.v b/boards/ulx3s-universal-make/clocks/clk_25M_200M.v
new file mode 100644
index 0000000..0ce5c18
--- /dev/null
+++ b/boards/ulx3s-universal-make/clocks/clk_25M_200M.v
@@ -0,0 +1,75 @@
+/* Verilog netlist generated by SCUBA Diamond (64-bit) 3.7.0.96.1 */
+/* Module Version: 5.7 */
+/* /mt/lattice/diamond/3.7_x64/ispfpga/bin/lin64/scuba -w -n clk_25M_200M -lang verilog -synth synplify -bus_exp 7 -bb -arch sa5p00 -type pll -fin 25.00 -fclkop 200.00 -fclkop_tol 0.0 -phase_cntl STATIC -fb_mode 1 -fdc /home/guest/src/fpga/usbserial-core/TinyFPGA-Bootloader/boards/ulx3s/clock/clk_25M_200M/clk_25M_200M.fdc */
+/* Wed Jul 11 00:09:44 2018 */
+
+
+`timescale 1 ns / 1 ps
+module clk_25M_200M (CLKI, CLKOP)/* synthesis NGD_DRC_MASK=1 */;
+ input wire CLKI;
+ output wire CLKOP;
+
+ wire REFCLK;
+ wire LOCK;
+ wire CLKOP_t;
+ wire scuba_vhi;
+ wire scuba_vlo;
+
+ VHI scuba_vhi_inst (.Z(scuba_vhi));
+
+ VLO scuba_vlo_inst (.Z(scuba_vlo));
+
+ defparam PLLInst_0.PLLRST_ENA = "DISABLED" ;
+ defparam PLLInst_0.INTFB_WAKE = "DISABLED" ;
+ defparam PLLInst_0.STDBY_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.DPHASE_SOURCE = "DISABLED" ;
+ defparam PLLInst_0.CLKOS3_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS3_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_CPHASE = 2 ;
+ defparam PLLInst_0.PLL_LOCK_MODE = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.CLKOP_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOP_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXD = "DIVD" ;
+ defparam PLLInst_0.CLKOS3_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXC = "DIVC" ;
+ defparam PLLInst_0.CLKOS2_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXB = "DIVB" ;
+ defparam PLLInst_0.CLKOS_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXA = "DIVA" ;
+ defparam PLLInst_0.CLKOP_ENABLE = "ENABLED" ;
+ defparam PLLInst_0.CLKOS3_DIV = 1 ;
+ defparam PLLInst_0.CLKOS2_DIV = 1 ;
+ defparam PLLInst_0.CLKOS_DIV = 1 ;
+ defparam PLLInst_0.CLKOP_DIV = 3 ;
+ defparam PLLInst_0.CLKFB_DIV = 8 ;
+ defparam PLLInst_0.CLKI_DIV = 1 ;
+ defparam PLLInst_0.FEEDBK_PATH = "CLKOP" ;
+ EHXPLLL PLLInst_0 (.CLKI(CLKI), .CLKFB(CLKOP_t), .PHASESEL1(scuba_vlo),
+ .PHASESEL0(scuba_vlo), .PHASEDIR(scuba_vlo), .PHASESTEP(scuba_vlo),
+ .PHASELOADREG(scuba_vlo), .STDBY(scuba_vlo), .PLLWAKESYNC(scuba_vlo),
+ .RST(scuba_vlo), .ENCLKOP(scuba_vlo), .ENCLKOS(scuba_vlo), .ENCLKOS2(scuba_vlo),
+ .ENCLKOS3(scuba_vlo), .CLKOP(CLKOP_t), .CLKOS(), .CLKOS2(), .CLKOS3(),
+ .LOCK(LOCK), .INTLOCK(), .REFCLK(REFCLK), .CLKINTFB())
+ /* synthesis FREQUENCY_PIN_CLKOP="200.000000" */
+ /* synthesis FREQUENCY_PIN_CLKI="25.000000" */
+ /* synthesis ICP_CURRENT="5" */
+ /* synthesis LPF_RESISTOR="16" */;
+
+ assign CLKOP = CLKOP_t;
+
+
+ // exemplar begin
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKOP 200.000000
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKI 25.000000
+ // exemplar attribute PLLInst_0 ICP_CURRENT 5
+ // exemplar attribute PLLInst_0 LPF_RESISTOR 16
+ // exemplar end
+
+endmodule
diff --git a/boards/ulx3s-universal-make/constraints/ulx3s_v17patch.lpf b/boards/ulx3s-universal-make/constraints/ulx3s_v17patch.lpf
new file mode 100644
index 0000000..8e0d34c
--- /dev/null
+++ b/boards/ulx3s-universal-make/constraints/ulx3s_v17patch.lpf
@@ -0,0 +1,435 @@
+BLOCK RESETPATHS;
+BLOCK ASYNCPATHS;
+## ULX3S v1.7 patched towards v1.8
+
+# The clock "usb" and "gpdi" sheet
+LOCATE COMP "clk_25mhz" SITE "G2";
+IOBUF PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33;
+FREQUENCY PORT "clk_25mhz" 25 MHZ;
+
+# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash
+SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 SLAVE_SPI_PORT=DISABLE MASTER_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE;
+
+## USBSERIAL FTDI-FPGA serial port "usb" sheet
+LOCATE COMP "ftdi_rxd" SITE "L4"; # FPGA transmits to ftdi
+LOCATE COMP "ftdi_txd" SITE "M1"; # FPGA receives from ftdi
+LOCATE COMP "ftdi_nrts" SITE "M3"; # FPGA receives
+LOCATE COMP "ftdi_ndtr" SITE "N1"; # FPGA receives
+LOCATE COMP "ftdi_txden" SITE "L3"; # FPGA receives
+IOBUF PORT "ftdi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "ftdi_txd" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_nrts" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_ndtr" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_txden" PULLMODE=UP IO_TYPE=LVCMOS33;
+
+## LED indicators "blinkey" and "gpio" sheet
+LOCATE COMP "led[7]" SITE "H3";
+LOCATE COMP "led[6]" SITE "E1";
+LOCATE COMP "led[5]" SITE "E2";
+LOCATE COMP "led[4]" SITE "D1";
+LOCATE COMP "led[3]" SITE "D2";
+LOCATE COMP "led[2]" SITE "C1";
+LOCATE COMP "led[1]" SITE "C2";
+LOCATE COMP "led[0]" SITE "B2";
+IOBUF PORT "led[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Pushbuttons "blinkey", "flash", "power", "gpdi" sheet
+LOCATE COMP "btn[0]" SITE "D6"; # BTN_PWRn (inverted logic)
+LOCATE COMP "btn[1]" SITE "R1"; # FIRE1
+LOCATE COMP "btn[2]" SITE "T1"; # FIRE2
+LOCATE COMP "btn[3]" SITE "W1"; # UP
+LOCATE COMP "btn[4]" SITE "V1"; # DOWN
+LOCATE COMP "btn[5]" SITE "U1"; # LEFT
+LOCATE COMP "btn[6]" SITE "Y2"; # RIGHT
+IOBUF PORT "btn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[4]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[5]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[6]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## DIP switch "blinkey", "gpio" sheet
+LOCATE COMP "sw[0]" SITE "E8"; # SW1
+LOCATE COMP "sw[1]" SITE "D8"; # SW2
+LOCATE COMP "sw[2]" SITE "D7"; # SW3
+LOCATE COMP "sw[3]" SITE "E7"; # SW4
+IOBUF PORT "sw[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI OLED DISPLAY SSD1331 (Color) or SSD1306 (B/W) "blinkey", "usb" sheet
+LOCATE COMP "oled_clk" SITE "P4";
+LOCATE COMP "oled_mosi" SITE "P3";
+LOCATE COMP "oled_dc" SITE "P1";
+LOCATE COMP "oled_resn" SITE "P2";
+LOCATE COMP "oled_csn" SITE "N2";
+IOBUF PORT "oled_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_dc" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_resn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI Flash chip "flash" sheet
+LOCATE COMP "flash_csn" SITE "R2";
+LOCATE COMP "flash_clk" SITE "U3";
+LOCATE COMP "flash_mosi" SITE "W2";
+LOCATE COMP "flash_miso" SITE "V2";
+#LOCATE COMP "flash_csspin" SITE "AJ3";
+#LOCATE COMP "flash_initn" SITE "AG4";
+#LOCATE COMP "flash_done" SITE "AJ4";
+#LOCATE COMP "flash_programn" SITE "AH4";
+#LOCATE COMP "flash_cfg_select[0]" SITE "AM4";
+#LOCATE COMP "flash_cfg_select[1]" SITE "AL4";
+#LOCATE COMP "flash_cfg_select[2]" SITE "AK4";
+IOBUF PORT "flash_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_clk" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_csspin" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_initn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SD card "sdcard", "usb" sheet
+LOCATE COMP "sd_clk" SITE "J1"; # sd_clk WiFi_GPIO14
+LOCATE COMP "sd_cmd" SITE "J3"; # sd_cmd_di (MOSI) WiFi GPIO15
+LOCATE COMP "sd_d[0]" SITE "K2"; # sd_dat0_do (MISO) WiFi GPIO2
+LOCATE COMP "sd_d[1]" SITE "K1"; # sd_dat1_irq WiFi GPIO4
+LOCATE COMP "sd_d[2]" SITE "H2"; # sd_dat2 WiFi_GPIO12
+LOCATE COMP "sd_d[3]" SITE "H1"; # sd_dat3_csn WiFi_GPIO13
+LOCATE COMP "sd_wp" SITE "P5"; # not connected
+LOCATE COMP "sd_cdn" SITE "N5"; # not connected
+IOBUF PORT "sd_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cmd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; # WiFi GPIO12 pulldown bootstrapping requirement
+IOBUF PORT "sd_d[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_wp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## ADC SPI (MAX11123) "analog", "ram" sheet
+LOCATE COMP "adc_csn" SITE "R17";
+LOCATE COMP "adc_mosi" SITE "R16";
+LOCATE COMP "adc_miso" SITE "U16";
+LOCATE COMP "adc_sclk" SITE "P17";
+IOBUF PORT "adc_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_sclk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Audio 4-bit DAC "analog", "gpio" sheet
+# 4-bit mode can drive down to 75 ohm load impedance.
+# Lower impedance leads to IO overload,
+# FPGA will stop working and need reboot.
+# For standard 17 ohm earphones:
+# use bits 2,3 as input (High-Z) and drive only bits 0,1.
+LOCATE COMP "audio_l[3]" SITE "B3"; # JACK TIP (left audio)
+LOCATE COMP "audio_l[2]" SITE "C3";
+LOCATE COMP "audio_l[1]" SITE "D3";
+LOCATE COMP "audio_l[0]" SITE "E4";
+LOCATE COMP "audio_r[3]" SITE "C5"; # JACK RING1 (right audio)
+LOCATE COMP "audio_r[2]" SITE "D5";
+LOCATE COMP "audio_r[1]" SITE "B5";
+LOCATE COMP "audio_r[0]" SITE "A3";
+LOCATE COMP "audio_v[3]" SITE "E5"; # JACK RING2 (video or digital audio)
+LOCATE COMP "audio_v[2]" SITE "F5";
+LOCATE COMP "audio_v[1]" SITE "F2";
+LOCATE COMP "audio_v[0]" SITE "H5";
+IOBUF PORT "audio_l[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## WiFi ESP-32 "wifi", "usb", "flash" sheet
+# other pins are shared with GP/GN, SD card and JTAG
+LOCATE COMP "wifi_en" SITE "F1"; # enable/reset WiFi
+LOCATE COMP "wifi_rxd" SITE "K3"; # FPGA transmits to WiFi
+LOCATE COMP "wifi_txd" SITE "K4"; # FPGA receives from WiFi
+LOCATE COMP "wifi_gpio0" SITE "L2";
+LOCATE COMP "wifi_gpio5" SITE "N4"; # WIFI LED
+LOCATE COMP "wifi_gpio16" SITE "L1";
+LOCATE COMP "wifi_gpio17" SITE "N3";
+# LOCATE COMP "prog_done" SITE "Y3"; # not GPIO, always active
+IOBUF PORT "wifi_en" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_txd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio16" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio17" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+# IOBUF PORT "prog_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## PCB antenna 433 MHz (may be also used for FM) "usb" sheet
+LOCATE COMP "ant_433mhz" SITE "G1";
+IOBUF PORT "ant_433mhz" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Second USB port going directly into FPGA "usb", "ram" sheet
+LOCATE COMP "usb_fpga_dp" SITE "E16";
+LOCATE COMP "usb_fpga_dn" SITE "F16";
+IOBUF PORT "usb_fpga_dp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## JTAG ESP-32 "usb" sheet
+# connected to FT231X and ESP-32
+# commented out because those are dedicated pins, not directly useable as GPIO
+# but could be used by some vendor-specific JTAG bridging (boundary scan) module
+#LOCATE COMP "jtag_tdi" SITE "R5"; # FTDI_nRI FPGA receives
+#LOCATE COMP "jtag_tdo" SITE "V4"; # FTDI_nCTS FPGA transmits
+#LOCATE COMP "jtag_tck" SITE "T5"; # FTDI_nDSR FPGA receives
+#LOCATE COMP "jtag_tms" SITE "U5"; # FTDI_nDCD FPGA receives
+#IOBUF PORT "jtag_tdi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tdo" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tck" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tms" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SDRAM "ram" sheet
+LOCATE COMP "sdram_clk" SITE "F19";
+LOCATE COMP "sdram_cke" SITE "F20";
+LOCATE COMP "sdram_csn" SITE "P20";
+LOCATE COMP "sdram_wen" SITE "T20";
+LOCATE COMP "sdram_rasn" SITE "R20";
+LOCATE COMP "sdram_casn" SITE "T19";
+LOCATE COMP "sdram_a[0]" SITE "M20";
+LOCATE COMP "sdram_a[1]" SITE "M19";
+LOCATE COMP "sdram_a[2]" SITE "L20";
+LOCATE COMP "sdram_a[3]" SITE "L19";
+LOCATE COMP "sdram_a[4]" SITE "K20";
+LOCATE COMP "sdram_a[5]" SITE "K19";
+LOCATE COMP "sdram_a[6]" SITE "K18";
+LOCATE COMP "sdram_a[7]" SITE "J20";
+LOCATE COMP "sdram_a[8]" SITE "J19";
+LOCATE COMP "sdram_a[9]" SITE "H20";
+LOCATE COMP "sdram_a[10]" SITE "N19";
+LOCATE COMP "sdram_a[11]" SITE "G20";
+LOCATE COMP "sdram_a[12]" SITE "G19";
+LOCATE COMP "sdram_ba[0]" SITE "P19";
+LOCATE COMP "sdram_ba[1]" SITE "N20";
+LOCATE COMP "sdram_dqm[0]" SITE "U19";
+LOCATE COMP "sdram_dqm[1]" SITE "E20";
+LOCATE COMP "sdram_d[0]" SITE "J16";
+LOCATE COMP "sdram_d[1]" SITE "L18";
+LOCATE COMP "sdram_d[2]" SITE "M18";
+LOCATE COMP "sdram_d[3]" SITE "N18";
+LOCATE COMP "sdram_d[4]" SITE "P18";
+LOCATE COMP "sdram_d[5]" SITE "T18";
+LOCATE COMP "sdram_d[6]" SITE "T17";
+LOCATE COMP "sdram_d[7]" SITE "U20";
+LOCATE COMP "sdram_d[8]" SITE "E19";
+LOCATE COMP "sdram_d[9]" SITE "D20";
+LOCATE COMP "sdram_d[10]" SITE "D19";
+LOCATE COMP "sdram_d[11]" SITE "C20";
+LOCATE COMP "sdram_d[12]" SITE "E18";
+LOCATE COMP "sdram_d[13]" SITE "F18";
+LOCATE COMP "sdram_d[14]" SITE "J18";
+LOCATE COMP "sdram_d[15]" SITE "J17";
+IOBUF PORT "sdram_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_cke" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_wen" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_rasn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_casn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[13]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[14]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[15]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPDI differential interface (Video) "gpdi" sheet
+LOCATE COMP "gpdi_dp[0]" SITE "A16"; # Blue +
+LOCATE COMP "gpdi_dn[0]" SITE "B16"; # Blue -
+LOCATE COMP "gpdi_dp[1]" SITE "A14"; # Green +
+LOCATE COMP "gpdi_dn[1]" SITE "C14"; # Green -
+LOCATE COMP "gpdi_dp[2]" SITE "A12"; # Red +
+LOCATE COMP "gpdi_dn[2]" SITE "A13"; # Read +
+LOCATE COMP "gpdi_ethp" SITE "A19"; # Ethernet +
+LOCATE COMP "gpdi_ethn" SITE "B20"; # Ethernet -
+LOCATE COMP "gpdi_clkp" SITE "A17"; # Clock +
+LOCATE COMP "gpdi_clkn" SITE "B18"; # Clock -
+LOCATE COMP "gpdi_cec" SITE "A18";
+LOCATE COMP "gpdi_sda" SITE "B19"; # I2C shared with RTC
+LOCATE COMP "gpdi_scl" SITE "C12"; # I2C shared with RTC
+IOBUF PORT "gpdi_dp[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_clkp" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_clkn" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethp" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethn" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_cec" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_sda" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_scl" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPIO (default single-ended) "gpio", "ram", "gpdi" sheet
+# Pins enumerated gp[0-27], gn[0-27].
+# With differential mode enabled on Lattice,
+# gp[] (+) are used, gn[] (-) are ignored from design
+# as they handle inverted signal by default.
+# To enable differential, rename LVCMOS33->LVCMOS33D
+LOCATE COMP "gp[0]" SITE "B11"; # J1_5+ GP0
+LOCATE COMP "gn[0]" SITE "C11"; # J1_5- GN0
+LOCATE COMP "gp[1]" SITE "A10"; # J1_7+ GP1
+LOCATE COMP "gn[1]" SITE "A11"; # J1_7- GN1
+LOCATE COMP "gp[2]" SITE "A9"; # J1_9+ GP2
+LOCATE COMP "gn[2]" SITE "B10"; # J1_9- GN2
+LOCATE COMP "gp[3]" SITE "B9"; # J1_11+ GP3
+LOCATE COMP "gn[3]" SITE "C10"; # J1_11- GN3
+LOCATE COMP "gp[4]" SITE "A7"; # J1_13+ GP4
+LOCATE COMP "gn[4]" SITE "A8"; # J1_13- GN4
+LOCATE COMP "gp[5]" SITE "C8"; # J1_15+ GP5
+LOCATE COMP "gn[5]" SITE "B8"; # J1_15- GN5
+LOCATE COMP "gp[6]" SITE "C6"; # J1_17+ GP6
+LOCATE COMP "gn[6]" SITE "C7"; # J1_17- GN6
+IOBUF PORT "gp[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[7]" SITE "A6"; # J1_23+ GP7
+LOCATE COMP "gn[7]" SITE "B6"; # J1_23- GN7
+LOCATE COMP "gp[8]" SITE "A4"; # J1_25+ GP8
+LOCATE COMP "gn[8]" SITE "A5"; # J1_25- GN8
+LOCATE COMP "gp[9]" SITE "A2"; # J1_27+ GP9
+LOCATE COMP "gn[9]" SITE "B1"; # J1_27- GN9
+LOCATE COMP "gp[10]" SITE "C4"; # J1_29+ GP10 WIFI_GPIO27
+LOCATE COMP "gn[10]" SITE "B4"; # J1_29- GN10
+LOCATE COMP "gp[11]" SITE "F4"; # J1_31+ GP11 WIFI_GPIO25
+LOCATE COMP "gn[11]" SITE "E3"; # J1_31- GN11 WIFI_GPIO26
+LOCATE COMP "gp[12]" SITE "G3"; # J1_33+ GP12 WIFI_GPIO32
+LOCATE COMP "gn[12]" SITE "F3"; # J1_33- GN12 WIFI_GPIO33
+LOCATE COMP "gp[13]" SITE "H4"; # J1_35+ GP13 WIFI_GPIO34
+LOCATE COMP "gn[13]" SITE "G5"; # J1_35- GN13 WIFI_GPIO35
+IOBUF PORT "gp[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[14]" SITE "U18"; # J2_5+ GP14
+LOCATE COMP "gn[14]" SITE "U17"; # J2_5- GN14
+LOCATE COMP "gp[15]" SITE "N17"; # J2_7+ GP15
+LOCATE COMP "gn[15]" SITE "P16"; # J2_7- GN15
+LOCATE COMP "gp[16]" SITE "N16"; # J2_9+ GP16
+LOCATE COMP "gn[16]" SITE "M17"; # J2_9- GN16
+LOCATE COMP "gp[17]" SITE "L16"; # J2_11+ GP17
+LOCATE COMP "gn[17]" SITE "L17"; # J2_11- GN17
+LOCATE COMP "gp[18]" SITE "H18"; # J2_13+ GP18
+LOCATE COMP "gn[18]" SITE "H17"; # J2_13- GN18
+LOCATE COMP "gp[19]" SITE "F17"; # J2_15+ GP19
+LOCATE COMP "gn[19]" SITE "G18"; # J2_15- GN19
+LOCATE COMP "gp[20]" SITE "D18"; # J2_17+ GP20
+LOCATE COMP "gn[20]" SITE "E17"; # J2_17- GN20
+IOBUF PORT "gp[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[21]" SITE "C18"; # J2_23+ GP21
+LOCATE COMP "gn[21]" SITE "D17"; # J2_23- GN21
+LOCATE COMP "gp[22]" SITE "D15"; # J2_25+ GP22
+LOCATE COMP "gn[22]" SITE "E15"; # J2_25- GN22
+LOCATE COMP "gp[23]" SITE "B17"; # J2_27+ GP23
+LOCATE COMP "gn[23]" SITE "C17"; # J2_27- GN23
+LOCATE COMP "gp[24]" SITE "C16"; # J2_29+ GP24
+LOCATE COMP "gn[24]" SITE "D16"; # J2_29- GN24
+LOCATE COMP "gp[25]" SITE "B15"; # J2_31+ GP25
+LOCATE COMP "gn[25]" SITE "C15"; # J2_31- GN25
+LOCATE COMP "gp[26]" SITE "B13"; # J2_33+ GP26
+LOCATE COMP "gn[26]" SITE "C13"; # J2_33- GN26
+LOCATE COMP "gp[27]" SITE "D13"; # J2_35+ GP27
+LOCATE COMP "gn[27]" SITE "E13"; # J2_35- GN27
+IOBUF PORT "gp[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SHUTDOWN "power", "ram" sheet (connected from PCB v1.7.5)
+# on PCB v1.7 shutdown is not connected to FPGA
+LOCATE COMP "shutdown" SITE "G16"; # FPGA receives
+IOBUF PORT "shutdown" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
diff --git a/boards/ulx3s-universal-make/constraints/ulx3s_v20.lpf b/boards/ulx3s-universal-make/constraints/ulx3s_v20.lpf
new file mode 100644
index 0000000..2a254c2
--- /dev/null
+++ b/boards/ulx3s-universal-make/constraints/ulx3s_v20.lpf
@@ -0,0 +1,455 @@
+BLOCK RESETPATHS;
+BLOCK ASYNCPATHS;
+## ULX3S v2.0 and v2.1
+
+# The clock "usb" and "gpdi" sheet
+LOCATE COMP "clk_25mhz" SITE "G2";
+IOBUF PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33;
+FREQUENCY PORT "clk_25mhz" 25 MHZ;
+
+# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash
+# compress ON for lattice ddtcmd
+# SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 MASTER_SPI_PORT=DISABLE SLAVE_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE;
+# compress OFF for trellis ecppacd
+SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=OFF MCCLK_FREQ=62 MASTER_SPI_PORT=DISABLE SLAVE_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE;
+
+## USBSERIAL FTDI-FPGA serial port "usb" sheet
+LOCATE COMP "ftdi_rxd" SITE "L4"; # FPGA transmits to ftdi
+LOCATE COMP "ftdi_txd" SITE "M1"; # FPGA receives from ftdi
+LOCATE COMP "ftdi_nrts" SITE "M3"; # FPGA receives
+LOCATE COMP "ftdi_ndtr" SITE "N1"; # FPGA receives
+LOCATE COMP "ftdi_txden" SITE "L3"; # FPGA receives
+IOBUF PORT "ftdi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "ftdi_txd" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_nrts" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_ndtr" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_txden" PULLMODE=UP IO_TYPE=LVCMOS33;
+
+## LED indicators "blinkey" and "gpio" sheet
+LOCATE COMP "led[7]" SITE "H3";
+LOCATE COMP "led[6]" SITE "E1";
+LOCATE COMP "led[5]" SITE "E2";
+LOCATE COMP "led[4]" SITE "D1";
+LOCATE COMP "led[3]" SITE "D2";
+LOCATE COMP "led[2]" SITE "C1";
+LOCATE COMP "led[1]" SITE "C2";
+LOCATE COMP "led[0]" SITE "B2";
+IOBUF PORT "led[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Pushbuttons "blinkey", "flash", "power", "gpdi" sheet
+LOCATE COMP "btn[0]" SITE "D6"; # BTN_PWRn (inverted logic)
+LOCATE COMP "btn[1]" SITE "R1"; # FIRE1
+LOCATE COMP "btn[2]" SITE "T1"; # FIRE2
+LOCATE COMP "btn[3]" SITE "R18"; # UP W1->R18
+LOCATE COMP "btn[4]" SITE "V1"; # DOWN
+LOCATE COMP "btn[5]" SITE "U1"; # LEFT
+LOCATE COMP "btn[6]" SITE "H16"; # RIGHT Y2->H16
+IOBUF PORT "btn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[4]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[5]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[6]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## DIP switch "blinkey", "gpio" sheet
+LOCATE COMP "sw[0]" SITE "E8"; # SW1
+LOCATE COMP "sw[1]" SITE "D8"; # SW2
+LOCATE COMP "sw[2]" SITE "D7"; # SW3
+LOCATE COMP "sw[3]" SITE "E7"; # SW4
+IOBUF PORT "sw[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI OLED DISPLAY SSD1331 (Color) or SSD1306 (B/W) "blinkey", "usb" sheet
+LOCATE COMP "oled_clk" SITE "P4";
+LOCATE COMP "oled_mosi" SITE "P3";
+LOCATE COMP "oled_dc" SITE "P1";
+LOCATE COMP "oled_resn" SITE "P2";
+LOCATE COMP "oled_csn" SITE "N2";
+IOBUF PORT "oled_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_dc" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_resn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI Flash chip "flash" sheet
+LOCATE COMP "flash_csn" SITE "R2";
+LOCATE COMP "flash_mosi" SITE "W2";
+LOCATE COMP "flash_miso" SITE "V2";
+LOCATE COMP "flash_holdn" SITE "W1";
+LOCATE COMP "flash_wpn" SITE "Y2";
+#LOCATE COMP "flash_clk" SITE "U3";
+#LOCATE COMP "flash_csspin" SITE "AJ3";
+#LOCATE COMP "flash_initn" SITE "AG4";
+#LOCATE COMP "flash_done" SITE "AJ4";
+#LOCATE COMP "flash_programn" SITE "AH4";
+#LOCATE COMP "flash_cfg_select[0]" SITE "AM4";
+#LOCATE COMP "flash_cfg_select[1]" SITE "AL4";
+#LOCATE COMP "flash_cfg_select[2]" SITE "AK4";
+IOBUF PORT "flash_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_holdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_wpn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_clk" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_csspin" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_initn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SD card "sdcard", "usb" sheet
+LOCATE COMP "sd_clk" SITE "H2"; # sd_clk WiFi_GPIO14
+LOCATE COMP "sd_cmd" SITE "J1"; # sd_cmd_di (MOSI) WiFi GPIO15
+LOCATE COMP "sd_d[0]" SITE "J3"; # sd_dat0_do (MISO) WiFi GPIO2
+LOCATE COMP "sd_d[1]" SITE "H1"; # sd_dat1_irq WiFi GPIO4
+LOCATE COMP "sd_d[2]" SITE "K1"; # sd_dat2 WiFi_GPIO12
+LOCATE COMP "sd_d[3]" SITE "K2"; # sd_dat3_csn WiFi_GPIO13
+LOCATE COMP "sd_wp" SITE "P5"; # not connected
+LOCATE COMP "sd_cdn" SITE "N5"; # not connected
+IOBUF PORT "sd_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cmd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; # WiFi GPIO12 pulldown bootstrapping requirement
+IOBUF PORT "sd_d[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_wp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## ADC SPI (MAX11123) "analog", "ram" sheet
+LOCATE COMP "adc_csn" SITE "R17";
+LOCATE COMP "adc_mosi" SITE "R16";
+LOCATE COMP "adc_miso" SITE "U16";
+LOCATE COMP "adc_sclk" SITE "P17";
+IOBUF PORT "adc_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_sclk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Audio 4-bit DAC "analog", "gpio" sheet
+# 4-bit mode can drive down to 75 ohm load impedance.
+# Lower impedance leads to IO overload,
+# FPGA will stop working and need reboot.
+# For standard 17 ohm earphones:
+# use bits 2,3 as input (High-Z) and drive only bits 0,1.
+LOCATE COMP "audio_l[3]" SITE "B3"; # JACK TIP (left audio)
+LOCATE COMP "audio_l[2]" SITE "C3";
+LOCATE COMP "audio_l[1]" SITE "D3";
+LOCATE COMP "audio_l[0]" SITE "E4";
+LOCATE COMP "audio_r[3]" SITE "C5"; # JACK RING1 (right audio)
+LOCATE COMP "audio_r[2]" SITE "D5";
+LOCATE COMP "audio_r[1]" SITE "B5";
+LOCATE COMP "audio_r[0]" SITE "A3";
+LOCATE COMP "audio_v[3]" SITE "E5"; # JACK RING2 (video or digital audio)
+LOCATE COMP "audio_v[2]" SITE "F5";
+LOCATE COMP "audio_v[1]" SITE "F2";
+LOCATE COMP "audio_v[0]" SITE "H5";
+IOBUF PORT "audio_l[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## WiFi ESP-32 "wifi", "usb", "flash" sheet
+# other pins are shared with GP/GN, SD card and JTAG
+LOCATE COMP "wifi_en" SITE "F1"; # enable/reset WiFi
+LOCATE COMP "wifi_rxd" SITE "K3"; # FPGA transmits to WiFi
+LOCATE COMP "wifi_txd" SITE "K4"; # FPGA receives from WiFi
+LOCATE COMP "wifi_gpio0" SITE "L2";
+LOCATE COMP "wifi_gpio5" SITE "N4"; # WIFI LED
+LOCATE COMP "wifi_gpio16" SITE "L1"; # Serial1 RX
+LOCATE COMP "wifi_gpio17" SITE "N3"; # Serial1 TX
+# LOCATE COMP "prog_done" SITE "Y3"; # not GPIO, always active
+IOBUF PORT "wifi_en" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_txd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio16" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio17" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+# IOBUF PORT "prog_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## PCB antenna 433 MHz (may be also used for FM) "usb" sheet
+LOCATE COMP "ant_433mhz" SITE "G1";
+IOBUF PORT "ant_433mhz" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Second USB port "US2" going directly into FPGA "usb", "ram" sheet
+LOCATE COMP "usb_fpga_dp" SITE "E16"; # single ended or differential input only
+LOCATE COMP "usb_fpga_dn" SITE "F16";
+IOBUF PORT "usb_fpga_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+LOCATE COMP "usb_fpga_bd_dp" SITE "D15"; # differential bidirectional
+LOCATE COMP "usb_fpga_bd_dn" SITE "E15";
+IOBUF PORT "usb_fpga_bd_dp" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "usb_fpga_bd_dn" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=4;
+LOCATE COMP "usb_fpga_pu_dp" SITE "B12"; # pull up/down control
+LOCATE COMP "usb_fpga_pu_dn" SITE "C12";
+IOBUF PORT "usb_fpga_pu_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+IOBUF PORT "usb_fpga_pu_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+
+## JTAG ESP-32 "usb" sheet
+# connected to FT231X and ESP-32
+# commented out because those are dedicated pins, not directly useable as GPIO
+# but could be used by some vendor-specific JTAG bridging (boundary scan) module
+#LOCATE COMP "jtag_tdi" SITE "R5"; # FTDI_nRI FPGA receives
+#LOCATE COMP "jtag_tdo" SITE "V4"; # FTDI_nCTS FPGA transmits
+#LOCATE COMP "jtag_tck" SITE "T5"; # FTDI_nDSR FPGA receives
+#LOCATE COMP "jtag_tms" SITE "U5"; # FTDI_nDCD FPGA receives
+#IOBUF PORT "jtag_tdi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tdo" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tck" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tms" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SDRAM "ram" sheet
+LOCATE COMP "sdram_clk" SITE "F19";
+LOCATE COMP "sdram_cke" SITE "F20";
+LOCATE COMP "sdram_csn" SITE "P20";
+LOCATE COMP "sdram_wen" SITE "T20";
+LOCATE COMP "sdram_rasn" SITE "R20";
+LOCATE COMP "sdram_casn" SITE "T19";
+LOCATE COMP "sdram_a[0]" SITE "M20";
+LOCATE COMP "sdram_a[1]" SITE "M19";
+LOCATE COMP "sdram_a[2]" SITE "L20";
+LOCATE COMP "sdram_a[3]" SITE "L19";
+LOCATE COMP "sdram_a[4]" SITE "K20";
+LOCATE COMP "sdram_a[5]" SITE "K19";
+LOCATE COMP "sdram_a[6]" SITE "K18";
+LOCATE COMP "sdram_a[7]" SITE "J20";
+LOCATE COMP "sdram_a[8]" SITE "J19";
+LOCATE COMP "sdram_a[9]" SITE "H20";
+LOCATE COMP "sdram_a[10]" SITE "N19";
+LOCATE COMP "sdram_a[11]" SITE "G20";
+LOCATE COMP "sdram_a[12]" SITE "G19";
+LOCATE COMP "sdram_ba[0]" SITE "P19";
+LOCATE COMP "sdram_ba[1]" SITE "N20";
+LOCATE COMP "sdram_dqm[0]" SITE "U19";
+LOCATE COMP "sdram_dqm[1]" SITE "E20";
+LOCATE COMP "sdram_d[0]" SITE "J16";
+LOCATE COMP "sdram_d[1]" SITE "L18";
+LOCATE COMP "sdram_d[2]" SITE "M18";
+LOCATE COMP "sdram_d[3]" SITE "N18";
+LOCATE COMP "sdram_d[4]" SITE "P18";
+LOCATE COMP "sdram_d[5]" SITE "T18";
+LOCATE COMP "sdram_d[6]" SITE "T17";
+LOCATE COMP "sdram_d[7]" SITE "U20";
+LOCATE COMP "sdram_d[8]" SITE "E19";
+LOCATE COMP "sdram_d[9]" SITE "D20";
+LOCATE COMP "sdram_d[10]" SITE "D19";
+LOCATE COMP "sdram_d[11]" SITE "C20";
+LOCATE COMP "sdram_d[12]" SITE "E18";
+LOCATE COMP "sdram_d[13]" SITE "F18";
+LOCATE COMP "sdram_d[14]" SITE "J18";
+LOCATE COMP "sdram_d[15]" SITE "J17";
+IOBUF PORT "sdram_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_cke" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_wen" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_rasn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_casn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[13]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[14]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[15]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPDI differential interface (Video) "gpdi" sheet
+LOCATE COMP "gpdi_dp[0]" SITE "A16"; # Blue +
+LOCATE COMP "gpdi_dn[0]" SITE "B16"; # Blue -
+LOCATE COMP "gpdi_dp[1]" SITE "A14"; # Green +
+LOCATE COMP "gpdi_dn[1]" SITE "C14"; # Green -
+LOCATE COMP "gpdi_dp[2]" SITE "A12"; # Red +
+LOCATE COMP "gpdi_dn[2]" SITE "A13"; # Red -
+LOCATE COMP "gpdi_dp[3]" SITE "A17"; # Clock +
+LOCATE COMP "gpdi_dn[3]" SITE "B18"; # Clock -
+LOCATE COMP "gpdi_ethp" SITE "A19"; # Ethernet +
+LOCATE COMP "gpdi_ethn" SITE "B20"; # Ethernet -
+LOCATE COMP "gpdi_cec" SITE "A18";
+LOCATE COMP "gpdi_sda" SITE "B19"; # I2C shared with RTC
+LOCATE COMP "gpdi_scl" SITE "E12"; # I2C shared with RTC C12->E12
+IOBUF PORT "gpdi_dp[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[3]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[3]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethp" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethn" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_cec" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_sda" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_scl" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPIO (default single-ended) "gpio", "ram", "gpdi" sheet
+# Pins enumerated gp[0-27], gn[0-27].
+# With differential mode enabled on Lattice,
+# gp[] (+) are used, gn[] (-) are ignored from design
+# as they handle inverted signal by default.
+# To enable differential, rename LVCMOS33->LVCMOS33D
+LOCATE COMP "gp[0]" SITE "B11"; # J1_5+ GP0
+LOCATE COMP "gn[0]" SITE "C11"; # J1_5- GN0
+LOCATE COMP "gp[1]" SITE "A10"; # J1_7+ GP1
+LOCATE COMP "gn[1]" SITE "A11"; # J1_7- GN1
+LOCATE COMP "gp[2]" SITE "A9"; # J1_9+ GP2
+LOCATE COMP "gn[2]" SITE "B10"; # J1_9- GN2
+LOCATE COMP "gp[3]" SITE "B9"; # J1_11+ GP3
+LOCATE COMP "gn[3]" SITE "C10"; # J1_11- GN3
+LOCATE COMP "gp[4]" SITE "A7"; # J1_13+ GP4
+LOCATE COMP "gn[4]" SITE "A8"; # J1_13- GN4
+LOCATE COMP "gp[5]" SITE "C8"; # J1_15+ GP5
+LOCATE COMP "gn[5]" SITE "B8"; # J1_15- GN5
+LOCATE COMP "gp[6]" SITE "C6"; # J1_17+ GP6
+LOCATE COMP "gn[6]" SITE "C7"; # J1_17- GN6
+IOBUF PORT "gp[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[7]" SITE "A6"; # J1_23+ GP7
+LOCATE COMP "gn[7]" SITE "B6"; # J1_23- GN7
+LOCATE COMP "gp[8]" SITE "A4"; # J1_25+ GP8
+LOCATE COMP "gn[8]" SITE "A5"; # J1_25- GN8
+LOCATE COMP "gp[9]" SITE "A2"; # J1_27+ GP9
+LOCATE COMP "gn[9]" SITE "B1"; # J1_27- GN9
+LOCATE COMP "gp[10]" SITE "C4"; # J1_29+ GP10 WIFI_GPIO27
+LOCATE COMP "gn[10]" SITE "B4"; # J1_29- GN10
+LOCATE COMP "gp[11]" SITE "F4"; # J1_31+ GP11 WIFI_GPIO25
+LOCATE COMP "gn[11]" SITE "E3"; # J1_31- GN11 WIFI_GPIO26
+LOCATE COMP "gp[12]" SITE "G3"; # J1_33+ GP12 WIFI_GPIO32
+LOCATE COMP "gn[12]" SITE "F3"; # J1_33- GN12 WIFI_GPIO33
+LOCATE COMP "gp[13]" SITE "H4"; # J1_35+ GP13 WIFI_GPIO34
+LOCATE COMP "gn[13]" SITE "G5"; # J1_35- GN13 WIFI_GPIO35
+IOBUF PORT "gp[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[14]" SITE "U18"; # J2_5+ GP14
+LOCATE COMP "gn[14]" SITE "U17"; # J2_5- GN14
+LOCATE COMP "gp[15]" SITE "N17"; # J2_7+ GP15
+LOCATE COMP "gn[15]" SITE "P16"; # J2_7- GN15
+LOCATE COMP "gp[16]" SITE "N16"; # J2_9+ GP16
+LOCATE COMP "gn[16]" SITE "M17"; # J2_9- GN16
+LOCATE COMP "gp[17]" SITE "L16"; # J2_11+ GP17
+LOCATE COMP "gn[17]" SITE "L17"; # J2_11- GN17
+LOCATE COMP "gp[18]" SITE "H18"; # J2_13+ GP18
+LOCATE COMP "gn[18]" SITE "H17"; # J2_13- GN18
+LOCATE COMP "gp[19]" SITE "F17"; # J2_15+ GP19
+LOCATE COMP "gn[19]" SITE "G18"; # J2_15- GN19
+LOCATE COMP "gp[20]" SITE "D18"; # J2_17+ GP20
+LOCATE COMP "gn[20]" SITE "E17"; # J2_17- GN20
+IOBUF PORT "gp[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[21]" SITE "C18"; # J2_23+ GP21
+LOCATE COMP "gn[21]" SITE "D17"; # J2_23- GN21
+LOCATE COMP "gp[22]" SITE "B15"; # J2_25+ GP22 D15->B15
+LOCATE COMP "gn[22]" SITE "C15"; # J2_25- GN22 E15->C15
+LOCATE COMP "gp[23]" SITE "B17"; # J2_27+ GP23
+LOCATE COMP "gn[23]" SITE "C17"; # J2_27- GN23
+LOCATE COMP "gp[24]" SITE "C16"; # J2_29+ GP24
+LOCATE COMP "gn[24]" SITE "D16"; # J2_29- GN24
+LOCATE COMP "gp[25]" SITE "D14"; # J2_31+ GP25 B15->D14
+LOCATE COMP "gn[25]" SITE "E14"; # J2_31- GN25 C15->E14
+LOCATE COMP "gp[26]" SITE "B13"; # J2_33+ GP26
+LOCATE COMP "gn[26]" SITE "C13"; # J2_33- GN26
+LOCATE COMP "gp[27]" SITE "D13"; # J2_35+ GP27
+LOCATE COMP "gn[27]" SITE "E13"; # J2_35- GN27
+IOBUF PORT "gp[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## PROGRAMN (reload bitstream from FLASH, exit from bootloader)
+# PCB v2.0.5 and higher
+LOCATE COMP "user_programn" SITE "M4";
+IOBUF PORT "user_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SHUTDOWN "power", "ram" sheet (connected from PCB v1.7.5)
+# on PCB v1.7 shutdown is not connected to FPGA
+LOCATE COMP "shutdown" SITE "G16"; # FPGA receives
+IOBUF PORT "shutdown" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
diff --git a/boards/ulx3s-universal-make/makefile b/boards/ulx3s-universal-make/makefile
new file mode 100644
index 0000000..fd8a8e1
--- /dev/null
+++ b/boards/ulx3s-universal-make/makefile
@@ -0,0 +1,59 @@
+# ******* project, board and chip name *******
+PROJECT = ulx3s_bootloader
+BOARD = ulx3s
+# 12 25 45 85
+FPGA_SIZE = 12
+
+FPGA_PACKAGE = 6bg381c
+# config flash: 1:SPI (standard), 4:QSPI (quad)
+FLASH_SPI = 4
+# chip: is25lp032d is25lp128f s25fl164k
+FLASH_CHIP = is25lp128f
+
+# ******* if programming with OpenOCD *******
+# using local latest openocd until in linux distribution
+OPENOCD=openocd_ft232r
+# default onboard usb-jtag
+OPENOCD_INTERFACE=$(SCRIPTS)/ft231x.ocd
+# ulx3s-jtag-passthru
+#OPENOCD_INTERFACE=$(SCRIPTS)/ft231x2.ocd
+# ulx2s
+#OPENOCD_INTERFACE=$(SCRIPTS)/ft232r.ocd
+# external jtag
+#OPENOCD_INTERFACE=$(SCRIPTS)/ft2232.ocd
+
+# ******* design files *******
+CONSTRAINTS = constraints/ulx3s_v20.lpf
+TOP_MODULE = bootloader_sp_ulx3s
+TOP_MODULE_FILE = top/$(TOP_MODULE).v
+
+VERILOG_FILES = \
+ $(TOP_MODULE_FILE) \
+ clocks/clk_25M_200M.v \
+ clocks/clk_200M_48M.v \
+ ../../common/tinyfpgasp_bootloader.v \
+ ../../common/edge_detect.v \
+ ../../common/usb_fs_in_arb.v \
+ ../../common/usb_fs_in_pe.v \
+ ../../common/usb_fs_out_arb.v \
+ ../../common/usb_fs_out_pe.v \
+ ../../common/usb_fs_pe.v \
+ ../../common/usb_fs_rx.v \
+ ../../common/usb_fs_tx_mux.v \
+ ../../common/usb_fs_tx.v \
+ ../../common/usb_reset_det.v \
+ ../../common/usb_sp_ctrl_ep.v
+
+
+# *.vhd those files will be converted to *.v files with vhdl2vl (warning overwriting/deleting)
+VHDL_FILES =
+
+# synthesis options
+#YOSYS_OPTIONS = -noccu2
+
+TRELLIS = /mt/scratch/tmp/openfpga/multiboot/prjtrellis/
+SCRIPTS = scripts
+include $(SCRIPTS)/ulx3s_diamond.mk
+
+#include $(SCRIPTS)/ulx3s_trellis.mk
+
diff --git a/boards/ulx3s-universal-make/scripts/IspXCF.dtd b/boards/ulx3s-universal-make/scripts/IspXCF.dtd
new file mode 100644
index 0000000..e69de29
diff --git a/boards/ulx3s-universal-make/scripts/ecp5-ocd.sh b/boards/ulx3s-universal-make/scripts/ecp5-ocd.sh
new file mode 100755
index 0000000..0e68526
--- /dev/null
+++ b/boards/ulx3s-universal-make/scripts/ecp5-ocd.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+# ecp5-ocd.sh
+
+CHIP_ID=$1
+FILE_SVF=$2
+
+cat << EOF
+# OpenOCD commands
+
+telnet_port 4444
+gdb_port 3333
+
+# JTAG TAPs
+jtag newtap lfe5 tap -expected-id ${CHIP_ID} -irlen 8 -irmask 0xFF -ircapture 0x5
+
+init
+scan_chain
+svf -tap lfe5.tap -quiet -progress ${FILE_SVF}
+shutdown
+EOF
diff --git a/boards/ulx3s-universal-make/scripts/ft2232.ocd b/boards/ulx3s-universal-make/scripts/ft2232.ocd
new file mode 100644
index 0000000..52f68a0
--- /dev/null
+++ b/boards/ulx3s-universal-make/scripts/ft2232.ocd
@@ -0,0 +1,19 @@
+#
+# Generic FT2232H JTAG Programmer
+#
+
+
+interface ftdi
+# ftdi_device_desc "Dual RS232-HS"
+ftdi_vid_pid 0x0403 0x6010
+ftdi_layout_init 0x3088 0x1f8b
+
+# default is port A if unspecified
+# pinout ADBUS 0-TCK 1-TDI 2-TDO 3-TMS
+#ftdi_channel 0
+
+# uncomment this to use port B
+# pinout BDBUS 0-TCK 1-TDI 2-TDO 3-TMS
+ftdi_channel 1
+
+adapter_khz 25000
diff --git a/boards/ulx3s-universal-make/scripts/ft231x.ocd b/boards/ulx3s-universal-make/scripts/ft231x.ocd
new file mode 100644
index 0000000..e01f20b
--- /dev/null
+++ b/boards/ulx3s-universal-make/scripts/ft231x.ocd
@@ -0,0 +1,15 @@
+#
+# openocd_ft232r patched for custom jtag nums and buffer_size
+#
+
+interface ft232r
+ft232r_vid_pid 0x0403 0x6015
+# ft232r_serial_desc 123456
+ft232r_tck_num DSR
+ft232r_tms_num DCD
+ft232r_tdi_num RI
+ft232r_tdo_num CTS
+ft232r_trst_num RTS
+ft232r_srst_num DTR
+ft232r_restore_serial 0x15
+adapter_khz 1000
diff --git a/boards/ulx3s-universal-make/scripts/ft231x2.ocd b/boards/ulx3s-universal-make/scripts/ft231x2.ocd
new file mode 100644
index 0000000..5e384be
--- /dev/null
+++ b/boards/ulx3s-universal-make/scripts/ft231x2.ocd
@@ -0,0 +1,19 @@
+#
+# openocd_ft232r patched for custom jtag nums and buffer_size
+# pinout for ulx3s jtag-thru:
+
+# GP14 TMS
+# GN14 TDO
+# GP15 TDI
+# GN15 TCK
+
+interface ft232r
+ft232r_vid_pid 0x0403 0x6015
+# ft232r_serial_desc 250001
+ft232r_tck_num DTR
+ft232r_tms_num RTS
+ft232r_tdi_num TXD
+ft232r_tdo_num RXD
+ft232r_trst_num DCD
+ft232r_srst_num RI
+adapter_khz 1000
diff --git a/boards/ulx3s-universal-make/scripts/ft232r.ocd b/boards/ulx3s-universal-make/scripts/ft232r.ocd
new file mode 100644
index 0000000..2b2ad63
--- /dev/null
+++ b/boards/ulx3s-universal-make/scripts/ft232r.ocd
@@ -0,0 +1,14 @@
+#
+# openocd_ft232r patched for custom jtag nums and buffer_size
+# low-cost FT232R board from ebay
+
+interface ft232r
+# ft232r_vid_pid 0x0403 0x6015
+# ft232r_serial_desc 250001
+ft232r_tck_num DTR
+ft232r_tms_num CTS
+ft232r_tdi_num TXD
+ft232r_tdo_num RXD
+ft232r_trst_num DCD
+ft232r_srst_num RI
+adapter_khz 1000
diff --git a/boards/ulx3s-universal-make/scripts/ldf.xsl b/boards/ulx3s-universal-make/scripts/ldf.xsl
new file mode 100644
index 0000000..4819bea
--- /dev/null
+++ b/boards/ulx3s-universal-make/scripts/ldf.xsl
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-universal-make/scripts/project.ldf b/boards/ulx3s-universal-make/scripts/project.ldf
new file mode 100644
index 0000000..29b8d5d
--- /dev/null
+++ b/boards/ulx3s-universal-make/scripts/project.ldf
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-universal-make/scripts/ulx3s.sty b/boards/ulx3s-universal-make/scripts/ulx3s.sty
new file mode 100644
index 0000000..2b752ed
--- /dev/null
+++ b/boards/ulx3s-universal-make/scripts/ulx3s.sty
@@ -0,0 +1,200 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-universal-make/scripts/ulx3s_diamond.mk b/boards/ulx3s-universal-make/scripts/ulx3s_diamond.mk
new file mode 100644
index 0000000..75fd5fb
--- /dev/null
+++ b/boards/ulx3s-universal-make/scripts/ulx3s_diamond.mk
@@ -0,0 +1,289 @@
+# ******* project, board and chip name *******
+PROJECT ?= project
+BOARD ?= board
+FPGA_SIZE ?= 12
+FPGA_CHIP ?= lfe5u-$(FPGA_SIZE)f
+FPGA_PACKAGE ?= 6bg381c
+# config flash: 1:SPI (standard), 4:QSPI (quad)
+FLASH_SPI ?= 1
+# chip: is25lp032d is25lp128f s25fl164k
+FLASH_CHIP ?= is25lp032d
+
+# ******* design files *******
+CONSTRAINTS ?= board_constraints.lpf
+STRATEGY ?= $(SCRIPTS)/ulx3s.sty
+TOP_MODULE ?= top
+TOP_MODULE_FILE ?= $(TOP_MODULE).v
+VERILOG_FILES ?= $(TOP_MODULE_FILE)
+VHDL_FILES ?=
+
+# ******* tools installation paths *******
+# https://github.com/ldoolitt/vhd2vl
+VHDL2VL ?= /mt/scratch/tmp/openfpga/vhd2vl/src/vhd2vl
+# https://github.com/YosysHQ/yosys
+YOSYS ?= /mt/scratch/tmp/openfpga/yosys/yosys
+# https://github.com/YosysHQ/nextpnr
+NEXTPNR-ECP5 ?= /mt/scratch/tmp/openfpga/nextpnr/nextpnr-ecp5
+# https://github.com/SymbiFlow/prjtrellis
+TRELLIS ?= /mt/scratch/tmp/openfpga/prjtrellis
+
+ifeq ($(FPGA_CHIP), lfe5u-12f)
+ CHIP_ID=0x21111043
+ MASK_FILE=LFE5U-45F.msk
+endif
+ifeq ($(FPGA_CHIP), lfe5u-25f)
+ CHIP_ID=0x41111043
+ MASK_FILE=LFE5U-45F.msk
+endif
+ifeq ($(FPGA_CHIP), lfe5u-45f)
+ CHIP_ID=0x41112043
+ MASK_FILE=LFE5U-45F.msk
+endif
+ifeq ($(FPGA_CHIP), lfe5u-85f)
+ CHIP_ID=0x41113043
+ MASK_FILE=LFE5U-85F.msk
+endif
+
+ifeq ($(FPGA_SIZE), 12)
+ FPGA_K=25
+ IDCODE_CHIPID=--idcode $(CHIP_ID)
+else
+ FPGA_K=$(FPGA_SIZE)
+ IDCODE_CHIPID=
+endif
+
+FPGA_CHIP_EQUIVALENT ?= lfe5u-$(FPGA_K)f
+
+# open source synthesis tools
+ECPPLL ?= $(TRELLIS)/libtrellis/ecppll
+ECPPACK ?= $(TRELLIS)/libtrellis/ecppack
+ECPMULTI ?= $(TRELLIS)/libtrellis/ecpmulti
+TRELLISDB ?= $(TRELLIS)/database
+LIBTRELLIS ?= $(TRELLIS)/libtrellis
+BIT2SVF ?= $(TRELLIS)/tools/bit_to_svf.py
+BASECFG ?= $(TRELLIS)/misc/basecfgs/empty_$(FPGA_CHIP_EQUIVALENT).config
+# yosys options, sometimes those can be used: -noccu2 -nomux -nodram
+YOSYS_OPTIONS ?=
+
+# clock generator
+CLK0_NAME ?= clk0
+CLK0_FILE_NAME ?= clocks/$(CLK0_NAME).v
+CLK0_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0
+CLK1_NAME ?= clk1
+CLK1_FILE_NAME ?= clocks/$(CLK1_NAME).v
+CLK1_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0
+CLK2_NAME ?= clk2
+CLK2_FILE_NAME ?= clocks/$(CLK2_NAME).v
+CLK2_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0
+CLK3_NAME ?= clk3
+CLK3_FILE_NAME ?= clocks/$(CLK3_NAME).v
+CLK3_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0
+
+# closed source synthesis tools
+DIAMOND_BASE := /usr/local/diamond
+ifneq ($(wildcard $(DIAMOND_BASE)),)
+ DIAMOND_BIN := $(shell find ${DIAMOND_BASE}/ -maxdepth 2 -name bin | sort -rn | head -1)
+ DIAMONDC := $(shell find ${DIAMOND_BIN}/ -name diamondc)
+ DDTCMD := $(shell find ${DIAMOND_BIN}/ -name ddtcmd)
+ MASK_PATH := $(shell find ${DIAMOND_BASE}/ -maxdepth 5 -name xpga -type d)/ecp5
+endif
+
+#PROJ_FILE := $(shell ls *.ldf | head -1)
+#PROJ_NAME := $(shell fgrep default_implementation ${PROJ_FILE} | cut -d'"' -f 4)
+#IMPL_NAME := $(shell fgrep default_implementation ${PROJ_FILE} | cut -d'"' -f 8)
+#IMPL_DIR := $(shell fgrep default_strategy ${PROJ_FILE} | cut -d'"' -f 4)
+
+# programming tools
+TINYFPGASP ?= tinyfpgasp
+FLEAFPGA_JTAG ?= FleaFPGA-JTAG
+OPENOCD ?= openocd
+OPENOCD_INTERFACE ?= $(SCRIPTS)/ft231x.ocd
+UJPROG ?= ujprog
+
+# helper scripts directory
+SCRIPTS ?= scripts
+
+# rest of the include makefile
+FPGA_CHIP_UPPERCASE := $(shell echo $(FPGA_CHIP) | tr '[:lower:]' '[:upper:]')
+FPGA_PACKAGE_UPPERCASE := $(shell echo $(FPGA_PACKAGE) | tr '[:lower:]' '[:upper:]')
+
+#all: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf
+# all: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf
+#all: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+all: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit
+
+# VHDL to VERILOG conversion
+%.v: %.vhd
+ $(VHDL2VL) $< $@
+
+#*.v: *.vhdl
+# $(VHDL2VL) $< $@
+
+#$(PROJECT).ys: makefile
+# $(SCRIPTS)/ysgen.sh $(VERILOG_FILES) $(VHDL_TO_VERILOG_FILES) > $@
+# echo "hierarchy -top ${TOP_MODULE}" >> $@
+# echo "synth_ecp5 -noccu2 -nomux -nodram -json ${PROJECT}.json" >> $@
+
+#$(PROJECT).json: $(PROJECT).ys $(VERILOG_FILES) $(VHDL_TO_VERILOG_FILES)
+# $(YOSYS) $(PROJECT).ys
+
+$(PROJECT).json: $(VERILOG_FILES) $(VHDL_TO_VERILOG_FILES)
+ $(YOSYS) \
+ -p "hierarchy -top ${TOP_MODULE}" \
+ -p "synth_ecp5 ${YOSYS_OPTIONS} -json ${PROJECT}.json" \
+ $(VERILOG_FILES) $(VHDL_TO_VERILOG_FILES)
+
+$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config: $(PROJECT).json $(BASECFG)
+ $(NEXTPNR-ECP5) --$(FPGA_K)k --json $(PROJECT).json --lpf $(CONSTRAINTS) --basecfg $(BASECFG) --textcfg $@
+
+#$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config
+# LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPPACK) $(IDCODE_CHIPID) --db $(TRELLISDB) --input $< --bit $@
+
+multi.bit: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit
+ LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPMULTI) \
+ --db $(TRELLISDB) \
+ --flashsize 128 \
+ --input $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit \
+ --input $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit --address 0x200000 \
+ --output $@
+
+multi12f.bit: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit
+ LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPMULTI) \
+ --db $(TRELLISDB) \
+ --flashsize 128 \
+ --input-idcode 0x41111043 \
+ --input $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit \
+ --input $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit --address 0x200000 \
+ --output-idcode 0x21111043 \
+ --output $@
+
+
+# generate LDF project file for diamond
+$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).ldf: $(SCRIPTS)/project.ldf $(SCRIPTS)/ldf.xsl
+ xsltproc \
+ --stringparam FPGA_DEVICE $(FPGA_CHIP_UPPERCASE)-$(FPGA_PACKAGE_UPPERCASE) \
+ --stringparam CONSTRAINTS_FILE $(CONSTRAINTS) \
+ --stringparam STRATEGY_FILE $(STRATEGY) \
+ --stringparam TOP_MODULE $(TOP_MODULE) \
+ --stringparam TOP_MODULE_FILE $(TOP_MODULE_FILE) \
+ --stringparam VHDL_FILES "$(VHDL_FILES)" \
+ --stringparam VERILOG_FILES "$(VERILOG_FILES)" \
+ $(SCRIPTS)/ldf.xsl $(SCRIPTS)/project.ldf > $@
+
+project/project_project.bit: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).ldf $(VERILOG_FILES) $(VHDL_FILES)
+ echo prj_project open $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).ldf \; prj_run Export -task Bitgen | ${DIAMONDC}
+
+$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit: project/project_project.bit
+ ln -sf project/project_project.bit $@
+
+$(CLK0_FILE_NAME):
+ LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPPLL) $(CLK0_OPTIONS) --file $@
+ sed -e "s/module pll(/module $(CLK0_NAME)(/g" -i $@
+
+$(CLK1_FILE_NAME):
+ LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPPLL) $(CLK1_OPTIONS) --file $@
+ sed -e "s/module pll(/module $(CLK1_NAME)(/g" -i $@
+
+$(CLK2_FILE_NAME):
+ LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPPLL) $(CLK2_OPTIONS) --file $@
+ sed -e "s/module pll(/module $(CLK2_NAME)(/g" -i $@
+
+$(CLK3_FILE_NAME):
+ LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPPLL) $(CLK3_OPTIONS) --file $@
+ sed -e "s/module pll(/module $(CLK3_NAME)(/g" -i $@
+
+# generate sram programming XCF file for DDTCMD
+$(BOARD)_$(FPGA_SIZE)f.xcf: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit $(SCRIPTS)/$(BOARD)_sram.xcf $(SCRIPTS)/xcf.xsl
+ xsltproc \
+ --stringparam FPGA_CHIP $(FPGA_CHIP_UPPERCASE) \
+ --stringparam CHIP_ID $(CHIP_ID) \
+ --stringparam BITSTREAM_FILE $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit \
+ $(SCRIPTS)/xcf.xsl $(SCRIPTS)/$(BOARD)_sram.xcf > $@
+
+# run DDTCMD to generate sram VME file
+$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme: $(BOARD)_$(FPGA_SIZE)f.xcf $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit
+ LANG=C ${DDTCMD} -oft -fullvme -if $(BOARD)_$(FPGA_SIZE)f.xcf -nocompress -noheader -of $@
+
+# run DDTCMD to generate SVF file
+$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf: $(BOARD)_$(FPGA_SIZE)f.xcf $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if $(BOARD)_$(FPGA_SIZE)f.xcf -of $@
+
+# run DDTCMD to generate flash MCS file
+$(BOARD)_$(FPGA_SIZE)f_$(PROJECT)_flash.mcs: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit
+ LANG=C ${DDTCMD} -dev $(FPGA_CHIP_UPPERCASE) \
+ -if $< -oft -int -quad $(FPGA_SPI) -of $@
+
+# generate flash programming XCF file for DDTCMD
+$(BOARD)_$(FPGA_SIZE)f_flash_$(FLASH_CHIP).xcf: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit $(SCRIPTS)/$(BOARD)_flash_$(FLASH_CHIP).xcf $(SCRIPTS)/xcf.xsl
+ xsltproc \
+ --stringparam FPGA_CHIP $(FPGA_CHIP_UPPERCASE) \
+ --stringparam CHIP_ID $(CHIP_ID) \
+ --stringparam MASK_FILE $(MASK_PATH)/$(MASK_FILE) \
+ --stringparam BITSTREAM_FILE $(BOARD)_$(FPGA_SIZE)f_$(PROJECT)_flash.mcs \
+ $(SCRIPTS)/xcf.xsl $(SCRIPTS)/$(BOARD)_flash_$(FLASH_CHIP).xcf > $@
+
+# run DDTCMD to generate flash VME file
+$(BOARD)_$(FPGA_SIZE)f_$(PROJECT)_flash_$(FLASH_CHIP).vme: ulx3s_$(FPGA_SIZE)f_flash_$(FLASH_CHIP).xcf $(BOARD)_$(FPGA_SIZE)f_$(PROJECT)_flash.mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if $(BOARD)_$(FPGA_SIZE)f_flash_$(FLASH_CHIP).xcf -nocompress -noheader -of $@
+
+# generate SVF file by prjtrellis python script
+#$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit
+# $(BIT2SVF) $< $@
+
+#$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config
+# LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPPACK) $(IDCODE_CHIPID) --db $(TRELLISDB) $< --freq 62.0 --svf-rowsize 8000 --svf $@
+
+# program SRAM with ujrprog (temporary)
+program: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit
+ $(UJPROG) $<
+
+# program SRAM with FleaFPGA-JTAG (temporary)
+program_flea: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme
+ $(FLEAFPGA_JTAG) $<
+
+# program FLASH over US1 port with ujprog (permanently)
+flash: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit
+ $(UJPROG) -j flash $<
+
+# program FLASH uver US1 with FleaFPGA-JTAG (permanent)
+flash_flea: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT)_flash_$(FLASH_CHIP).vme
+ $(FLEAFPGA_JTAG) $<
+
+# program FLASH over US2 port with tinyfpgasp bootloader (permanently)
+flash_tiny: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit
+ $(TINYFPGASP) -w $<
+
+# generate chip-specific openocd programming file
+$(BOARD)_$(FPGA_SIZE)f.ocd: makefile $(SCRIPTS)/ecp5-ocd.sh
+ $(SCRIPTS)/ecp5-ocd.sh $(CHIP_ID) $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf > $@
+
+# program SRAM with OPENOCD
+program_ocd: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf $(BOARD)_$(FPGA_SIZE)f.ocd
+ $(OPENOCD) --file=$(OPENOCD_INTERFACE) --file=$(BOARD)_$(FPGA_SIZE)f.ocd
+
+JUNK = *~
+#JUNK += $(PROJECT).ys
+JUNK += $(PROJECT).json
+JUNK += $(VHDL_TO_VERILOG_FILES)
+JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config
+JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).ldf
+JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit
+JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme
+JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf
+JUNK += $(BOARD)_$(FPGA_SIZE)f.xcf
+JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT)_flash.mcs
+JUNK += $(BOARD)_$(FPGA_SIZE)f_flash_$(FLASH_CHIP).xcf
+JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT)_flash_$(FLASH_CHIP).vme
+JUNK += $(BOARD)_$(FPGA_SIZE)f.ocd
+JUNK += $(CLK0_FILE_NAME) $(CLK1_FILE_NAME) $(CLK2_FILE_NAME) $(CLK3_FILE_NAME)
+# diamond junk
+JUNK += ${IMPL_DIR} .recovery ._Real_._Math_.vhd *.sty reportview.xml
+JUNK += dummy_sym.sort project_tcl.html promote.xml
+JUNK += generate_core.tcl generate_ngd.tcl msg_file.log
+
+JUNK_DIR = project
+JUNK_DIR += project_tcr.dir
+
+clean:
+ rm -rf $(JUNK_DIR)
+ rm -f $(JUNK)
diff --git a/boards/ulx3s-universal-make/scripts/ulx3s_flash_is25lp032d.xcf b/boards/ulx3s-universal-make/scripts/ulx3s_flash_is25lp032d.xcf
new file mode 100644
index 0000000..d4ddc66
--- /dev/null
+++ b/boards/ulx3s-universal-make/scripts/ulx3s_flash_is25lp032d.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-12F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project_flash_is25lp032d.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-12F
+ 0x21111043
+ All
+ LFE5U-12F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ Micron
+ SPI Serial Flash
+ SPI-M25P32
+ 0x15
+ 8-pin VDFPN8
+ SPI Flash Erase,Program
+ project/project_project_flash_is25lp032d.mcs
+ 0x00000000
+ 0x00400000
+ 32
+ 4194304
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project_flash_is25lp032d.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-universal-make/scripts/ulx3s_flash_is25lp128f.xcf b/boards/ulx3s-universal-make/scripts/ulx3s_flash_is25lp128f.xcf
new file mode 100644
index 0000000..4096eaf
--- /dev/null
+++ b/boards/ulx3s-universal-make/scripts/ulx3s_flash_is25lp128f.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-12F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project_flash_is25lp128f.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-12F
+ 0x21111043
+ All
+ LFE5U-12F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ SPANSION
+ SPI Serial Flash
+ SPI-S25FL128S
+ 8-lead WSON
+ 0x17
+ SPI Flash Erase,Program
+ project/project_project_flash_is25lp128f.mcs
+ 0x00000000
+ 0x01000000
+ 128
+ 16777216
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project_flash_is25lp128f.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-universal-make/scripts/ulx3s_flash_s25fl164k.xcf b/boards/ulx3s-universal-make/scripts/ulx3s_flash_s25fl164k.xcf
new file mode 100644
index 0000000..8247a13
--- /dev/null
+++ b/boards/ulx3s-universal-make/scripts/ulx3s_flash_s25fl164k.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-12F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project_flash_s25fl164k.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-12F
+ 0x21111043
+ All
+ LFE5U-12F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ SPANSION
+ SPI Serial Flash
+ SPI-S25FL164K
+ 0x16
+ 8-lead SOIC
+ SPI Flash Erase,Program
+ project/project_project_flash_s25fl164k.mcs
+ 0x00000000
+ 0x00800000
+ 64
+ 8388608
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project_flash_s25fl164k.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-universal-make/scripts/ulx3s_sram.xcf b/boards/ulx3s-universal-make/scripts/ulx3s_sram.xcf
new file mode 100644
index 0000000..dd6a770
--- /dev/null
+++ b/boards/ulx3s-universal-make/scripts/ulx3s_sram.xcf
@@ -0,0 +1,48 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-25F
+ 0x41111043
+ All
+ LFE5U-25F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project.bit
+ Fast Program
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ DUAL RS232-HS A Location 0000 Serial Dual RS232-HS A
+
+
diff --git a/boards/ulx3s-universal-make/scripts/ulx3s_trellis.mk b/boards/ulx3s-universal-make/scripts/ulx3s_trellis.mk
new file mode 100644
index 0000000..a541c6e
--- /dev/null
+++ b/boards/ulx3s-universal-make/scripts/ulx3s_trellis.mk
@@ -0,0 +1,207 @@
+# ******* project, board and chip name *******
+PROJECT ?= project
+BOARD ?= board
+FPGA_SIZE ?= 12
+FPGA_CHIP ?= lfe5u-$(FPGA_SIZE)f
+
+# ******* design files *******
+CONSTRAINTS ?= board_constraints.lpf
+TOP_MODULE ?= top
+VERILOG_FILES ?= $(TOP_MODULE).v
+# implicit list of *.vhd VHDL files to be converted to verilog *.v
+# files here are list as *.v but user should
+# edit original source which has *.vhd extension (vhdl_blink.vhd)
+VHDL_FILES ?=
+
+# ******* tools installation paths *******
+# https://github.com/ldoolitt/vhd2vl
+VHDL2VL ?= /mt/scratch/tmp/openfpga/vhd2vl/src/vhd2vl
+# https://github.com/YosysHQ/yosys
+YOSYS ?= /mt/scratch/tmp/openfpga/yosys/yosys
+# https://github.com/YosysHQ/nextpnr
+NEXTPNR-ECP5 ?= /mt/scratch/tmp/openfpga/nextpnr/nextpnr-ecp5
+# https://github.com/SymbiFlow/prjtrellis
+TRELLIS ?= /mt/scratch/tmp/openfpga/prjtrellis
+
+ifeq ($(FPGA_CHIP), lfe5u-12f)
+ CHIP_ID=0x21111043
+endif
+ifeq ($(FPGA_CHIP), lfe5u-25f)
+ CHIP_ID=0x41111043
+endif
+ifeq ($(FPGA_CHIP), lfe5u-45f)
+ CHIP_ID=0x41112043
+endif
+ifeq ($(FPGA_CHIP), lfe5u-85f)
+ CHIP_ID=0x41113043
+endif
+
+ifeq ($(FPGA_SIZE), 12)
+ FPGA_K=25
+ IDCODE_CHIPID=--idcode $(CHIP_ID)
+else
+ FPGA_K=$(FPGA_SIZE)
+ IDCODE_CHIPID=
+endif
+
+FPGA_CHIP_EQUIVALENT ?= lfe5u-$(FPGA_K)f
+
+# open source synthesis tools
+ECPPLL ?= $(TRELLIS)/libtrellis/ecppll
+ECPPACK ?= $(TRELLIS)/libtrellis/ecppack
+TRELLISDB ?= $(TRELLIS)/database
+LIBTRELLIS ?= $(TRELLIS)/libtrellis
+BIT2SVF ?= $(TRELLIS)/tools/bit_to_svf.py
+BASECFG ?= $(TRELLIS)/misc/basecfgs/empty_$(FPGA_CHIP_EQUIVALENT).config
+# yosys options, sometimes those can be used: -noccu2 -nomux -nodram
+YOSYS_OPTIONS ?=
+
+# clock generator
+CLK0_NAME ?= clk0
+CLK0_FILE_NAME ?= clocks/$(CLK0_NAME).v
+CLK0_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0
+CLK1_NAME ?= clk1
+CLK1_FILE_NAME ?= clocks/$(CLK1_NAME).v
+CLK1_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0
+CLK2_NAME ?= clk2
+CLK2_FILE_NAME ?= clocks/$(CLK2_NAME).v
+CLK2_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0
+CLK3_NAME ?= clk3
+CLK3_FILE_NAME ?= clocks/$(CLK3_NAME).v
+CLK3_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0
+
+# closed source synthesis tools
+DIAMOND_BASE := /usr/local/diamond
+ifneq ($(wildcard $(DIAMOND_BASE)),)
+ DIAMOND_BIN := $(shell find ${DIAMOND_BASE}/ -maxdepth 2 -name bin | sort -rn | head -1)
+ DIAMONDC := $(shell find ${DIAMOND_BIN}/ -name diamondc)
+ DDTCMD := $(shell find ${DIAMOND_BIN}/ -name ddtcmd)
+endif
+
+# programming tools
+TINYFPGASP ?= tinyfpgasp
+FLEAFPGA_JTAG ?= FleaFPGA-JTAG
+OPENOCD ?= openocd
+OPENOCD_INTERFACE ?= $(SCRIPTS)/ft231x.ocd
+UJPROG ?= ujprog
+
+# helper scripts directory
+SCRIPTS ?= scripts
+
+# rest of the include makefile
+FPGA_CHIP_UPPERCASE := $(shell echo $(FPGA_CHIP) | tr '[:lower:]' '[:upper:]')
+
+
+#all: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf
+all: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf
+
+# VHDL to VERILOG conversion
+# convert all *.vhd filenames to .v extension
+VHDL_TO_VERILOG_FILES = $(VHDL_FILES:.vhd=.v)
+# implicit conversion rule
+%.v: %.vhd
+ $(VHDL2VL) $< $@
+
+#*.v: *.vhdl
+# $(VHDL2VL) $< $@
+
+#$(PROJECT).ys: makefile
+# $(SCRIPTS)/ysgen.sh $(VERILOG_FILES) $(VHDL_TO_VERILOG_FILES) > $@
+# echo "hierarchy -top ${TOP_MODULE}" >> $@
+# echo "synth_ecp5 -noccu2 -nomux -nodram -json ${PROJECT}.json" >> $@
+
+#$(PROJECT).json: $(PROJECT).ys $(VERILOG_FILES) $(VHDL_TO_VERILOG_FILES)
+# $(YOSYS) $(PROJECT).ys
+
+$(PROJECT).json: $(VERILOG_FILES) $(VHDL_TO_VERILOG_FILES)
+ $(YOSYS) \
+ -p "hierarchy -top ${TOP_MODULE}" \
+ -p "synth_ecp5 ${YOSYS_OPTIONS} -json ${PROJECT}.json" \
+ $(VERILOG_FILES) $(VHDL_TO_VERILOG_FILES)
+
+$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config: $(PROJECT).json $(BASECFG)
+ $(NEXTPNR-ECP5) --$(FPGA_K)k --json $(PROJECT).json --lpf $(CONSTRAINTS) --basecfg $(BASECFG) --textcfg $@
+
+# $(NEXTPNR-ECP5) --$(FPGA_K)k --json $(PROJECT).json --lpf $(CONSTRAINTS) --textcfg $@
+# basecfg is obsolete for new prjtrellis
+
+$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config
+ LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPPACK) $(IDCODE_CHIPID) --db $(TRELLISDB) --input $< --bit $@
+
+$(CLK0_FILE_NAME):
+ LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPPLL) $(CLK0_OPTIONS) --file $@
+ sed -e "s/module pll(/module $(CLK0_NAME)(/g" -i $@
+
+$(CLK1_FILE_NAME):
+ LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPPLL) $(CLK1_OPTIONS) --file $@
+ sed -e "s/module pll(/module $(CLK1_NAME)(/g" -i $@
+
+$(CLK2_FILE_NAME):
+ LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPPLL) $(CLK2_OPTIONS) --file $@
+ sed -e "s/module pll(/module $(CLK2_NAME)(/g" -i $@
+
+$(CLK3_FILE_NAME):
+ LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPPLL) $(CLK3_OPTIONS) --file $@
+ sed -e "s/module pll(/module $(CLK3_NAME)(/g" -i $@
+
+# generate XCF programming file for DDTCMD
+$(BOARD)_$(FPGA_SIZE)f.xcf: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit $(SCRIPTS)/$(BOARD)_sram.xcf $(SCRIPTS)/xcf.xsl $(DTD_FILE)
+ xsltproc \
+ --stringparam FPGA_CHIP $(FPGA_CHIP_UPPERCASE) \
+ --stringparam CHIP_ID $(CHIP_ID) \
+ --stringparam BITSTREAM_FILE $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit \
+ $(SCRIPTS)/xcf.xsl $(SCRIPTS)/$(BOARD)_sram.xcf > $@
+
+# run DDTCMD to generate VME file
+$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme: $(BOARD)_$(FPGA_SIZE)f.xcf $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit
+ LANG=C ${DDTCMD} -oft -fullvme -if $(BOARD)_$(FPGA_SIZE)f.xcf -nocompress -noheader -of $@
+
+# run DDTCMD to generate SVF file
+#$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf: $(BOARD)_$(FPGA_SIZE)f.xcf $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit
+# LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if $(BOARD)_$(FPGA_SIZE)f.xcf -of $@
+
+# generate SVF file by prjtrellis python script
+#$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit
+# $(BIT2SVF) $< $@
+
+$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config
+ LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPPACK) $(IDCODE_CHIPID) --db $(TRELLISDB) $< --freq 62.0 --svf-rowsize 8000 --svf $@
+
+# program SRAM with ujrprog (temporary)
+program: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit
+ $(UJPROG) $<
+
+# program SRAM with FleaFPGA-JTAG (temporary)
+program_flea: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme
+ $(FLEAFPGA_JTAG) $<
+
+# program FLASH over US1 port with ujprog bootloader (permanently)
+flash: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit
+ $(UJPROG) -j flash $<
+
+# program FLASH over US2 port with tinyfpgasp bootloader (permanently)
+flash_tiny: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit
+ $(TINYFPGASP) -w $<
+
+# generate chip-specific openocd programming file
+$(BOARD)_$(FPGA_SIZE)f.ocd: makefile $(SCRIPTS)/ecp5-ocd.sh
+ $(SCRIPTS)/ecp5-ocd.sh $(CHIP_ID) $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf > $@
+
+# program SRAM with OPENOCD
+program_ocd: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf $(BOARD)_$(FPGA_SIZE)f.ocd
+ $(OPENOCD) --file=$(OPENOCD_INTERFACE) --file=$(BOARD)_$(FPGA_SIZE)f.ocd
+
+JUNK = *~
+#JUNK += $(PROJECT).ys
+JUNK += $(PROJECT).json
+JUNK += $(VHDL_TO_VERILOG_FILES)
+JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config
+JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit
+JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme
+JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf
+JUNK += $(BOARD)_$(FPGA_SIZE)f.xcf
+JUNK += $(BOARD)_$(FPGA_SIZE)f.ocd
+JUNK += $(CLK0_FILE_NAME) $(CLK1_FILE_NAME) $(CLK2_FILE_NAME) $(CLK3_FILE_NAME)
+
+clean:
+ rm -f $(JUNK)
diff --git a/boards/ulx3s-universal-make/scripts/xcf.xsl b/boards/ulx3s-universal-make/scripts/xcf.xsl
new file mode 100644
index 0000000..a152970
--- /dev/null
+++ b/boards/ulx3s-universal-make/scripts/xcf.xsl
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-universal-make/top/bootloader_sp_ulx3s.v b/boards/ulx3s-universal-make/top/bootloader_sp_ulx3s.v
new file mode 100644
index 0000000..95e7e0b
--- /dev/null
+++ b/boards/ulx3s-universal-make/top/bootloader_sp_ulx3s.v
@@ -0,0 +1,148 @@
+module bootloader_sp_ulx3s (
+ input clk_25mhz,
+
+ inout usb_fpga_dp,
+ inout usb_fpga_dn,
+
+ output usb_fpga_pu_dp,
+ inout user_programn,
+
+ output [7:0] led,
+
+ input flash_miso,
+ output flash_mosi,
+ output flash_csn,
+ output flash_wpn,
+ output flash_holdn,
+
+ input [6:0] btn,
+ output wifi_gpio0
+);
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// generate 48 mhz clock
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ wire clk_200mhz;
+ clk_25M_200M clk_200M_inst (
+ .CLKI(clk_25mhz),
+ .CLKOP(clk_200mhz)
+ );
+
+ wire clk_48mhz;
+ wire clk_ready;
+ clk_200M_48M clk_48M_inst (
+ .CLKI(clk_200mhz),
+ .CLKOP(clk_48mhz),
+ .LOCK(clk_ready)
+ );
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// instantiate tinyfpga bootloader
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ reg [15:0] reset_counter = 0; // counter for debouce and prolong reset
+ wire reset;
+ assign reset = ~reset_counter[15];
+ wire usb_p_tx;
+ wire usb_n_tx;
+ wire usb_p_rx;
+ wire usb_n_rx;
+ wire usb_tx_en;
+ wire pin_led;
+ wire [7:0] debug_led;
+ wire boot;
+ wire S_flash_clk;
+ wire S_flash_csn;
+
+ tinyfpgasp_bootloader tinyfpgasp_bootloader_inst (
+ .clk_48mhz(clk_48mhz),
+ .reset(reset),
+ .usb_p_tx(usb_p_tx),
+ .usb_n_tx(usb_n_tx),
+ .usb_p_rx(usb_p_rx),
+ .usb_n_rx(usb_n_rx),
+ .usb_tx_en(usb_tx_en),
+ .led(pin_led),
+ .debug_led(debug_led),
+ .spi_miso(flash_miso),
+ .spi_mosi(flash_mosi),
+ .spi_sck(S_flash_clk),
+ .spi_cs(S_flash_csn),
+ .boot(boot)
+ );
+
+ assign usb_fpga_dp = reset ? 1'b0 : (usb_tx_en ? usb_p_tx : 1'bz);
+ assign usb_fpga_dn = reset ? 1'b0 : (usb_tx_en ? usb_n_tx : 1'bz);
+ assign usb_p_rx = usb_tx_en ? 1'b1 : usb_fpga_dp;
+ assign usb_n_rx = usb_tx_en ? 1'b0 : usb_fpga_dn;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// Vendor-specific clock output to SPI config flash
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ USRMCLK usrmclk_inst (
+ .USRMCLKI(S_flash_clk),
+ .USRMCLKTS(S_flash_csn)
+ ) /* synthesis syn_noprune=1 */;
+ assign flash_csn = S_flash_csn;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// Debonuce and prolong RESET
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ always @(posedge clk_48mhz)
+ begin
+ if (btn[1] | ~clk_ready)
+ reset_counter <= 0;
+ else
+ if (reset_counter[15] == 0)
+ reset_counter <= reset_counter + 1;
+ end
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// ULX3S board buttons and LEDs
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ assign wifi_gpio0 = btn[0];
+ assign led[0] = pin_led;
+ assign led[1] = ~pin_led;
+ assign led[5] = debug_led;
+ assign led[7] = boot;
+ // assign led[3:0] = {flash_miso, flash_mosi, S_flash_clk, S_flash_csn};
+
+ // PULLUP 1.5k D+
+ assign usb_fpga_pu_dp = 1;
+
+ // set 1 to holdn wpn for use as single bit mode spi
+ assign flash_holdn = 1;
+ assign flash_wpn = 1;
+
+ // delay for BTN0 is required
+ reg [3:0] R_progn = 0;
+ always @(posedge clk_25mhz)
+ if(btn[0])
+ R_progn <= 0;
+ else
+ R_progn <= R_progn + 1;
+
+ // EXIT from BOOTLOADER
+ assign user_programn = ~boot & ~R_progn[3];
+
+endmodule
diff --git a/boards/ulx3s-v1.7-45f-sp/Makefile b/boards/ulx3s-v1.7-45f-sp/Makefile
new file mode 100644
index 0000000..7990438
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/Makefile
@@ -0,0 +1,127 @@
+
+PROJ_FILE := $(shell ls *.ldf | head -1)
+PROJ_NAME := $(shell fgrep default_implementation ${PROJ_FILE} | cut -d'"' -f 4)
+IMPL_NAME := $(shell fgrep default_implementation ${PROJ_FILE} | cut -d'"' -f 8)
+IMPL_DIR := $(shell fgrep default_strategy ${PROJ_FILE} | cut -d'"' -f 4)
+
+DIAMOND_BASE := /usr/local/diamond
+DIAMOND_BIN := $(shell find ${DIAMOND_BASE}/ -maxdepth 2 -name bin | sort -rn | head -1)
+DIAMONDC := $(shell find ${DIAMOND_BIN}/ -name diamondc)
+DDTCMD := $(shell find ${DIAMOND_BIN}/ -name ddtcmd)
+
+OPENOCD_BASE := ../../programmer/openocd/ulx3s/
+
+# name of the project as defined in project file
+PROJECT = project
+
+# FPGA flashing device for programming
+FPGA_DEVICE = LFE5U-45F
+
+JUNK = ${IMPL_DIR} .recovery ._Real_._Math_.vhd *.sty reportview.xml
+JUNK += dummy_sym.sort project_tcl.html promote.xml
+JUNK += generate_core.tcl generate_ngd.tcl msg_file.log
+JUNK += project_tcr.dir
+
+all: $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_micron_32mbit.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_micron_32mbit.svf \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_spansion_64mbit.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_spansion_64mbit.svf
+
+$(PROJECT)/$(PROJECT)_$(PROJECT).bit:
+ echo prj_project open ${PROJ_FILE} \; prj_run Export -task Bitgen | ${DIAMONDC}
+
+# same file with different name required for multiboot to work
+$(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ cp $< $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_45f_sram.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_45f_sram.xcf -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT).mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit -oft -int -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_flash_micron_32mbit.vme: $(PROJECT)/$(PROJECT)_$(PROJECT).mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_45f_flash_micron_32mbit.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_flash_spansion_64mbit.vme: $(PROJECT)/$(PROJECT)_$(PROJECT).mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_45f_flash_spansion_64mbit.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_micron_32mbit.mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -oft -advanced -format int -flashsize 32 -header \
+ -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -golden $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -multi 1 -altfile $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit -address 0x200000 -next prim -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_micron_32mbit.vme: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_micron_32mbit.mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_45f_multiboot_micron_32mbit.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_micron_32mbit.svf: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_micron_32mbit.mcs
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_45f_multiboot_micron_32mbit.xcf -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_spansion_64mbit.mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit
+ dd if=/dev/zero of=/tmp/zero.bit bs=1k count=300
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -oft -advanced -format int -flashsize 64 -header \
+ -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -golden $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -multi 1 -altfile $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit -address 0x200000 -next prim -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_spansion_64mbit.vme: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_spansion_64mbit.mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_45f_multiboot_spansion_64mbit.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_spansion_64mbit.svf: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_spansion_64mbit.mcs
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_45f_multiboot_spansion_64mbit.xcf -of $@
+
+program: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ echo pgr_project open ulx3s_45f_sram.xcf \; pgr_program run | ${DIAMONDC}
+
+program_wifi: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ openocd --file=$(OPENOCD_BASE)/remote.ocd --file=$(OPENOCD_BASE)/ecp5-45f.ocd
+
+program_web: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ svfupload.py ulx3s.lan $<
+
+program_web_flash: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_micron_32mbit.svf
+ svfupload.py ulx3s.lan $<
+
+program_ft2232: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ openocd --file=$(OPENOCD_BASE)/ft2232-fpu1.ocd --file=$(OPENOCD_BASE)/ecp5-45f.ocd
+
+program_flea: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme
+ FleaFPGA-JTAG $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme
+
+program_flea_flash: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_micron_32mbit.vme
+ FleaFPGA-JTAG $<
+
+program_flea_flash_spansion: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_spansion_64mbit.vme
+ FleaFPGA-JTAG $<
+
+#$(PROJECT)/$(PROJECT)_$(PROJECT).jed:
+# echo prj_project open ${PROJ_FILE} \; prj_run Export -task Jedecgen | ${DIAMONDC}
+
+#$(PROJECT)/$(PROJECT)_$(PROJECT)_flash.vme: $(PROJECT)/$(PROJECT)_$(PROJECT).jed
+# ${DDTCMD} -oft -fullvme -if sparrowhawk_flash_micron_32mbit.xcf -nocompress -noheader -of $@
+
+#$(PROJECT)/$(PROJECT)_$(PROJECT)_flash.svf: $(PROJECT)/$(PROJECT)_$(PROJECT).jed
+# ${DDTCMD} -oft -svfsingle -op "FLASH Erase,Program,Verify" -if $< -of $@
+
+flash: $(PROJECT)/$(PROJECT)_$(PROJECT)_flash.vme
+ ${PROGRAMMERC} $<
+ # after this, to gain access to serial port on linux
+ # rmmod ftdi_sio; modprobe ftdi_sio
+
+# example another project
+#%.svf : %.jed
+# ${DDTCMD} -oft -svfsingle -op "FLASH Erase,Program,Verify" -if $< -of $@
+# mv -f $@ $@.flash
+# ${DDTCMD} -oft -svfsingle -revd -op "SRAM Fast Program" -if $< -of $@
+# mv -f $@ $@.sram
+# ./svf_to_urjtag.pl <$@.flash | sed 's/,/./g' > $@
+
+clean:
+ rm -rf $(JUNK) *~
diff --git a/boards/ulx3s-v1.7-45f-sp/bootloader.ldf b/boards/ulx3s-v1.7-45f-sp/bootloader.ldf
new file mode 100644
index 0000000..6467f47
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/bootloader.ldf
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-v1.7-45f-sp/clocks/clk_200M_48M.v b/boards/ulx3s-v1.7-45f-sp/clocks/clk_200M_48M.v
new file mode 100644
index 0000000..2e9bb80
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/clocks/clk_200M_48M.v
@@ -0,0 +1,75 @@
+/* Verilog netlist generated by SCUBA Diamond (64-bit) 3.7.0.96.1 */
+/* Module Version: 5.7 */
+/* /mt/lattice/diamond/3.7_x64/ispfpga/bin/lin64/scuba -w -n clk_200M_48M -lang verilog -synth synplify -bus_exp 7 -bb -arch sa5p00 -type pll -fin 200.00 -fclkop 48.00 -fclkop_tol 0.0 -phase_cntl STATIC -fb_mode 1 -fdc /home/guest/src/fpga/usbserial-core/TinyFPGA-Bootloader/boards/ulx3s/clock/clk_200M_48M/clk_200M_48M.fdc */
+/* Wed Jul 11 00:10:22 2018 */
+
+
+`timescale 1 ns / 1 ps
+module clk_200M_48M (CLKI, CLKOP, LOCK)/* synthesis NGD_DRC_MASK=1 */;
+ input wire CLKI;
+ output wire CLKOP;
+ output wire LOCK;
+
+ wire REFCLK;
+ wire CLKOP_t;
+ wire scuba_vhi;
+ wire scuba_vlo;
+
+ VHI scuba_vhi_inst (.Z(scuba_vhi));
+
+ VLO scuba_vlo_inst (.Z(scuba_vlo));
+
+ defparam PLLInst_0.PLLRST_ENA = "DISABLED" ;
+ defparam PLLInst_0.INTFB_WAKE = "DISABLED" ;
+ defparam PLLInst_0.STDBY_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.DPHASE_SOURCE = "DISABLED" ;
+ defparam PLLInst_0.CLKOS3_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS3_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_CPHASE = 11 ;
+ defparam PLLInst_0.PLL_LOCK_MODE = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.CLKOP_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOP_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXD = "DIVD" ;
+ defparam PLLInst_0.CLKOS3_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXC = "DIVC" ;
+ defparam PLLInst_0.CLKOS2_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXB = "DIVB" ;
+ defparam PLLInst_0.CLKOS_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXA = "DIVA" ;
+ defparam PLLInst_0.CLKOP_ENABLE = "ENABLED" ;
+ defparam PLLInst_0.CLKOS3_DIV = 1 ;
+ defparam PLLInst_0.CLKOS2_DIV = 1 ;
+ defparam PLLInst_0.CLKOS_DIV = 1 ;
+ defparam PLLInst_0.CLKOP_DIV = 12 ;
+ defparam PLLInst_0.CLKFB_DIV = 6 ;
+ defparam PLLInst_0.CLKI_DIV = 25 ;
+ defparam PLLInst_0.FEEDBK_PATH = "CLKOP" ;
+ EHXPLLL PLLInst_0 (.CLKI(CLKI), .CLKFB(CLKOP_t), .PHASESEL1(scuba_vlo),
+ .PHASESEL0(scuba_vlo), .PHASEDIR(scuba_vlo), .PHASESTEP(scuba_vlo),
+ .PHASELOADREG(scuba_vlo), .STDBY(scuba_vlo), .PLLWAKESYNC(scuba_vlo),
+ .RST(scuba_vlo), .ENCLKOP(scuba_vlo), .ENCLKOS(scuba_vlo), .ENCLKOS2(scuba_vlo),
+ .ENCLKOS3(scuba_vlo), .CLKOP(CLKOP_t), .CLKOS(), .CLKOS2(), .CLKOS3(),
+ .LOCK(LOCK), .INTLOCK(), .REFCLK(REFCLK), .CLKINTFB())
+ /* synthesis FREQUENCY_PIN_CLKOP="48.000000" */
+ /* synthesis FREQUENCY_PIN_CLKI="200.000000" */
+ /* synthesis ICP_CURRENT="5" */
+ /* synthesis LPF_RESISTOR="16" */;
+
+ assign CLKOP = CLKOP_t;
+
+
+ // exemplar begin
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKOP 48.000000
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKI 200.000000
+ // exemplar attribute PLLInst_0 ICP_CURRENT 5
+ // exemplar attribute PLLInst_0 LPF_RESISTOR 16
+ // exemplar end
+
+endmodule
diff --git a/boards/ulx3s-v1.7-45f-sp/clocks/clk_25M_200M.v b/boards/ulx3s-v1.7-45f-sp/clocks/clk_25M_200M.v
new file mode 100644
index 0000000..0ce5c18
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/clocks/clk_25M_200M.v
@@ -0,0 +1,75 @@
+/* Verilog netlist generated by SCUBA Diamond (64-bit) 3.7.0.96.1 */
+/* Module Version: 5.7 */
+/* /mt/lattice/diamond/3.7_x64/ispfpga/bin/lin64/scuba -w -n clk_25M_200M -lang verilog -synth synplify -bus_exp 7 -bb -arch sa5p00 -type pll -fin 25.00 -fclkop 200.00 -fclkop_tol 0.0 -phase_cntl STATIC -fb_mode 1 -fdc /home/guest/src/fpga/usbserial-core/TinyFPGA-Bootloader/boards/ulx3s/clock/clk_25M_200M/clk_25M_200M.fdc */
+/* Wed Jul 11 00:09:44 2018 */
+
+
+`timescale 1 ns / 1 ps
+module clk_25M_200M (CLKI, CLKOP)/* synthesis NGD_DRC_MASK=1 */;
+ input wire CLKI;
+ output wire CLKOP;
+
+ wire REFCLK;
+ wire LOCK;
+ wire CLKOP_t;
+ wire scuba_vhi;
+ wire scuba_vlo;
+
+ VHI scuba_vhi_inst (.Z(scuba_vhi));
+
+ VLO scuba_vlo_inst (.Z(scuba_vlo));
+
+ defparam PLLInst_0.PLLRST_ENA = "DISABLED" ;
+ defparam PLLInst_0.INTFB_WAKE = "DISABLED" ;
+ defparam PLLInst_0.STDBY_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.DPHASE_SOURCE = "DISABLED" ;
+ defparam PLLInst_0.CLKOS3_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS3_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_CPHASE = 2 ;
+ defparam PLLInst_0.PLL_LOCK_MODE = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.CLKOP_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOP_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXD = "DIVD" ;
+ defparam PLLInst_0.CLKOS3_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXC = "DIVC" ;
+ defparam PLLInst_0.CLKOS2_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXB = "DIVB" ;
+ defparam PLLInst_0.CLKOS_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXA = "DIVA" ;
+ defparam PLLInst_0.CLKOP_ENABLE = "ENABLED" ;
+ defparam PLLInst_0.CLKOS3_DIV = 1 ;
+ defparam PLLInst_0.CLKOS2_DIV = 1 ;
+ defparam PLLInst_0.CLKOS_DIV = 1 ;
+ defparam PLLInst_0.CLKOP_DIV = 3 ;
+ defparam PLLInst_0.CLKFB_DIV = 8 ;
+ defparam PLLInst_0.CLKI_DIV = 1 ;
+ defparam PLLInst_0.FEEDBK_PATH = "CLKOP" ;
+ EHXPLLL PLLInst_0 (.CLKI(CLKI), .CLKFB(CLKOP_t), .PHASESEL1(scuba_vlo),
+ .PHASESEL0(scuba_vlo), .PHASEDIR(scuba_vlo), .PHASESTEP(scuba_vlo),
+ .PHASELOADREG(scuba_vlo), .STDBY(scuba_vlo), .PLLWAKESYNC(scuba_vlo),
+ .RST(scuba_vlo), .ENCLKOP(scuba_vlo), .ENCLKOS(scuba_vlo), .ENCLKOS2(scuba_vlo),
+ .ENCLKOS3(scuba_vlo), .CLKOP(CLKOP_t), .CLKOS(), .CLKOS2(), .CLKOS3(),
+ .LOCK(LOCK), .INTLOCK(), .REFCLK(REFCLK), .CLKINTFB())
+ /* synthesis FREQUENCY_PIN_CLKOP="200.000000" */
+ /* synthesis FREQUENCY_PIN_CLKI="25.000000" */
+ /* synthesis ICP_CURRENT="5" */
+ /* synthesis LPF_RESISTOR="16" */;
+
+ assign CLKOP = CLKOP_t;
+
+
+ // exemplar begin
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKOP 200.000000
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKI 25.000000
+ // exemplar attribute PLLInst_0 ICP_CURRENT 5
+ // exemplar attribute PLLInst_0 LPF_RESISTOR 16
+ // exemplar end
+
+endmodule
diff --git a/boards/ulx3s-v1.7-45f-sp/constraints/ulx3s_v17patch.lpf b/boards/ulx3s-v1.7-45f-sp/constraints/ulx3s_v17patch.lpf
new file mode 100644
index 0000000..8e0d34c
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/constraints/ulx3s_v17patch.lpf
@@ -0,0 +1,435 @@
+BLOCK RESETPATHS;
+BLOCK ASYNCPATHS;
+## ULX3S v1.7 patched towards v1.8
+
+# The clock "usb" and "gpdi" sheet
+LOCATE COMP "clk_25mhz" SITE "G2";
+IOBUF PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33;
+FREQUENCY PORT "clk_25mhz" 25 MHZ;
+
+# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash
+SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 SLAVE_SPI_PORT=DISABLE MASTER_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE;
+
+## USBSERIAL FTDI-FPGA serial port "usb" sheet
+LOCATE COMP "ftdi_rxd" SITE "L4"; # FPGA transmits to ftdi
+LOCATE COMP "ftdi_txd" SITE "M1"; # FPGA receives from ftdi
+LOCATE COMP "ftdi_nrts" SITE "M3"; # FPGA receives
+LOCATE COMP "ftdi_ndtr" SITE "N1"; # FPGA receives
+LOCATE COMP "ftdi_txden" SITE "L3"; # FPGA receives
+IOBUF PORT "ftdi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "ftdi_txd" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_nrts" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_ndtr" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_txden" PULLMODE=UP IO_TYPE=LVCMOS33;
+
+## LED indicators "blinkey" and "gpio" sheet
+LOCATE COMP "led[7]" SITE "H3";
+LOCATE COMP "led[6]" SITE "E1";
+LOCATE COMP "led[5]" SITE "E2";
+LOCATE COMP "led[4]" SITE "D1";
+LOCATE COMP "led[3]" SITE "D2";
+LOCATE COMP "led[2]" SITE "C1";
+LOCATE COMP "led[1]" SITE "C2";
+LOCATE COMP "led[0]" SITE "B2";
+IOBUF PORT "led[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Pushbuttons "blinkey", "flash", "power", "gpdi" sheet
+LOCATE COMP "btn[0]" SITE "D6"; # BTN_PWRn (inverted logic)
+LOCATE COMP "btn[1]" SITE "R1"; # FIRE1
+LOCATE COMP "btn[2]" SITE "T1"; # FIRE2
+LOCATE COMP "btn[3]" SITE "W1"; # UP
+LOCATE COMP "btn[4]" SITE "V1"; # DOWN
+LOCATE COMP "btn[5]" SITE "U1"; # LEFT
+LOCATE COMP "btn[6]" SITE "Y2"; # RIGHT
+IOBUF PORT "btn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[4]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[5]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[6]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## DIP switch "blinkey", "gpio" sheet
+LOCATE COMP "sw[0]" SITE "E8"; # SW1
+LOCATE COMP "sw[1]" SITE "D8"; # SW2
+LOCATE COMP "sw[2]" SITE "D7"; # SW3
+LOCATE COMP "sw[3]" SITE "E7"; # SW4
+IOBUF PORT "sw[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI OLED DISPLAY SSD1331 (Color) or SSD1306 (B/W) "blinkey", "usb" sheet
+LOCATE COMP "oled_clk" SITE "P4";
+LOCATE COMP "oled_mosi" SITE "P3";
+LOCATE COMP "oled_dc" SITE "P1";
+LOCATE COMP "oled_resn" SITE "P2";
+LOCATE COMP "oled_csn" SITE "N2";
+IOBUF PORT "oled_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_dc" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_resn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI Flash chip "flash" sheet
+LOCATE COMP "flash_csn" SITE "R2";
+LOCATE COMP "flash_clk" SITE "U3";
+LOCATE COMP "flash_mosi" SITE "W2";
+LOCATE COMP "flash_miso" SITE "V2";
+#LOCATE COMP "flash_csspin" SITE "AJ3";
+#LOCATE COMP "flash_initn" SITE "AG4";
+#LOCATE COMP "flash_done" SITE "AJ4";
+#LOCATE COMP "flash_programn" SITE "AH4";
+#LOCATE COMP "flash_cfg_select[0]" SITE "AM4";
+#LOCATE COMP "flash_cfg_select[1]" SITE "AL4";
+#LOCATE COMP "flash_cfg_select[2]" SITE "AK4";
+IOBUF PORT "flash_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_clk" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_csspin" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_initn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SD card "sdcard", "usb" sheet
+LOCATE COMP "sd_clk" SITE "J1"; # sd_clk WiFi_GPIO14
+LOCATE COMP "sd_cmd" SITE "J3"; # sd_cmd_di (MOSI) WiFi GPIO15
+LOCATE COMP "sd_d[0]" SITE "K2"; # sd_dat0_do (MISO) WiFi GPIO2
+LOCATE COMP "sd_d[1]" SITE "K1"; # sd_dat1_irq WiFi GPIO4
+LOCATE COMP "sd_d[2]" SITE "H2"; # sd_dat2 WiFi_GPIO12
+LOCATE COMP "sd_d[3]" SITE "H1"; # sd_dat3_csn WiFi_GPIO13
+LOCATE COMP "sd_wp" SITE "P5"; # not connected
+LOCATE COMP "sd_cdn" SITE "N5"; # not connected
+IOBUF PORT "sd_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cmd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; # WiFi GPIO12 pulldown bootstrapping requirement
+IOBUF PORT "sd_d[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_wp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## ADC SPI (MAX11123) "analog", "ram" sheet
+LOCATE COMP "adc_csn" SITE "R17";
+LOCATE COMP "adc_mosi" SITE "R16";
+LOCATE COMP "adc_miso" SITE "U16";
+LOCATE COMP "adc_sclk" SITE "P17";
+IOBUF PORT "adc_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_sclk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Audio 4-bit DAC "analog", "gpio" sheet
+# 4-bit mode can drive down to 75 ohm load impedance.
+# Lower impedance leads to IO overload,
+# FPGA will stop working and need reboot.
+# For standard 17 ohm earphones:
+# use bits 2,3 as input (High-Z) and drive only bits 0,1.
+LOCATE COMP "audio_l[3]" SITE "B3"; # JACK TIP (left audio)
+LOCATE COMP "audio_l[2]" SITE "C3";
+LOCATE COMP "audio_l[1]" SITE "D3";
+LOCATE COMP "audio_l[0]" SITE "E4";
+LOCATE COMP "audio_r[3]" SITE "C5"; # JACK RING1 (right audio)
+LOCATE COMP "audio_r[2]" SITE "D5";
+LOCATE COMP "audio_r[1]" SITE "B5";
+LOCATE COMP "audio_r[0]" SITE "A3";
+LOCATE COMP "audio_v[3]" SITE "E5"; # JACK RING2 (video or digital audio)
+LOCATE COMP "audio_v[2]" SITE "F5";
+LOCATE COMP "audio_v[1]" SITE "F2";
+LOCATE COMP "audio_v[0]" SITE "H5";
+IOBUF PORT "audio_l[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## WiFi ESP-32 "wifi", "usb", "flash" sheet
+# other pins are shared with GP/GN, SD card and JTAG
+LOCATE COMP "wifi_en" SITE "F1"; # enable/reset WiFi
+LOCATE COMP "wifi_rxd" SITE "K3"; # FPGA transmits to WiFi
+LOCATE COMP "wifi_txd" SITE "K4"; # FPGA receives from WiFi
+LOCATE COMP "wifi_gpio0" SITE "L2";
+LOCATE COMP "wifi_gpio5" SITE "N4"; # WIFI LED
+LOCATE COMP "wifi_gpio16" SITE "L1";
+LOCATE COMP "wifi_gpio17" SITE "N3";
+# LOCATE COMP "prog_done" SITE "Y3"; # not GPIO, always active
+IOBUF PORT "wifi_en" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_txd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio16" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio17" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+# IOBUF PORT "prog_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## PCB antenna 433 MHz (may be also used for FM) "usb" sheet
+LOCATE COMP "ant_433mhz" SITE "G1";
+IOBUF PORT "ant_433mhz" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Second USB port going directly into FPGA "usb", "ram" sheet
+LOCATE COMP "usb_fpga_dp" SITE "E16";
+LOCATE COMP "usb_fpga_dn" SITE "F16";
+IOBUF PORT "usb_fpga_dp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## JTAG ESP-32 "usb" sheet
+# connected to FT231X and ESP-32
+# commented out because those are dedicated pins, not directly useable as GPIO
+# but could be used by some vendor-specific JTAG bridging (boundary scan) module
+#LOCATE COMP "jtag_tdi" SITE "R5"; # FTDI_nRI FPGA receives
+#LOCATE COMP "jtag_tdo" SITE "V4"; # FTDI_nCTS FPGA transmits
+#LOCATE COMP "jtag_tck" SITE "T5"; # FTDI_nDSR FPGA receives
+#LOCATE COMP "jtag_tms" SITE "U5"; # FTDI_nDCD FPGA receives
+#IOBUF PORT "jtag_tdi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tdo" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tck" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tms" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SDRAM "ram" sheet
+LOCATE COMP "sdram_clk" SITE "F19";
+LOCATE COMP "sdram_cke" SITE "F20";
+LOCATE COMP "sdram_csn" SITE "P20";
+LOCATE COMP "sdram_wen" SITE "T20";
+LOCATE COMP "sdram_rasn" SITE "R20";
+LOCATE COMP "sdram_casn" SITE "T19";
+LOCATE COMP "sdram_a[0]" SITE "M20";
+LOCATE COMP "sdram_a[1]" SITE "M19";
+LOCATE COMP "sdram_a[2]" SITE "L20";
+LOCATE COMP "sdram_a[3]" SITE "L19";
+LOCATE COMP "sdram_a[4]" SITE "K20";
+LOCATE COMP "sdram_a[5]" SITE "K19";
+LOCATE COMP "sdram_a[6]" SITE "K18";
+LOCATE COMP "sdram_a[7]" SITE "J20";
+LOCATE COMP "sdram_a[8]" SITE "J19";
+LOCATE COMP "sdram_a[9]" SITE "H20";
+LOCATE COMP "sdram_a[10]" SITE "N19";
+LOCATE COMP "sdram_a[11]" SITE "G20";
+LOCATE COMP "sdram_a[12]" SITE "G19";
+LOCATE COMP "sdram_ba[0]" SITE "P19";
+LOCATE COMP "sdram_ba[1]" SITE "N20";
+LOCATE COMP "sdram_dqm[0]" SITE "U19";
+LOCATE COMP "sdram_dqm[1]" SITE "E20";
+LOCATE COMP "sdram_d[0]" SITE "J16";
+LOCATE COMP "sdram_d[1]" SITE "L18";
+LOCATE COMP "sdram_d[2]" SITE "M18";
+LOCATE COMP "sdram_d[3]" SITE "N18";
+LOCATE COMP "sdram_d[4]" SITE "P18";
+LOCATE COMP "sdram_d[5]" SITE "T18";
+LOCATE COMP "sdram_d[6]" SITE "T17";
+LOCATE COMP "sdram_d[7]" SITE "U20";
+LOCATE COMP "sdram_d[8]" SITE "E19";
+LOCATE COMP "sdram_d[9]" SITE "D20";
+LOCATE COMP "sdram_d[10]" SITE "D19";
+LOCATE COMP "sdram_d[11]" SITE "C20";
+LOCATE COMP "sdram_d[12]" SITE "E18";
+LOCATE COMP "sdram_d[13]" SITE "F18";
+LOCATE COMP "sdram_d[14]" SITE "J18";
+LOCATE COMP "sdram_d[15]" SITE "J17";
+IOBUF PORT "sdram_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_cke" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_wen" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_rasn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_casn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[13]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[14]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[15]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPDI differential interface (Video) "gpdi" sheet
+LOCATE COMP "gpdi_dp[0]" SITE "A16"; # Blue +
+LOCATE COMP "gpdi_dn[0]" SITE "B16"; # Blue -
+LOCATE COMP "gpdi_dp[1]" SITE "A14"; # Green +
+LOCATE COMP "gpdi_dn[1]" SITE "C14"; # Green -
+LOCATE COMP "gpdi_dp[2]" SITE "A12"; # Red +
+LOCATE COMP "gpdi_dn[2]" SITE "A13"; # Read +
+LOCATE COMP "gpdi_ethp" SITE "A19"; # Ethernet +
+LOCATE COMP "gpdi_ethn" SITE "B20"; # Ethernet -
+LOCATE COMP "gpdi_clkp" SITE "A17"; # Clock +
+LOCATE COMP "gpdi_clkn" SITE "B18"; # Clock -
+LOCATE COMP "gpdi_cec" SITE "A18";
+LOCATE COMP "gpdi_sda" SITE "B19"; # I2C shared with RTC
+LOCATE COMP "gpdi_scl" SITE "C12"; # I2C shared with RTC
+IOBUF PORT "gpdi_dp[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_clkp" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_clkn" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethp" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethn" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_cec" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_sda" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_scl" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPIO (default single-ended) "gpio", "ram", "gpdi" sheet
+# Pins enumerated gp[0-27], gn[0-27].
+# With differential mode enabled on Lattice,
+# gp[] (+) are used, gn[] (-) are ignored from design
+# as they handle inverted signal by default.
+# To enable differential, rename LVCMOS33->LVCMOS33D
+LOCATE COMP "gp[0]" SITE "B11"; # J1_5+ GP0
+LOCATE COMP "gn[0]" SITE "C11"; # J1_5- GN0
+LOCATE COMP "gp[1]" SITE "A10"; # J1_7+ GP1
+LOCATE COMP "gn[1]" SITE "A11"; # J1_7- GN1
+LOCATE COMP "gp[2]" SITE "A9"; # J1_9+ GP2
+LOCATE COMP "gn[2]" SITE "B10"; # J1_9- GN2
+LOCATE COMP "gp[3]" SITE "B9"; # J1_11+ GP3
+LOCATE COMP "gn[3]" SITE "C10"; # J1_11- GN3
+LOCATE COMP "gp[4]" SITE "A7"; # J1_13+ GP4
+LOCATE COMP "gn[4]" SITE "A8"; # J1_13- GN4
+LOCATE COMP "gp[5]" SITE "C8"; # J1_15+ GP5
+LOCATE COMP "gn[5]" SITE "B8"; # J1_15- GN5
+LOCATE COMP "gp[6]" SITE "C6"; # J1_17+ GP6
+LOCATE COMP "gn[6]" SITE "C7"; # J1_17- GN6
+IOBUF PORT "gp[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[7]" SITE "A6"; # J1_23+ GP7
+LOCATE COMP "gn[7]" SITE "B6"; # J1_23- GN7
+LOCATE COMP "gp[8]" SITE "A4"; # J1_25+ GP8
+LOCATE COMP "gn[8]" SITE "A5"; # J1_25- GN8
+LOCATE COMP "gp[9]" SITE "A2"; # J1_27+ GP9
+LOCATE COMP "gn[9]" SITE "B1"; # J1_27- GN9
+LOCATE COMP "gp[10]" SITE "C4"; # J1_29+ GP10 WIFI_GPIO27
+LOCATE COMP "gn[10]" SITE "B4"; # J1_29- GN10
+LOCATE COMP "gp[11]" SITE "F4"; # J1_31+ GP11 WIFI_GPIO25
+LOCATE COMP "gn[11]" SITE "E3"; # J1_31- GN11 WIFI_GPIO26
+LOCATE COMP "gp[12]" SITE "G3"; # J1_33+ GP12 WIFI_GPIO32
+LOCATE COMP "gn[12]" SITE "F3"; # J1_33- GN12 WIFI_GPIO33
+LOCATE COMP "gp[13]" SITE "H4"; # J1_35+ GP13 WIFI_GPIO34
+LOCATE COMP "gn[13]" SITE "G5"; # J1_35- GN13 WIFI_GPIO35
+IOBUF PORT "gp[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[14]" SITE "U18"; # J2_5+ GP14
+LOCATE COMP "gn[14]" SITE "U17"; # J2_5- GN14
+LOCATE COMP "gp[15]" SITE "N17"; # J2_7+ GP15
+LOCATE COMP "gn[15]" SITE "P16"; # J2_7- GN15
+LOCATE COMP "gp[16]" SITE "N16"; # J2_9+ GP16
+LOCATE COMP "gn[16]" SITE "M17"; # J2_9- GN16
+LOCATE COMP "gp[17]" SITE "L16"; # J2_11+ GP17
+LOCATE COMP "gn[17]" SITE "L17"; # J2_11- GN17
+LOCATE COMP "gp[18]" SITE "H18"; # J2_13+ GP18
+LOCATE COMP "gn[18]" SITE "H17"; # J2_13- GN18
+LOCATE COMP "gp[19]" SITE "F17"; # J2_15+ GP19
+LOCATE COMP "gn[19]" SITE "G18"; # J2_15- GN19
+LOCATE COMP "gp[20]" SITE "D18"; # J2_17+ GP20
+LOCATE COMP "gn[20]" SITE "E17"; # J2_17- GN20
+IOBUF PORT "gp[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[21]" SITE "C18"; # J2_23+ GP21
+LOCATE COMP "gn[21]" SITE "D17"; # J2_23- GN21
+LOCATE COMP "gp[22]" SITE "D15"; # J2_25+ GP22
+LOCATE COMP "gn[22]" SITE "E15"; # J2_25- GN22
+LOCATE COMP "gp[23]" SITE "B17"; # J2_27+ GP23
+LOCATE COMP "gn[23]" SITE "C17"; # J2_27- GN23
+LOCATE COMP "gp[24]" SITE "C16"; # J2_29+ GP24
+LOCATE COMP "gn[24]" SITE "D16"; # J2_29- GN24
+LOCATE COMP "gp[25]" SITE "B15"; # J2_31+ GP25
+LOCATE COMP "gn[25]" SITE "C15"; # J2_31- GN25
+LOCATE COMP "gp[26]" SITE "B13"; # J2_33+ GP26
+LOCATE COMP "gn[26]" SITE "C13"; # J2_33- GN26
+LOCATE COMP "gp[27]" SITE "D13"; # J2_35+ GP27
+LOCATE COMP "gn[27]" SITE "E13"; # J2_35- GN27
+IOBUF PORT "gp[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SHUTDOWN "power", "ram" sheet (connected from PCB v1.7.5)
+# on PCB v1.7 shutdown is not connected to FPGA
+LOCATE COMP "shutdown" SITE "G16"; # FPGA receives
+IOBUF PORT "shutdown" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
diff --git a/boards/ulx3s-v1.7-45f-sp/initialize/boardmeta4MB.bin b/boards/ulx3s-v1.7-45f-sp/initialize/boardmeta4MB.bin
new file mode 100644
index 0000000..7a525c7
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/initialize/boardmeta4MB.bin
@@ -0,0 +1,119 @@
+{
+ "boardmeta":
+ {
+ "name": "ULX3S",
+ "fpga": "LFE5U-45F-6BG381C",
+ "hver": "1.7",
+ "uuid": "00000000-0000-0000-0000-000000000000",
+ "serial": 12345
+ },
+ "bootmeta":
+ {
+ "bootloader": "TinyFPGA USB Bootloader",
+ "bver": "2.0.0",
+ "update": "https://github.com/emard/TinyFPGA-Bootloader",
+ "addrmap":
+ {
+ "bootloader": "0x000000-0x0FFFFF",
+ "golden": "0x100000-0x1FFFFF",
+ "userimage": "0x200000-0x2FFFFF",
+ "userdata": "0x300000-0x3FBFFF"
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-v1.7-45f-sp/initialize/boardmeta8MB.bin b/boards/ulx3s-v1.7-45f-sp/initialize/boardmeta8MB.bin
new file mode 100644
index 0000000..89be03c
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/initialize/boardmeta8MB.bin
@@ -0,0 +1,58 @@
+{
+ "boardmeta":
+ {
+ "name": "ULX3S",
+ "fpga": "LFE5U-45F-6BG381C",
+ "hver": "1.7",
+ "uuid": "00000000-0000-0000-0000-000000000000",
+ "serial": 12345
+ },
+ "bootmeta":
+ {
+ "bootloader": "TinyFPGA USB Bootloader",
+ "bver": "2.0.0",
+ "update": "https://github.com/emard/TinyFPGA-Bootloader",
+ "addrmap":
+ {
+ "bootloader": "0x000000-0x0FFFFF",
+ "golden": "0x100000-0x1FFFFF",
+ "userimage": "0x200000-0x3FFFFF",
+ "userdata": "0x500000-0x7FBFFF"
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-v1.7-45f-sp/initialize/initialize4MB.sh b/boards/ulx3s-v1.7-45f-sp/initialize/initialize4MB.sh
new file mode 100755
index 0000000..3d67d93
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/initialize/initialize4MB.sh
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+
+# Initializer for ECP5 dual boot.
+
+# first half of the FLASH is for user bitstram
+# bootloader bitstream starts at second half of the FLASH
+# board metadata at last 0x1000 bytes
+# Jump command at last 0x100 bytes
+
+# flash size: 16 Mbit = 2 MB = 0x200000
+# flash size: 32 Mbit = 4 MB = 0x400000
+# flash size: 64 Mbit = 8 MB = 0x800000
+# flash size: 128 Mbit = 16 MB = 0x1000000
+
+bootloader_image_address=$(printf "%d" 0x000000) # 0
+golden_image_address=$(printf "%d" 0x100000) # 0x100000 (1MB) (backup of bootloader)
+board_meta_address=$(printf "%d" 0x3FF000) # flash size - 0x1000
+jump_command_address=$(printf "%d" 0x3FFF00) # flash size - 0x100
+
+# primary image must be generated by diamond deployment tool (ddtcmd)
+# simply overwriting bootloader image will not have multiboot capability
+#tinyprog --pyserial --no-boot -a $bootloader_image_address -u ../../boards/ulx3s-v1.7-45f/tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $golden_image_address -u ../tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $(printf "%d" $board_meta_address) -u boardmeta4MB.bin
+./jump.py $golden_image_address > jump.bin
+tinyprog --pyserial --no-boot -a $(printf "%d" $jump_command_address) -u jump.bin
+# hexdump -C jump.bin
+# check that's board is recognized by tingprog
+tinyprog --pyserial -l
+#tinyprog -m
diff --git a/boards/ulx3s-v1.7-45f-sp/initialize/initialize8MB.sh b/boards/ulx3s-v1.7-45f-sp/initialize/initialize8MB.sh
new file mode 100755
index 0000000..b127f53
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/initialize/initialize8MB.sh
@@ -0,0 +1,31 @@
+#!/bin/sh -e
+
+# Initializer for ECP5 dual boot.
+
+# first half of the FLASH is for user bitstram
+# bootloader bitstream starts at second half of the FLASH
+# board metadata at last 0x1000 bytes
+# Jump command at last 0x100 bytes
+
+# flash size: 8 Mbit = 1 MB = 0x100000
+# flash size: 16 Mbit = 2 MB = 0x200000
+# flash size: 32 Mbit = 4 MB = 0x400000
+# flash size: 64 Mbit = 8 MB = 0x800000
+# flash size: 128 Mbit = 16 MB = 0x1000000
+
+bootloader_image_address=$(printf "%d" 0x000000) # 0
+golden_image_address=$(printf "%d" 0x100000) # 0x100000 (1MB) (backup of bootloader)
+board_meta_address=$(printf "%d" 0x7FF000) # flash size - 0x1000 (-4KB)
+jump_command_address=$(printf "%d" 0x7FFF00) # flash size - 0x100 (-256)
+
+# primary image must be generated by diamond deployment tool (ddtcmd)
+# simply overwriting bootloader image will not have multiboot capability
+#tinyprog --pyserial --no-boot -a $bootloader_image_address -u ../../boards/ulx3s-v1.7-45f/tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $golden_image_address -u ../tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $(printf "%d" $board_meta_address) -u boardmeta8MB.bin
+./jump.py $golden_image_address > jump.bin
+tinyprog --pyserial --no-boot -a $(printf "%d" $jump_command_address) -u jump.bin
+# hexdump -C jump.bin
+# check that's board is recognized by tingprog
+tinyprog --pyserial -l
+#tinyprog -m
diff --git a/boards/ulx3s-v1.7-45f-sp/initialize/jump.bin b/boards/ulx3s-v1.7-45f-sp/initialize/jump.bin
new file mode 100644
index 0000000..d39691f
Binary files /dev/null and b/boards/ulx3s-v1.7-45f-sp/initialize/jump.bin differ
diff --git a/boards/ulx3s-v1.7-45f-sp/initialize/jump.py b/boards/ulx3s-v1.7-45f-sp/initialize/jump.py
new file mode 100755
index 0000000..b1ff948
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/initialize/jump.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+
+# Lattice ECP5 jump command generator
+# TN1216 p.23 describes the jump command syntax which does not work.
+# The syntax has been fixed by looking at dual boot intel hex file
+# generated by diamond, this actually works.
+
+import struct
+import sys
+
+# write output of this funtion at FLASH address:
+# jump_command_address = 0x3FFF00 = 4194048
+
+# write "golden" bitstream at FLASH address:
+golden_image_address = 0x140000
+golden_image_address = int(sys.argv[1])
+
+# normally both 0
+reverse_bytes = 0
+reverse_bits = 0
+
+# to compare with intel HEX file generated by diamond:
+# (not for normal use)
+# reverse_bytes = 1
+# reverse_bits = 1
+# ./jump.py | hexdump -C
+
+def reverse_Bits(n, no_of_bits):
+ result = 0
+ for i in range(no_of_bits):
+ result <<= 1
+ result |= n & 1
+ n >>= 1
+ return result
+
+def uint8(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 8)
+ return struct.pack(">B", n)
+
+def uint16(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 16)
+ if reverse_bytes:
+ return struct.pack("H", n)
+
+def uint24(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 24)
+ if reverse_bytes:
+ return struct.pack("> 8 )
+ else:
+ return struct.pack(">HB", n >> 8, n & 0xFF )
+
+def uint32(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 32)
+ if reverse_bytes:
+ return struct.pack("L", n)
+
+packet = b''
+# Frame (START) 18 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint16(0xFFFF) # 2 dummy bytes (diamond generates this 2 bytes more)
+# Preamble
+packet += uint16(0xBDB3) # Preamble
+# Frame (Control Register 0) commented out, diamond doesn't output this
+# if uncommented, jump won't work:
+#packet += uint8(0xC4) # Write control register 0 command
+#packet += uint24(0) # 24-bit Command Information
+#packet += uint32(0) # Control Register 0 data
+# This is generated by diamond:
+packet += uint32(0xFFFFFFFF) # I don't know what it does but it works
+# Framme (Jump Command)
+#packet += uint8(0xFE) # Jump command Wrong noted in TN1216
+packet += uint8(0x7E) # Jump command generated by diamond
+packet += uint24(0) # 24-bit Command Information
+packet += uint8(0x03) # SPI Flash Read opcode (0x03 = regular read, 0x0B = fast read)
+packet += uint24(golden_image_address) # 24-bit SPI Flash Sector X address
+# Frame (END) 18 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint16(0xFFFF) # 2 dummy bytes (diamond generates this 2 bytes more)
+
+sys.stdout.write(packet)
+# print([elem.encode("hex") for elem in packet])
diff --git a/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k.bit b/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k.bit
new file mode 120000
index 0000000..59e9556
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k.bit
@@ -0,0 +1 @@
+project/project_project.bit
\ No newline at end of file
diff --git a/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k_multiboot_flash_micron_32mbit.svf b/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k_multiboot_flash_micron_32mbit.svf
new file mode 120000
index 0000000..623c0d8
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k_multiboot_flash_micron_32mbit.svf
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_micron_32mbit.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k_multiboot_flash_micron_32mbit.vme b/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k_multiboot_flash_micron_32mbit.vme
new file mode 120000
index 0000000..bc0382a
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k_multiboot_flash_micron_32mbit.vme
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_micron_32mbit.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k_multiboot_flash_spansion_64mbit.svf b/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k_multiboot_flash_spansion_64mbit.svf
new file mode 120000
index 0000000..2c6afa4
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k_multiboot_flash_spansion_64mbit.svf
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_spansion_64mbit.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k_multiboot_flash_spansion_64mbit.vme b/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k_multiboot_flash_spansion_64mbit.vme
new file mode 120000
index 0000000..9e1e580
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k_multiboot_flash_spansion_64mbit.vme
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_spansion_64mbit.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k_sram.svf b/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k_sram.svf
new file mode 120000
index 0000000..bb7617d
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k_sram.svf
@@ -0,0 +1 @@
+project/project_project_sram.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k_sram.vme b/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k_sram.vme
new file mode 120000
index 0000000..d098048
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/tinyfpga_45k_sram.vme
@@ -0,0 +1 @@
+project/project_project_sram.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v1.7-45f-sp/top/bootloader_sp_ulx3s.v b/boards/ulx3s-v1.7-45f-sp/top/bootloader_sp_ulx3s.v
new file mode 100644
index 0000000..3aad1a4
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/top/bootloader_sp_ulx3s.v
@@ -0,0 +1,128 @@
+module bootloader_sp_ulx3s (
+ input clk_25mhz,
+
+ inout usb_fpga_dp,
+ inout usb_fpga_dn,
+
+ output [7:0] led,
+
+ input flash_miso,
+ output flash_mosi,
+ output flash_clk,
+ output flash_csn,
+
+ input [6:0] btn,
+ output wifi_gpio0
+);
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// generate 48 mhz clock
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ wire clk_200mhz;
+ clk_25M_200M clk_200M_inst (
+ .CLKI(clk_25mhz),
+ .CLKOP(clk_200mhz)
+ );
+
+ wire clk_48mhz;
+ wire clk_ready;
+ clk_200M_48M clk_48M_inst (
+ .CLKI(clk_200mhz),
+ .CLKOP(clk_48mhz),
+ .LOCK(clk_ready)
+ );
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// instantiate tinyfpga bootloader
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ reg [15:0] reset_counter = 0; // counter for debouce and prolong reset
+ wire reset;
+ assign reset = ~reset_counter[15];
+ wire usb_p_tx;
+ wire usb_n_tx;
+ wire usb_p_rx;
+ wire usb_n_rx;
+ wire usb_tx_en;
+ wire pin_led;
+ wire [7:0] debug_led;
+ wire boot;
+ wire S_flash_clk;
+ wire S_flash_csn;
+
+ tinyfpgasp_bootloader tinyfpgasp_bootloader_inst (
+ .clk_48mhz(clk_48mhz),
+ .reset(reset),
+ .usb_p_tx(usb_p_tx),
+ .usb_n_tx(usb_n_tx),
+ .usb_p_rx(usb_p_rx),
+ .usb_n_rx(usb_n_rx),
+ .usb_tx_en(usb_tx_en),
+ .led(pin_led),
+ .debug_led(debug_led),
+ .spi_miso(flash_miso),
+ .spi_mosi(flash_mosi),
+ .spi_sck(S_flash_clk),
+ .spi_cs(S_flash_csn),
+ .boot(boot)
+ );
+
+ assign usb_fpga_dp = reset ? 1'b0 : (usb_tx_en ? usb_p_tx : 1'bz);
+ assign usb_fpga_dn = reset ? 1'b0 : (usb_tx_en ? usb_n_tx : 1'bz);
+ assign usb_p_rx = usb_tx_en ? 1'b1 : usb_fpga_dp;
+ assign usb_n_rx = usb_tx_en ? 1'b0 : usb_fpga_dn;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// Vendor-specific clock output to SPI config flash
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ USRMCLK usrmclk_inst (
+ .USRMCLKI(S_flash_clk),
+ .USRMCLKTS(S_flash_csn)
+ ) /* synthesis syn_noprune=1 */;
+ assign flash_clk = S_flash_clk;
+ assign flash_csn = S_flash_csn;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// Debonuce and prolong RESET
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ always @(posedge clk_48mhz)
+ begin
+ if (btn[1] | ~clk_ready)
+ reset_counter <= 0;
+ else
+ if (reset_counter[15] == 0)
+ reset_counter <= reset_counter + 1;
+ end
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// ULX3S board buttons and LEDs
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ assign wifi_gpio0 = btn[0];
+ assign led[0] = pin_led;
+ assign led[1] = ~pin_led;
+ assign led[5] = debug_led;
+ assign led[7] = boot;
+ // assign led[3:0] = {flash_miso, flash_mosi, S_flash_clk, S_flash_csn};
+
+
+endmodule
diff --git a/boards/ulx3s-v1.7-45f-sp/ulx3s_45f_flash_micron_32mbit.xcf b/boards/ulx3s-v1.7-45f-sp/ulx3s_45f_flash_micron_32mbit.xcf
new file mode 100644
index 0000000..965834b
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/ulx3s_45f_flash_micron_32mbit.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-45F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-45F
+ 0x41112043
+ All
+ LFE5U-45F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ Micron
+ SPI Serial Flash
+ SPI-M25P32
+ 0x15
+ 8-pin VDFPN8
+ SPI Flash Erase,Program
+ project/project_project.mcs
+ 0x00000000
+ 0x00400000
+ 32
+ 4194304
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v1.7-45f-sp/ulx3s_45f_flash_spansion_64mbit.xcf b/boards/ulx3s-v1.7-45f-sp/ulx3s_45f_flash_spansion_64mbit.xcf
new file mode 100644
index 0000000..aedb695
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/ulx3s_45f_flash_spansion_64mbit.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-45F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-45F
+ 0x41112043
+ All
+ LFE5U-45F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ SPANSION
+ SPI Serial Flash
+ SPI-S25FL164K
+ 0x16
+ 8-lead SOIC
+ SPI Flash Erase,Program
+ project/project_project.mcs
+ 0x00000000
+ 0x00100000
+ 64
+ 8388608
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v1.7-45f-sp/ulx3s_45f_multiboot_micron_32mbit.xcf b/boards/ulx3s-v1.7-45f-sp/ulx3s_45f_multiboot_micron_32mbit.xcf
new file mode 100644
index 0000000..3109f0d
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/ulx3s_45f_multiboot_micron_32mbit.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-45F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project_multiboot_flash_micron_32mbit.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-45F
+ 0x41112043
+ All
+ LFE5U-45F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ Micron
+ SPI Serial Flash
+ SPI-M25P32
+ 0x15
+ 8-pin VDFPN8
+ SPI Flash Erase,Program
+ project/project_project_multiboot_flash_micron_32mbit.mcs
+ 0x00000000
+ 0x00400000
+ 32
+ 4194304
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project_multiboot_flash_micron_32mbit.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v1.7-45f-sp/ulx3s_45f_multiboot_spansion_64mbit.xcf b/boards/ulx3s-v1.7-45f-sp/ulx3s_45f_multiboot_spansion_64mbit.xcf
new file mode 100644
index 0000000..9daeac4
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/ulx3s_45f_multiboot_spansion_64mbit.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-45F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project_multiboot_flash_spansion_64mbit.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-45F
+ 0x41112043
+ All
+ LFE5U-45F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ SPANSION
+ SPI Serial Flash
+ SPI-S25FL164K
+ 0x16
+ 8-lead SOIC
+ SPI Flash Erase,Program
+ project/project_project_multiboot_flash_spansion_64mbit.mcs
+ 0x00000000
+ 0x00800000
+ 64
+ 8388608
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project_multiboot_flash_spansion_64mbit.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v1.7-45f-sp/ulx3s_45f_sram.xcf b/boards/ulx3s-v1.7-45f-sp/ulx3s_45f_sram.xcf
new file mode 100644
index 0000000..b11ed78
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f-sp/ulx3s_45f_sram.xcf
@@ -0,0 +1,48 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5UM
+ LFE5U-45F
+ 0x41112043
+ All
+ LFE5U-45F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project.bit
+ Fast Program
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ DUAL RS232-HS A Location 0000 Serial Dual RS232-HS A
+
+
diff --git a/boards/ulx3s-v1.7-45f/Makefile b/boards/ulx3s-v1.7-45f/Makefile
new file mode 100644
index 0000000..7990438
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/Makefile
@@ -0,0 +1,127 @@
+
+PROJ_FILE := $(shell ls *.ldf | head -1)
+PROJ_NAME := $(shell fgrep default_implementation ${PROJ_FILE} | cut -d'"' -f 4)
+IMPL_NAME := $(shell fgrep default_implementation ${PROJ_FILE} | cut -d'"' -f 8)
+IMPL_DIR := $(shell fgrep default_strategy ${PROJ_FILE} | cut -d'"' -f 4)
+
+DIAMOND_BASE := /usr/local/diamond
+DIAMOND_BIN := $(shell find ${DIAMOND_BASE}/ -maxdepth 2 -name bin | sort -rn | head -1)
+DIAMONDC := $(shell find ${DIAMOND_BIN}/ -name diamondc)
+DDTCMD := $(shell find ${DIAMOND_BIN}/ -name ddtcmd)
+
+OPENOCD_BASE := ../../programmer/openocd/ulx3s/
+
+# name of the project as defined in project file
+PROJECT = project
+
+# FPGA flashing device for programming
+FPGA_DEVICE = LFE5U-45F
+
+JUNK = ${IMPL_DIR} .recovery ._Real_._Math_.vhd *.sty reportview.xml
+JUNK += dummy_sym.sort project_tcl.html promote.xml
+JUNK += generate_core.tcl generate_ngd.tcl msg_file.log
+JUNK += project_tcr.dir
+
+all: $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_micron_32mbit.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_micron_32mbit.svf \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_spansion_64mbit.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_spansion_64mbit.svf
+
+$(PROJECT)/$(PROJECT)_$(PROJECT).bit:
+ echo prj_project open ${PROJ_FILE} \; prj_run Export -task Bitgen | ${DIAMONDC}
+
+# same file with different name required for multiboot to work
+$(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ cp $< $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_45f_sram.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_45f_sram.xcf -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT).mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit -oft -int -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_flash_micron_32mbit.vme: $(PROJECT)/$(PROJECT)_$(PROJECT).mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_45f_flash_micron_32mbit.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_flash_spansion_64mbit.vme: $(PROJECT)/$(PROJECT)_$(PROJECT).mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_45f_flash_spansion_64mbit.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_micron_32mbit.mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -oft -advanced -format int -flashsize 32 -header \
+ -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -golden $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -multi 1 -altfile $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit -address 0x200000 -next prim -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_micron_32mbit.vme: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_micron_32mbit.mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_45f_multiboot_micron_32mbit.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_micron_32mbit.svf: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_micron_32mbit.mcs
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_45f_multiboot_micron_32mbit.xcf -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_spansion_64mbit.mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit
+ dd if=/dev/zero of=/tmp/zero.bit bs=1k count=300
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -oft -advanced -format int -flashsize 64 -header \
+ -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -golden $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -multi 1 -altfile $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit -address 0x200000 -next prim -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_spansion_64mbit.vme: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_spansion_64mbit.mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_45f_multiboot_spansion_64mbit.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_spansion_64mbit.svf: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_spansion_64mbit.mcs
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_45f_multiboot_spansion_64mbit.xcf -of $@
+
+program: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ echo pgr_project open ulx3s_45f_sram.xcf \; pgr_program run | ${DIAMONDC}
+
+program_wifi: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ openocd --file=$(OPENOCD_BASE)/remote.ocd --file=$(OPENOCD_BASE)/ecp5-45f.ocd
+
+program_web: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ svfupload.py ulx3s.lan $<
+
+program_web_flash: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_micron_32mbit.svf
+ svfupload.py ulx3s.lan $<
+
+program_ft2232: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ openocd --file=$(OPENOCD_BASE)/ft2232-fpu1.ocd --file=$(OPENOCD_BASE)/ecp5-45f.ocd
+
+program_flea: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme
+ FleaFPGA-JTAG $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme
+
+program_flea_flash: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_micron_32mbit.vme
+ FleaFPGA-JTAG $<
+
+program_flea_flash_spansion: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_spansion_64mbit.vme
+ FleaFPGA-JTAG $<
+
+#$(PROJECT)/$(PROJECT)_$(PROJECT).jed:
+# echo prj_project open ${PROJ_FILE} \; prj_run Export -task Jedecgen | ${DIAMONDC}
+
+#$(PROJECT)/$(PROJECT)_$(PROJECT)_flash.vme: $(PROJECT)/$(PROJECT)_$(PROJECT).jed
+# ${DDTCMD} -oft -fullvme -if sparrowhawk_flash_micron_32mbit.xcf -nocompress -noheader -of $@
+
+#$(PROJECT)/$(PROJECT)_$(PROJECT)_flash.svf: $(PROJECT)/$(PROJECT)_$(PROJECT).jed
+# ${DDTCMD} -oft -svfsingle -op "FLASH Erase,Program,Verify" -if $< -of $@
+
+flash: $(PROJECT)/$(PROJECT)_$(PROJECT)_flash.vme
+ ${PROGRAMMERC} $<
+ # after this, to gain access to serial port on linux
+ # rmmod ftdi_sio; modprobe ftdi_sio
+
+# example another project
+#%.svf : %.jed
+# ${DDTCMD} -oft -svfsingle -op "FLASH Erase,Program,Verify" -if $< -of $@
+# mv -f $@ $@.flash
+# ${DDTCMD} -oft -svfsingle -revd -op "SRAM Fast Program" -if $< -of $@
+# mv -f $@ $@.sram
+# ./svf_to_urjtag.pl <$@.flash | sed 's/,/./g' > $@
+
+clean:
+ rm -rf $(JUNK) *~
diff --git a/boards/ulx3s-v1.7-45f/bootloader.ldf b/boards/ulx3s-v1.7-45f/bootloader.ldf
new file mode 100644
index 0000000..b725c28
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/bootloader.ldf
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-v1.7-45f/clocks/clk_200M_48M.v b/boards/ulx3s-v1.7-45f/clocks/clk_200M_48M.v
new file mode 100644
index 0000000..2e9bb80
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/clocks/clk_200M_48M.v
@@ -0,0 +1,75 @@
+/* Verilog netlist generated by SCUBA Diamond (64-bit) 3.7.0.96.1 */
+/* Module Version: 5.7 */
+/* /mt/lattice/diamond/3.7_x64/ispfpga/bin/lin64/scuba -w -n clk_200M_48M -lang verilog -synth synplify -bus_exp 7 -bb -arch sa5p00 -type pll -fin 200.00 -fclkop 48.00 -fclkop_tol 0.0 -phase_cntl STATIC -fb_mode 1 -fdc /home/guest/src/fpga/usbserial-core/TinyFPGA-Bootloader/boards/ulx3s/clock/clk_200M_48M/clk_200M_48M.fdc */
+/* Wed Jul 11 00:10:22 2018 */
+
+
+`timescale 1 ns / 1 ps
+module clk_200M_48M (CLKI, CLKOP, LOCK)/* synthesis NGD_DRC_MASK=1 */;
+ input wire CLKI;
+ output wire CLKOP;
+ output wire LOCK;
+
+ wire REFCLK;
+ wire CLKOP_t;
+ wire scuba_vhi;
+ wire scuba_vlo;
+
+ VHI scuba_vhi_inst (.Z(scuba_vhi));
+
+ VLO scuba_vlo_inst (.Z(scuba_vlo));
+
+ defparam PLLInst_0.PLLRST_ENA = "DISABLED" ;
+ defparam PLLInst_0.INTFB_WAKE = "DISABLED" ;
+ defparam PLLInst_0.STDBY_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.DPHASE_SOURCE = "DISABLED" ;
+ defparam PLLInst_0.CLKOS3_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS3_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_CPHASE = 11 ;
+ defparam PLLInst_0.PLL_LOCK_MODE = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.CLKOP_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOP_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXD = "DIVD" ;
+ defparam PLLInst_0.CLKOS3_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXC = "DIVC" ;
+ defparam PLLInst_0.CLKOS2_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXB = "DIVB" ;
+ defparam PLLInst_0.CLKOS_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXA = "DIVA" ;
+ defparam PLLInst_0.CLKOP_ENABLE = "ENABLED" ;
+ defparam PLLInst_0.CLKOS3_DIV = 1 ;
+ defparam PLLInst_0.CLKOS2_DIV = 1 ;
+ defparam PLLInst_0.CLKOS_DIV = 1 ;
+ defparam PLLInst_0.CLKOP_DIV = 12 ;
+ defparam PLLInst_0.CLKFB_DIV = 6 ;
+ defparam PLLInst_0.CLKI_DIV = 25 ;
+ defparam PLLInst_0.FEEDBK_PATH = "CLKOP" ;
+ EHXPLLL PLLInst_0 (.CLKI(CLKI), .CLKFB(CLKOP_t), .PHASESEL1(scuba_vlo),
+ .PHASESEL0(scuba_vlo), .PHASEDIR(scuba_vlo), .PHASESTEP(scuba_vlo),
+ .PHASELOADREG(scuba_vlo), .STDBY(scuba_vlo), .PLLWAKESYNC(scuba_vlo),
+ .RST(scuba_vlo), .ENCLKOP(scuba_vlo), .ENCLKOS(scuba_vlo), .ENCLKOS2(scuba_vlo),
+ .ENCLKOS3(scuba_vlo), .CLKOP(CLKOP_t), .CLKOS(), .CLKOS2(), .CLKOS3(),
+ .LOCK(LOCK), .INTLOCK(), .REFCLK(REFCLK), .CLKINTFB())
+ /* synthesis FREQUENCY_PIN_CLKOP="48.000000" */
+ /* synthesis FREQUENCY_PIN_CLKI="200.000000" */
+ /* synthesis ICP_CURRENT="5" */
+ /* synthesis LPF_RESISTOR="16" */;
+
+ assign CLKOP = CLKOP_t;
+
+
+ // exemplar begin
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKOP 48.000000
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKI 200.000000
+ // exemplar attribute PLLInst_0 ICP_CURRENT 5
+ // exemplar attribute PLLInst_0 LPF_RESISTOR 16
+ // exemplar end
+
+endmodule
diff --git a/boards/ulx3s-v1.7-45f/clocks/clk_25M_200M.v b/boards/ulx3s-v1.7-45f/clocks/clk_25M_200M.v
new file mode 100644
index 0000000..0ce5c18
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/clocks/clk_25M_200M.v
@@ -0,0 +1,75 @@
+/* Verilog netlist generated by SCUBA Diamond (64-bit) 3.7.0.96.1 */
+/* Module Version: 5.7 */
+/* /mt/lattice/diamond/3.7_x64/ispfpga/bin/lin64/scuba -w -n clk_25M_200M -lang verilog -synth synplify -bus_exp 7 -bb -arch sa5p00 -type pll -fin 25.00 -fclkop 200.00 -fclkop_tol 0.0 -phase_cntl STATIC -fb_mode 1 -fdc /home/guest/src/fpga/usbserial-core/TinyFPGA-Bootloader/boards/ulx3s/clock/clk_25M_200M/clk_25M_200M.fdc */
+/* Wed Jul 11 00:09:44 2018 */
+
+
+`timescale 1 ns / 1 ps
+module clk_25M_200M (CLKI, CLKOP)/* synthesis NGD_DRC_MASK=1 */;
+ input wire CLKI;
+ output wire CLKOP;
+
+ wire REFCLK;
+ wire LOCK;
+ wire CLKOP_t;
+ wire scuba_vhi;
+ wire scuba_vlo;
+
+ VHI scuba_vhi_inst (.Z(scuba_vhi));
+
+ VLO scuba_vlo_inst (.Z(scuba_vlo));
+
+ defparam PLLInst_0.PLLRST_ENA = "DISABLED" ;
+ defparam PLLInst_0.INTFB_WAKE = "DISABLED" ;
+ defparam PLLInst_0.STDBY_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.DPHASE_SOURCE = "DISABLED" ;
+ defparam PLLInst_0.CLKOS3_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS3_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_CPHASE = 2 ;
+ defparam PLLInst_0.PLL_LOCK_MODE = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.CLKOP_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOP_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXD = "DIVD" ;
+ defparam PLLInst_0.CLKOS3_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXC = "DIVC" ;
+ defparam PLLInst_0.CLKOS2_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXB = "DIVB" ;
+ defparam PLLInst_0.CLKOS_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXA = "DIVA" ;
+ defparam PLLInst_0.CLKOP_ENABLE = "ENABLED" ;
+ defparam PLLInst_0.CLKOS3_DIV = 1 ;
+ defparam PLLInst_0.CLKOS2_DIV = 1 ;
+ defparam PLLInst_0.CLKOS_DIV = 1 ;
+ defparam PLLInst_0.CLKOP_DIV = 3 ;
+ defparam PLLInst_0.CLKFB_DIV = 8 ;
+ defparam PLLInst_0.CLKI_DIV = 1 ;
+ defparam PLLInst_0.FEEDBK_PATH = "CLKOP" ;
+ EHXPLLL PLLInst_0 (.CLKI(CLKI), .CLKFB(CLKOP_t), .PHASESEL1(scuba_vlo),
+ .PHASESEL0(scuba_vlo), .PHASEDIR(scuba_vlo), .PHASESTEP(scuba_vlo),
+ .PHASELOADREG(scuba_vlo), .STDBY(scuba_vlo), .PLLWAKESYNC(scuba_vlo),
+ .RST(scuba_vlo), .ENCLKOP(scuba_vlo), .ENCLKOS(scuba_vlo), .ENCLKOS2(scuba_vlo),
+ .ENCLKOS3(scuba_vlo), .CLKOP(CLKOP_t), .CLKOS(), .CLKOS2(), .CLKOS3(),
+ .LOCK(LOCK), .INTLOCK(), .REFCLK(REFCLK), .CLKINTFB())
+ /* synthesis FREQUENCY_PIN_CLKOP="200.000000" */
+ /* synthesis FREQUENCY_PIN_CLKI="25.000000" */
+ /* synthesis ICP_CURRENT="5" */
+ /* synthesis LPF_RESISTOR="16" */;
+
+ assign CLKOP = CLKOP_t;
+
+
+ // exemplar begin
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKOP 200.000000
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKI 25.000000
+ // exemplar attribute PLLInst_0 ICP_CURRENT 5
+ // exemplar attribute PLLInst_0 LPF_RESISTOR 16
+ // exemplar end
+
+endmodule
diff --git a/boards/ulx3s-v1.7-45f/constraints/ulx3s_v17patch.lpf b/boards/ulx3s-v1.7-45f/constraints/ulx3s_v17patch.lpf
new file mode 100644
index 0000000..8e0d34c
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/constraints/ulx3s_v17patch.lpf
@@ -0,0 +1,435 @@
+BLOCK RESETPATHS;
+BLOCK ASYNCPATHS;
+## ULX3S v1.7 patched towards v1.8
+
+# The clock "usb" and "gpdi" sheet
+LOCATE COMP "clk_25mhz" SITE "G2";
+IOBUF PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33;
+FREQUENCY PORT "clk_25mhz" 25 MHZ;
+
+# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash
+SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 SLAVE_SPI_PORT=DISABLE MASTER_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE;
+
+## USBSERIAL FTDI-FPGA serial port "usb" sheet
+LOCATE COMP "ftdi_rxd" SITE "L4"; # FPGA transmits to ftdi
+LOCATE COMP "ftdi_txd" SITE "M1"; # FPGA receives from ftdi
+LOCATE COMP "ftdi_nrts" SITE "M3"; # FPGA receives
+LOCATE COMP "ftdi_ndtr" SITE "N1"; # FPGA receives
+LOCATE COMP "ftdi_txden" SITE "L3"; # FPGA receives
+IOBUF PORT "ftdi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "ftdi_txd" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_nrts" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_ndtr" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_txden" PULLMODE=UP IO_TYPE=LVCMOS33;
+
+## LED indicators "blinkey" and "gpio" sheet
+LOCATE COMP "led[7]" SITE "H3";
+LOCATE COMP "led[6]" SITE "E1";
+LOCATE COMP "led[5]" SITE "E2";
+LOCATE COMP "led[4]" SITE "D1";
+LOCATE COMP "led[3]" SITE "D2";
+LOCATE COMP "led[2]" SITE "C1";
+LOCATE COMP "led[1]" SITE "C2";
+LOCATE COMP "led[0]" SITE "B2";
+IOBUF PORT "led[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Pushbuttons "blinkey", "flash", "power", "gpdi" sheet
+LOCATE COMP "btn[0]" SITE "D6"; # BTN_PWRn (inverted logic)
+LOCATE COMP "btn[1]" SITE "R1"; # FIRE1
+LOCATE COMP "btn[2]" SITE "T1"; # FIRE2
+LOCATE COMP "btn[3]" SITE "W1"; # UP
+LOCATE COMP "btn[4]" SITE "V1"; # DOWN
+LOCATE COMP "btn[5]" SITE "U1"; # LEFT
+LOCATE COMP "btn[6]" SITE "Y2"; # RIGHT
+IOBUF PORT "btn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[4]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[5]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[6]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## DIP switch "blinkey", "gpio" sheet
+LOCATE COMP "sw[0]" SITE "E8"; # SW1
+LOCATE COMP "sw[1]" SITE "D8"; # SW2
+LOCATE COMP "sw[2]" SITE "D7"; # SW3
+LOCATE COMP "sw[3]" SITE "E7"; # SW4
+IOBUF PORT "sw[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI OLED DISPLAY SSD1331 (Color) or SSD1306 (B/W) "blinkey", "usb" sheet
+LOCATE COMP "oled_clk" SITE "P4";
+LOCATE COMP "oled_mosi" SITE "P3";
+LOCATE COMP "oled_dc" SITE "P1";
+LOCATE COMP "oled_resn" SITE "P2";
+LOCATE COMP "oled_csn" SITE "N2";
+IOBUF PORT "oled_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_dc" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_resn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI Flash chip "flash" sheet
+LOCATE COMP "flash_csn" SITE "R2";
+LOCATE COMP "flash_clk" SITE "U3";
+LOCATE COMP "flash_mosi" SITE "W2";
+LOCATE COMP "flash_miso" SITE "V2";
+#LOCATE COMP "flash_csspin" SITE "AJ3";
+#LOCATE COMP "flash_initn" SITE "AG4";
+#LOCATE COMP "flash_done" SITE "AJ4";
+#LOCATE COMP "flash_programn" SITE "AH4";
+#LOCATE COMP "flash_cfg_select[0]" SITE "AM4";
+#LOCATE COMP "flash_cfg_select[1]" SITE "AL4";
+#LOCATE COMP "flash_cfg_select[2]" SITE "AK4";
+IOBUF PORT "flash_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_clk" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_csspin" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_initn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SD card "sdcard", "usb" sheet
+LOCATE COMP "sd_clk" SITE "J1"; # sd_clk WiFi_GPIO14
+LOCATE COMP "sd_cmd" SITE "J3"; # sd_cmd_di (MOSI) WiFi GPIO15
+LOCATE COMP "sd_d[0]" SITE "K2"; # sd_dat0_do (MISO) WiFi GPIO2
+LOCATE COMP "sd_d[1]" SITE "K1"; # sd_dat1_irq WiFi GPIO4
+LOCATE COMP "sd_d[2]" SITE "H2"; # sd_dat2 WiFi_GPIO12
+LOCATE COMP "sd_d[3]" SITE "H1"; # sd_dat3_csn WiFi_GPIO13
+LOCATE COMP "sd_wp" SITE "P5"; # not connected
+LOCATE COMP "sd_cdn" SITE "N5"; # not connected
+IOBUF PORT "sd_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cmd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; # WiFi GPIO12 pulldown bootstrapping requirement
+IOBUF PORT "sd_d[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_wp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## ADC SPI (MAX11123) "analog", "ram" sheet
+LOCATE COMP "adc_csn" SITE "R17";
+LOCATE COMP "adc_mosi" SITE "R16";
+LOCATE COMP "adc_miso" SITE "U16";
+LOCATE COMP "adc_sclk" SITE "P17";
+IOBUF PORT "adc_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_sclk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Audio 4-bit DAC "analog", "gpio" sheet
+# 4-bit mode can drive down to 75 ohm load impedance.
+# Lower impedance leads to IO overload,
+# FPGA will stop working and need reboot.
+# For standard 17 ohm earphones:
+# use bits 2,3 as input (High-Z) and drive only bits 0,1.
+LOCATE COMP "audio_l[3]" SITE "B3"; # JACK TIP (left audio)
+LOCATE COMP "audio_l[2]" SITE "C3";
+LOCATE COMP "audio_l[1]" SITE "D3";
+LOCATE COMP "audio_l[0]" SITE "E4";
+LOCATE COMP "audio_r[3]" SITE "C5"; # JACK RING1 (right audio)
+LOCATE COMP "audio_r[2]" SITE "D5";
+LOCATE COMP "audio_r[1]" SITE "B5";
+LOCATE COMP "audio_r[0]" SITE "A3";
+LOCATE COMP "audio_v[3]" SITE "E5"; # JACK RING2 (video or digital audio)
+LOCATE COMP "audio_v[2]" SITE "F5";
+LOCATE COMP "audio_v[1]" SITE "F2";
+LOCATE COMP "audio_v[0]" SITE "H5";
+IOBUF PORT "audio_l[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## WiFi ESP-32 "wifi", "usb", "flash" sheet
+# other pins are shared with GP/GN, SD card and JTAG
+LOCATE COMP "wifi_en" SITE "F1"; # enable/reset WiFi
+LOCATE COMP "wifi_rxd" SITE "K3"; # FPGA transmits to WiFi
+LOCATE COMP "wifi_txd" SITE "K4"; # FPGA receives from WiFi
+LOCATE COMP "wifi_gpio0" SITE "L2";
+LOCATE COMP "wifi_gpio5" SITE "N4"; # WIFI LED
+LOCATE COMP "wifi_gpio16" SITE "L1";
+LOCATE COMP "wifi_gpio17" SITE "N3";
+# LOCATE COMP "prog_done" SITE "Y3"; # not GPIO, always active
+IOBUF PORT "wifi_en" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_txd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio16" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio17" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+# IOBUF PORT "prog_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## PCB antenna 433 MHz (may be also used for FM) "usb" sheet
+LOCATE COMP "ant_433mhz" SITE "G1";
+IOBUF PORT "ant_433mhz" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Second USB port going directly into FPGA "usb", "ram" sheet
+LOCATE COMP "usb_fpga_dp" SITE "E16";
+LOCATE COMP "usb_fpga_dn" SITE "F16";
+IOBUF PORT "usb_fpga_dp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## JTAG ESP-32 "usb" sheet
+# connected to FT231X and ESP-32
+# commented out because those are dedicated pins, not directly useable as GPIO
+# but could be used by some vendor-specific JTAG bridging (boundary scan) module
+#LOCATE COMP "jtag_tdi" SITE "R5"; # FTDI_nRI FPGA receives
+#LOCATE COMP "jtag_tdo" SITE "V4"; # FTDI_nCTS FPGA transmits
+#LOCATE COMP "jtag_tck" SITE "T5"; # FTDI_nDSR FPGA receives
+#LOCATE COMP "jtag_tms" SITE "U5"; # FTDI_nDCD FPGA receives
+#IOBUF PORT "jtag_tdi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tdo" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tck" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tms" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SDRAM "ram" sheet
+LOCATE COMP "sdram_clk" SITE "F19";
+LOCATE COMP "sdram_cke" SITE "F20";
+LOCATE COMP "sdram_csn" SITE "P20";
+LOCATE COMP "sdram_wen" SITE "T20";
+LOCATE COMP "sdram_rasn" SITE "R20";
+LOCATE COMP "sdram_casn" SITE "T19";
+LOCATE COMP "sdram_a[0]" SITE "M20";
+LOCATE COMP "sdram_a[1]" SITE "M19";
+LOCATE COMP "sdram_a[2]" SITE "L20";
+LOCATE COMP "sdram_a[3]" SITE "L19";
+LOCATE COMP "sdram_a[4]" SITE "K20";
+LOCATE COMP "sdram_a[5]" SITE "K19";
+LOCATE COMP "sdram_a[6]" SITE "K18";
+LOCATE COMP "sdram_a[7]" SITE "J20";
+LOCATE COMP "sdram_a[8]" SITE "J19";
+LOCATE COMP "sdram_a[9]" SITE "H20";
+LOCATE COMP "sdram_a[10]" SITE "N19";
+LOCATE COMP "sdram_a[11]" SITE "G20";
+LOCATE COMP "sdram_a[12]" SITE "G19";
+LOCATE COMP "sdram_ba[0]" SITE "P19";
+LOCATE COMP "sdram_ba[1]" SITE "N20";
+LOCATE COMP "sdram_dqm[0]" SITE "U19";
+LOCATE COMP "sdram_dqm[1]" SITE "E20";
+LOCATE COMP "sdram_d[0]" SITE "J16";
+LOCATE COMP "sdram_d[1]" SITE "L18";
+LOCATE COMP "sdram_d[2]" SITE "M18";
+LOCATE COMP "sdram_d[3]" SITE "N18";
+LOCATE COMP "sdram_d[4]" SITE "P18";
+LOCATE COMP "sdram_d[5]" SITE "T18";
+LOCATE COMP "sdram_d[6]" SITE "T17";
+LOCATE COMP "sdram_d[7]" SITE "U20";
+LOCATE COMP "sdram_d[8]" SITE "E19";
+LOCATE COMP "sdram_d[9]" SITE "D20";
+LOCATE COMP "sdram_d[10]" SITE "D19";
+LOCATE COMP "sdram_d[11]" SITE "C20";
+LOCATE COMP "sdram_d[12]" SITE "E18";
+LOCATE COMP "sdram_d[13]" SITE "F18";
+LOCATE COMP "sdram_d[14]" SITE "J18";
+LOCATE COMP "sdram_d[15]" SITE "J17";
+IOBUF PORT "sdram_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_cke" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_wen" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_rasn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_casn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[13]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[14]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[15]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPDI differential interface (Video) "gpdi" sheet
+LOCATE COMP "gpdi_dp[0]" SITE "A16"; # Blue +
+LOCATE COMP "gpdi_dn[0]" SITE "B16"; # Blue -
+LOCATE COMP "gpdi_dp[1]" SITE "A14"; # Green +
+LOCATE COMP "gpdi_dn[1]" SITE "C14"; # Green -
+LOCATE COMP "gpdi_dp[2]" SITE "A12"; # Red +
+LOCATE COMP "gpdi_dn[2]" SITE "A13"; # Read +
+LOCATE COMP "gpdi_ethp" SITE "A19"; # Ethernet +
+LOCATE COMP "gpdi_ethn" SITE "B20"; # Ethernet -
+LOCATE COMP "gpdi_clkp" SITE "A17"; # Clock +
+LOCATE COMP "gpdi_clkn" SITE "B18"; # Clock -
+LOCATE COMP "gpdi_cec" SITE "A18";
+LOCATE COMP "gpdi_sda" SITE "B19"; # I2C shared with RTC
+LOCATE COMP "gpdi_scl" SITE "C12"; # I2C shared with RTC
+IOBUF PORT "gpdi_dp[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_clkp" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_clkn" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethp" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethn" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_cec" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_sda" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_scl" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPIO (default single-ended) "gpio", "ram", "gpdi" sheet
+# Pins enumerated gp[0-27], gn[0-27].
+# With differential mode enabled on Lattice,
+# gp[] (+) are used, gn[] (-) are ignored from design
+# as they handle inverted signal by default.
+# To enable differential, rename LVCMOS33->LVCMOS33D
+LOCATE COMP "gp[0]" SITE "B11"; # J1_5+ GP0
+LOCATE COMP "gn[0]" SITE "C11"; # J1_5- GN0
+LOCATE COMP "gp[1]" SITE "A10"; # J1_7+ GP1
+LOCATE COMP "gn[1]" SITE "A11"; # J1_7- GN1
+LOCATE COMP "gp[2]" SITE "A9"; # J1_9+ GP2
+LOCATE COMP "gn[2]" SITE "B10"; # J1_9- GN2
+LOCATE COMP "gp[3]" SITE "B9"; # J1_11+ GP3
+LOCATE COMP "gn[3]" SITE "C10"; # J1_11- GN3
+LOCATE COMP "gp[4]" SITE "A7"; # J1_13+ GP4
+LOCATE COMP "gn[4]" SITE "A8"; # J1_13- GN4
+LOCATE COMP "gp[5]" SITE "C8"; # J1_15+ GP5
+LOCATE COMP "gn[5]" SITE "B8"; # J1_15- GN5
+LOCATE COMP "gp[6]" SITE "C6"; # J1_17+ GP6
+LOCATE COMP "gn[6]" SITE "C7"; # J1_17- GN6
+IOBUF PORT "gp[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[7]" SITE "A6"; # J1_23+ GP7
+LOCATE COMP "gn[7]" SITE "B6"; # J1_23- GN7
+LOCATE COMP "gp[8]" SITE "A4"; # J1_25+ GP8
+LOCATE COMP "gn[8]" SITE "A5"; # J1_25- GN8
+LOCATE COMP "gp[9]" SITE "A2"; # J1_27+ GP9
+LOCATE COMP "gn[9]" SITE "B1"; # J1_27- GN9
+LOCATE COMP "gp[10]" SITE "C4"; # J1_29+ GP10 WIFI_GPIO27
+LOCATE COMP "gn[10]" SITE "B4"; # J1_29- GN10
+LOCATE COMP "gp[11]" SITE "F4"; # J1_31+ GP11 WIFI_GPIO25
+LOCATE COMP "gn[11]" SITE "E3"; # J1_31- GN11 WIFI_GPIO26
+LOCATE COMP "gp[12]" SITE "G3"; # J1_33+ GP12 WIFI_GPIO32
+LOCATE COMP "gn[12]" SITE "F3"; # J1_33- GN12 WIFI_GPIO33
+LOCATE COMP "gp[13]" SITE "H4"; # J1_35+ GP13 WIFI_GPIO34
+LOCATE COMP "gn[13]" SITE "G5"; # J1_35- GN13 WIFI_GPIO35
+IOBUF PORT "gp[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[14]" SITE "U18"; # J2_5+ GP14
+LOCATE COMP "gn[14]" SITE "U17"; # J2_5- GN14
+LOCATE COMP "gp[15]" SITE "N17"; # J2_7+ GP15
+LOCATE COMP "gn[15]" SITE "P16"; # J2_7- GN15
+LOCATE COMP "gp[16]" SITE "N16"; # J2_9+ GP16
+LOCATE COMP "gn[16]" SITE "M17"; # J2_9- GN16
+LOCATE COMP "gp[17]" SITE "L16"; # J2_11+ GP17
+LOCATE COMP "gn[17]" SITE "L17"; # J2_11- GN17
+LOCATE COMP "gp[18]" SITE "H18"; # J2_13+ GP18
+LOCATE COMP "gn[18]" SITE "H17"; # J2_13- GN18
+LOCATE COMP "gp[19]" SITE "F17"; # J2_15+ GP19
+LOCATE COMP "gn[19]" SITE "G18"; # J2_15- GN19
+LOCATE COMP "gp[20]" SITE "D18"; # J2_17+ GP20
+LOCATE COMP "gn[20]" SITE "E17"; # J2_17- GN20
+IOBUF PORT "gp[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[21]" SITE "C18"; # J2_23+ GP21
+LOCATE COMP "gn[21]" SITE "D17"; # J2_23- GN21
+LOCATE COMP "gp[22]" SITE "D15"; # J2_25+ GP22
+LOCATE COMP "gn[22]" SITE "E15"; # J2_25- GN22
+LOCATE COMP "gp[23]" SITE "B17"; # J2_27+ GP23
+LOCATE COMP "gn[23]" SITE "C17"; # J2_27- GN23
+LOCATE COMP "gp[24]" SITE "C16"; # J2_29+ GP24
+LOCATE COMP "gn[24]" SITE "D16"; # J2_29- GN24
+LOCATE COMP "gp[25]" SITE "B15"; # J2_31+ GP25
+LOCATE COMP "gn[25]" SITE "C15"; # J2_31- GN25
+LOCATE COMP "gp[26]" SITE "B13"; # J2_33+ GP26
+LOCATE COMP "gn[26]" SITE "C13"; # J2_33- GN26
+LOCATE COMP "gp[27]" SITE "D13"; # J2_35+ GP27
+LOCATE COMP "gn[27]" SITE "E13"; # J2_35- GN27
+IOBUF PORT "gp[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SHUTDOWN "power", "ram" sheet (connected from PCB v1.7.5)
+# on PCB v1.7 shutdown is not connected to FPGA
+LOCATE COMP "shutdown" SITE "G16"; # FPGA receives
+IOBUF PORT "shutdown" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
diff --git a/boards/ulx3s-v1.7-45f/initialize/boardmeta4MB.bin b/boards/ulx3s-v1.7-45f/initialize/boardmeta4MB.bin
new file mode 100644
index 0000000..7a525c7
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/initialize/boardmeta4MB.bin
@@ -0,0 +1,119 @@
+{
+ "boardmeta":
+ {
+ "name": "ULX3S",
+ "fpga": "LFE5U-45F-6BG381C",
+ "hver": "1.7",
+ "uuid": "00000000-0000-0000-0000-000000000000",
+ "serial": 12345
+ },
+ "bootmeta":
+ {
+ "bootloader": "TinyFPGA USB Bootloader",
+ "bver": "2.0.0",
+ "update": "https://github.com/emard/TinyFPGA-Bootloader",
+ "addrmap":
+ {
+ "bootloader": "0x000000-0x0FFFFF",
+ "golden": "0x100000-0x1FFFFF",
+ "userimage": "0x200000-0x2FFFFF",
+ "userdata": "0x300000-0x3FBFFF"
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-v1.7-45f/initialize/boardmeta8MB.bin b/boards/ulx3s-v1.7-45f/initialize/boardmeta8MB.bin
new file mode 100644
index 0000000..89be03c
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/initialize/boardmeta8MB.bin
@@ -0,0 +1,58 @@
+{
+ "boardmeta":
+ {
+ "name": "ULX3S",
+ "fpga": "LFE5U-45F-6BG381C",
+ "hver": "1.7",
+ "uuid": "00000000-0000-0000-0000-000000000000",
+ "serial": 12345
+ },
+ "bootmeta":
+ {
+ "bootloader": "TinyFPGA USB Bootloader",
+ "bver": "2.0.0",
+ "update": "https://github.com/emard/TinyFPGA-Bootloader",
+ "addrmap":
+ {
+ "bootloader": "0x000000-0x0FFFFF",
+ "golden": "0x100000-0x1FFFFF",
+ "userimage": "0x200000-0x3FFFFF",
+ "userdata": "0x500000-0x7FBFFF"
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-v1.7-45f/initialize/initialize4MB.sh b/boards/ulx3s-v1.7-45f/initialize/initialize4MB.sh
new file mode 100755
index 0000000..3d67d93
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/initialize/initialize4MB.sh
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+
+# Initializer for ECP5 dual boot.
+
+# first half of the FLASH is for user bitstram
+# bootloader bitstream starts at second half of the FLASH
+# board metadata at last 0x1000 bytes
+# Jump command at last 0x100 bytes
+
+# flash size: 16 Mbit = 2 MB = 0x200000
+# flash size: 32 Mbit = 4 MB = 0x400000
+# flash size: 64 Mbit = 8 MB = 0x800000
+# flash size: 128 Mbit = 16 MB = 0x1000000
+
+bootloader_image_address=$(printf "%d" 0x000000) # 0
+golden_image_address=$(printf "%d" 0x100000) # 0x100000 (1MB) (backup of bootloader)
+board_meta_address=$(printf "%d" 0x3FF000) # flash size - 0x1000
+jump_command_address=$(printf "%d" 0x3FFF00) # flash size - 0x100
+
+# primary image must be generated by diamond deployment tool (ddtcmd)
+# simply overwriting bootloader image will not have multiboot capability
+#tinyprog --pyserial --no-boot -a $bootloader_image_address -u ../../boards/ulx3s-v1.7-45f/tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $golden_image_address -u ../tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $(printf "%d" $board_meta_address) -u boardmeta4MB.bin
+./jump.py $golden_image_address > jump.bin
+tinyprog --pyserial --no-boot -a $(printf "%d" $jump_command_address) -u jump.bin
+# hexdump -C jump.bin
+# check that's board is recognized by tingprog
+tinyprog --pyserial -l
+#tinyprog -m
diff --git a/boards/ulx3s-v1.7-45f/initialize/initialize8MB.sh b/boards/ulx3s-v1.7-45f/initialize/initialize8MB.sh
new file mode 100755
index 0000000..b127f53
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/initialize/initialize8MB.sh
@@ -0,0 +1,31 @@
+#!/bin/sh -e
+
+# Initializer for ECP5 dual boot.
+
+# first half of the FLASH is for user bitstram
+# bootloader bitstream starts at second half of the FLASH
+# board metadata at last 0x1000 bytes
+# Jump command at last 0x100 bytes
+
+# flash size: 8 Mbit = 1 MB = 0x100000
+# flash size: 16 Mbit = 2 MB = 0x200000
+# flash size: 32 Mbit = 4 MB = 0x400000
+# flash size: 64 Mbit = 8 MB = 0x800000
+# flash size: 128 Mbit = 16 MB = 0x1000000
+
+bootloader_image_address=$(printf "%d" 0x000000) # 0
+golden_image_address=$(printf "%d" 0x100000) # 0x100000 (1MB) (backup of bootloader)
+board_meta_address=$(printf "%d" 0x7FF000) # flash size - 0x1000 (-4KB)
+jump_command_address=$(printf "%d" 0x7FFF00) # flash size - 0x100 (-256)
+
+# primary image must be generated by diamond deployment tool (ddtcmd)
+# simply overwriting bootloader image will not have multiboot capability
+#tinyprog --pyserial --no-boot -a $bootloader_image_address -u ../../boards/ulx3s-v1.7-45f/tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $golden_image_address -u ../tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $(printf "%d" $board_meta_address) -u boardmeta8MB.bin
+./jump.py $golden_image_address > jump.bin
+tinyprog --pyserial --no-boot -a $(printf "%d" $jump_command_address) -u jump.bin
+# hexdump -C jump.bin
+# check that's board is recognized by tingprog
+tinyprog --pyserial -l
+#tinyprog -m
diff --git a/boards/ulx3s-v1.7-45f/initialize/jump.py b/boards/ulx3s-v1.7-45f/initialize/jump.py
new file mode 100755
index 0000000..b1ff948
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/initialize/jump.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+
+# Lattice ECP5 jump command generator
+# TN1216 p.23 describes the jump command syntax which does not work.
+# The syntax has been fixed by looking at dual boot intel hex file
+# generated by diamond, this actually works.
+
+import struct
+import sys
+
+# write output of this funtion at FLASH address:
+# jump_command_address = 0x3FFF00 = 4194048
+
+# write "golden" bitstream at FLASH address:
+golden_image_address = 0x140000
+golden_image_address = int(sys.argv[1])
+
+# normally both 0
+reverse_bytes = 0
+reverse_bits = 0
+
+# to compare with intel HEX file generated by diamond:
+# (not for normal use)
+# reverse_bytes = 1
+# reverse_bits = 1
+# ./jump.py | hexdump -C
+
+def reverse_Bits(n, no_of_bits):
+ result = 0
+ for i in range(no_of_bits):
+ result <<= 1
+ result |= n & 1
+ n >>= 1
+ return result
+
+def uint8(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 8)
+ return struct.pack(">B", n)
+
+def uint16(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 16)
+ if reverse_bytes:
+ return struct.pack("H", n)
+
+def uint24(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 24)
+ if reverse_bytes:
+ return struct.pack("> 8 )
+ else:
+ return struct.pack(">HB", n >> 8, n & 0xFF )
+
+def uint32(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 32)
+ if reverse_bytes:
+ return struct.pack("L", n)
+
+packet = b''
+# Frame (START) 18 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint16(0xFFFF) # 2 dummy bytes (diamond generates this 2 bytes more)
+# Preamble
+packet += uint16(0xBDB3) # Preamble
+# Frame (Control Register 0) commented out, diamond doesn't output this
+# if uncommented, jump won't work:
+#packet += uint8(0xC4) # Write control register 0 command
+#packet += uint24(0) # 24-bit Command Information
+#packet += uint32(0) # Control Register 0 data
+# This is generated by diamond:
+packet += uint32(0xFFFFFFFF) # I don't know what it does but it works
+# Framme (Jump Command)
+#packet += uint8(0xFE) # Jump command Wrong noted in TN1216
+packet += uint8(0x7E) # Jump command generated by diamond
+packet += uint24(0) # 24-bit Command Information
+packet += uint8(0x03) # SPI Flash Read opcode (0x03 = regular read, 0x0B = fast read)
+packet += uint24(golden_image_address) # 24-bit SPI Flash Sector X address
+# Frame (END) 18 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint16(0xFFFF) # 2 dummy bytes (diamond generates this 2 bytes more)
+
+sys.stdout.write(packet)
+# print([elem.encode("hex") for elem in packet])
diff --git a/boards/ulx3s-v1.7-45f/tinyfpga_45k.bit b/boards/ulx3s-v1.7-45f/tinyfpga_45k.bit
new file mode 120000
index 0000000..59e9556
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/tinyfpga_45k.bit
@@ -0,0 +1 @@
+project/project_project.bit
\ No newline at end of file
diff --git a/boards/ulx3s-v1.7-45f/tinyfpga_45k_multiboot_flash_micron_32mbit.svf b/boards/ulx3s-v1.7-45f/tinyfpga_45k_multiboot_flash_micron_32mbit.svf
new file mode 120000
index 0000000..623c0d8
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/tinyfpga_45k_multiboot_flash_micron_32mbit.svf
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_micron_32mbit.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v1.7-45f/tinyfpga_45k_multiboot_flash_micron_32mbit.vme b/boards/ulx3s-v1.7-45f/tinyfpga_45k_multiboot_flash_micron_32mbit.vme
new file mode 120000
index 0000000..bc0382a
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/tinyfpga_45k_multiboot_flash_micron_32mbit.vme
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_micron_32mbit.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v1.7-45f/tinyfpga_45k_multiboot_flash_spansion_64mbit.svf b/boards/ulx3s-v1.7-45f/tinyfpga_45k_multiboot_flash_spansion_64mbit.svf
new file mode 120000
index 0000000..2c6afa4
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/tinyfpga_45k_multiboot_flash_spansion_64mbit.svf
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_spansion_64mbit.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v1.7-45f/tinyfpga_45k_multiboot_flash_spansion_64mbit.vme b/boards/ulx3s-v1.7-45f/tinyfpga_45k_multiboot_flash_spansion_64mbit.vme
new file mode 120000
index 0000000..9e1e580
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/tinyfpga_45k_multiboot_flash_spansion_64mbit.vme
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_spansion_64mbit.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v1.7-45f/tinyfpga_45k_sram.svf b/boards/ulx3s-v1.7-45f/tinyfpga_45k_sram.svf
new file mode 120000
index 0000000..bb7617d
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/tinyfpga_45k_sram.svf
@@ -0,0 +1 @@
+project/project_project_sram.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v1.7-45f/tinyfpga_45k_sram.vme b/boards/ulx3s-v1.7-45f/tinyfpga_45k_sram.vme
new file mode 120000
index 0000000..d098048
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/tinyfpga_45k_sram.vme
@@ -0,0 +1 @@
+project/project_project_sram.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v1.7-45f/top/bootloader_ulx3s.v b/boards/ulx3s-v1.7-45f/top/bootloader_ulx3s.v
new file mode 100644
index 0000000..47812de
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/top/bootloader_ulx3s.v
@@ -0,0 +1,108 @@
+module bootloader_ulx3s (
+ input clk_25mhz,
+
+ inout usb_fpga_dp,
+ inout usb_fpga_dn,
+
+ output [7:0] led,
+
+ input flash_miso,
+ output flash_mosi,
+ output flash_clk,
+ output flash_csn,
+
+ input [6:0] btn,
+ output wifi_gpio0
+);
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// generate 48 mhz clock
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ wire clk_200mhz;
+ clk_25M_200M clk_200M_inst (
+ .CLKI(clk_25mhz),
+ .CLKOP(clk_200mhz)
+ );
+
+ wire clk_48mhz;
+ wire clk_ready;
+ clk_200M_48M clk_48M_inst (
+ .CLKI(clk_200mhz),
+ .CLKOP(clk_48mhz),
+ .LOCK(clk_ready)
+ );
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// instantiate tinyfpga bootloader
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ reg reset = 1'b1;
+ wire usb_p_tx;
+ wire usb_n_tx;
+ wire usb_p_rx;
+ wire usb_n_rx;
+ wire usb_tx_en;
+ wire pin_led;
+ wire boot;
+ wire S_flash_clk;
+ wire S_flash_csn;
+
+ tinyfpga_bootloader tinyfpga_bootloader_inst (
+ .clk_48mhz(clk_48mhz),
+ .reset(reset),
+ .usb_p_tx(usb_p_tx),
+ .usb_n_tx(usb_n_tx),
+ .usb_p_rx(usb_p_rx),
+ .usb_n_rx(usb_n_rx),
+ .usb_tx_en(usb_tx_en),
+ .led(pin_led),
+ .spi_miso(flash_miso),
+ .spi_mosi(flash_mosi),
+ .spi_sck(S_flash_clk),
+ .spi_cs(S_flash_csn),
+ .boot(boot)
+ );
+
+ assign usb_fpga_dp = reset ? 1'b0 : (usb_tx_en ? usb_p_tx : 1'bz);
+ assign usb_fpga_dn = reset ? 1'b0 : (usb_tx_en ? usb_n_tx : 1'bz);
+ assign usb_p_rx = usb_tx_en ? 1'b1 : usb_fpga_dp;
+ assign usb_n_rx = usb_tx_en ? 1'b0 : usb_fpga_dn;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// Vendor-specific clock output to SPI config flash
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ USRMCLK usrmclk_inst (
+ .USRMCLKI(S_flash_clk),
+ .USRMCLKTS(S_flash_csn)
+ ) /* synthesis syn_noprune=1 */;
+ assign flash_clk = S_flash_clk;
+ assign flash_csn = S_flash_csn;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// ULX3S board buttons and LEDs
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ assign wifi_gpio0 = btn[0];
+ assign led[5] = boot;
+ assign led[0] = pin_led;
+
+ always @(posedge clk_48mhz)
+ begin
+ reset <= btn[1] | ~clk_ready;
+ end
+
+endmodule
diff --git a/boards/ulx3s-v1.7-45f/ulx3s_45f_flash_micron_32mbit.xcf b/boards/ulx3s-v1.7-45f/ulx3s_45f_flash_micron_32mbit.xcf
new file mode 100644
index 0000000..8bde416
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/ulx3s_45f_flash_micron_32mbit.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Micron
+ ECP5U
+ LFE5U-45F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-45F
+ 0x41112043
+ All
+ LFE5U-45F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ Micron
+ SPI Serial Flash
+ SPI-M25P32
+ 0x15
+ 8-pin VDFPN8
+ SPI Flash Erase,Program
+ project/project_project.mcs
+ 0x00000000
+ 0x00080000
+ 32
+ 4194304
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v1.7-45f/ulx3s_45f_flash_spansion_64mbit.xcf b/boards/ulx3s-v1.7-45f/ulx3s_45f_flash_spansion_64mbit.xcf
new file mode 100644
index 0000000..5ab9626
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/ulx3s_45f_flash_spansion_64mbit.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Micron
+ ECP5U
+ LFE5U-45F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-45F
+ 0x41112043
+ All
+ LFE5U-45F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ SPANSION
+ SPI Serial Flash
+ SPI-S25FL164K
+ 0x16
+ 8-lead SOIC
+ SPI Flash Erase,Program
+ project/project_project.mcs
+ 0x00000000
+ 0x00100000
+ 64
+ 8388608
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v1.7-45f/ulx3s_45f_multiboot_micron_32mbit.xcf b/boards/ulx3s-v1.7-45f/ulx3s_45f_multiboot_micron_32mbit.xcf
new file mode 100644
index 0000000..f20aa77
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/ulx3s_45f_multiboot_micron_32mbit.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Micron
+ ECP5U
+ LFE5U-45F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project_multiboot_flash_micron_32mbit.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-45F
+ 0x41112043
+ All
+ LFE5U-45F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ SPANSION
+ SPI Serial Flash
+ SPI-S25FL164K
+ 0x16
+ 8-lead SOIC
+ SPI Flash Erase,Program
+ project/project_project_multiboot_flash_micron_32mbit.mcs
+ 0x00000000
+ 0x00800000
+ 64
+ 8388608
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project_multiboot_flash_micron_32mbit.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v1.7-45f/ulx3s_45f_multiboot_spansion_64mbit.xcf b/boards/ulx3s-v1.7-45f/ulx3s_45f_multiboot_spansion_64mbit.xcf
new file mode 100644
index 0000000..8ccb7e7
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/ulx3s_45f_multiboot_spansion_64mbit.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Micron
+ ECP5U
+ LFE5U-45F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project_multiboot_flash_spansion_64mbit.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-45F
+ 0x41112043
+ All
+ LFE5U-45F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ SPANSION
+ SPI Serial Flash
+ SPI-S25FL164K
+ 0x16
+ 8-lead SOIC
+ SPI Flash Erase,Program
+ project/project_project_multiboot_flash_spansion_64mbit.mcs
+ 0x00000000
+ 0x00800000
+ 64
+ 8388608
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project_multiboot_flash_spansion_64mbit.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v1.7-45f/ulx3s_45f_sram.xcf b/boards/ulx3s-v1.7-45f/ulx3s_45f_sram.xcf
new file mode 100644
index 0000000..b11ed78
--- /dev/null
+++ b/boards/ulx3s-v1.7-45f/ulx3s_45f_sram.xcf
@@ -0,0 +1,48 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5UM
+ LFE5U-45F
+ 0x41112043
+ All
+ LFE5U-45F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project.bit
+ Fast Program
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ DUAL RS232-HS A Location 0000 Serial Dual RS232-HS A
+
+
diff --git a/boards/ulx3s-v2.0-12f-sp/Makefile b/boards/ulx3s-v2.0-12f-sp/Makefile
new file mode 100644
index 0000000..041c7ee
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/Makefile
@@ -0,0 +1,140 @@
+
+PROJ_FILE := $(shell ls *.ldf | head -1)
+PROJ_NAME := $(shell fgrep default_implementation ${PROJ_FILE} | cut -d'"' -f 4)
+IMPL_NAME := $(shell fgrep default_implementation ${PROJ_FILE} | cut -d'"' -f 8)
+IMPL_DIR := $(shell fgrep default_strategy ${PROJ_FILE} | cut -d'"' -f 4)
+
+DIAMOND_BASE := /usr/local/diamond
+DIAMOND_BIN := $(shell find ${DIAMOND_BASE}/ -maxdepth 2 -name bin | sort -rn | head -1)
+DIAMONDC := $(shell find ${DIAMOND_BIN}/ -name diamondc)
+DDTCMD := $(shell find ${DIAMOND_BIN}/ -name ddtcmd)
+
+OPENOCD = openocd_ft232r
+# OPENOCD_BASE := ../../programmer/openocd/ulx3s
+OPENOCD_BASE := .
+
+# name of the project as defined in project file
+PROJECT = project
+
+# FPGA flashing device for programming
+FPGA_DEVICE = LFE5U-12F
+
+JUNK = ${IMPL_DIR} .recovery ._Real_._Math_.vhd *.sty reportview.xml
+JUNK += dummy_sym.sort project_tcl.html promote.xml
+JUNK += generate_core.tcl generate_ngd.tcl msg_file.log
+JUNK += project_tcr.dir
+
+all: $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.svf \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.svf \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.svf \
+
+
+$(PROJECT)/$(PROJECT)_$(PROJECT).bit:
+ echo prj_project open ${PROJ_FILE} \; prj_run Export -task Bitgen | ${DIAMONDC}
+
+# same file with different name required for multiboot to work
+$(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ cp $< $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_12f_sram.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_12f_sram.xcf -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT).mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit -oft -int -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -oft -advanced -format int -flashsize 32 -header -quad 4 \
+ -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -golden $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -multi 1 -altfile $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit -address 0x200000 -next prim -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.vme: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_12f_multiboot_flash_is25lp032d.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.svf: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.mcs
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_12f_multiboot_flash_is25lp032d.xcf -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -oft -advanced -format int -flashsize 64 -header -quad 4 \
+ -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -golden $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -multi 1 -altfile $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit -address 0x200000 -next prim -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.vme: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_12f_multiboot_flash_s25fl164k.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.svf: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.mcs
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_12f_multiboot_flash_s25fl164k.xcf -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -oft -advanced -format int -flashsize 128 -header -quad 4 \
+ -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -golden $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -multi 1 -altfile $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit -address 0x200000 -next prim -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.vme: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_12f_multiboot_flash_is25lp128f.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.svf: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.mcs
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_12f_multiboot_flash_is25lp128f.xcf -of $@
+
+program: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ echo pgr_project open ulx3s_12f_sram.xcf \; pgr_program run | ${DIAMONDC}
+
+program_wifi: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ openocd --file=$(OPENOCD_BASE)/remote.ocd --file=$(OPENOCD_BASE)/ecp5-12f.ocd
+
+program_web: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ svfupload.py ulx3s.lan $<
+
+program_web_flash: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.svf
+ svfupload.py ulx3s.lan $<
+
+program_ft2232: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ openocd --file=$(OPENOCD_BASE)/ft2232-fpu1.ocd --file=$(OPENOCD_BASE)/ecp5-12f.ocd
+
+program_ft231x: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ $(OPENOCD) --file=$(OPENOCD_BASE)/ft231x.ocd --file=$(OPENOCD_BASE)/ecp5-12f.ocd
+
+program_flea: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme
+ FleaFPGA-JTAG $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme
+
+program_flea_flash: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.vme
+ FleaFPGA-JTAG $<
+
+program_flea_flash_spansion: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.vme
+ FleaFPGA-JTAG $<
+
+#$(PROJECT)/$(PROJECT)_$(PROJECT).jed:
+# echo prj_project open ${PROJ_FILE} \; prj_run Export -task Jedecgen | ${DIAMONDC}
+
+#$(PROJECT)/$(PROJECT)_$(PROJECT)_flash.vme: $(PROJECT)/$(PROJECT)_$(PROJECT).jed
+# ${DDTCMD} -oft -fullvme -if sparrowhawk_flash_is25lp128f.xcf -nocompress -noheader -of $@
+
+#$(PROJECT)/$(PROJECT)_$(PROJECT)_flash.svf: $(PROJECT)/$(PROJECT)_$(PROJECT).jed
+# ${DDTCMD} -oft -svfsingle -op "FLASH Erase,Program,Verify" -if $< -of $@
+
+flash: $(PROJECT)/$(PROJECT)_$(PROJECT)_flash.vme
+ ${PROGRAMMERC} $<
+ # after this, to gain access to serial port on linux
+ # rmmod ftdi_sio; modprobe ftdi_sio
+
+# example another project
+#%.svf : %.jed
+# ${DDTCMD} -oft -svfsingle -op "FLASH Erase,Program,Verify" -if $< -of $@
+# mv -f $@ $@.flash
+# ${DDTCMD} -oft -svfsingle -revd -op "SRAM Fast Program" -if $< -of $@
+# mv -f $@ $@.sram
+# ./svf_to_urjtag.pl <$@.flash | sed 's/,/./g' > $@
+
+clean:
+ rm -rf $(JUNK) *~
diff --git a/boards/ulx3s-v2.0-12f-sp/bootloader.ldf b/boards/ulx3s-v2.0-12f-sp/bootloader.ldf
new file mode 100644
index 0000000..940df22
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/bootloader.ldf
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-v2.0-12f-sp/clocks/clk_200M_48M.v b/boards/ulx3s-v2.0-12f-sp/clocks/clk_200M_48M.v
new file mode 100644
index 0000000..2e9bb80
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/clocks/clk_200M_48M.v
@@ -0,0 +1,75 @@
+/* Verilog netlist generated by SCUBA Diamond (64-bit) 3.7.0.96.1 */
+/* Module Version: 5.7 */
+/* /mt/lattice/diamond/3.7_x64/ispfpga/bin/lin64/scuba -w -n clk_200M_48M -lang verilog -synth synplify -bus_exp 7 -bb -arch sa5p00 -type pll -fin 200.00 -fclkop 48.00 -fclkop_tol 0.0 -phase_cntl STATIC -fb_mode 1 -fdc /home/guest/src/fpga/usbserial-core/TinyFPGA-Bootloader/boards/ulx3s/clock/clk_200M_48M/clk_200M_48M.fdc */
+/* Wed Jul 11 00:10:22 2018 */
+
+
+`timescale 1 ns / 1 ps
+module clk_200M_48M (CLKI, CLKOP, LOCK)/* synthesis NGD_DRC_MASK=1 */;
+ input wire CLKI;
+ output wire CLKOP;
+ output wire LOCK;
+
+ wire REFCLK;
+ wire CLKOP_t;
+ wire scuba_vhi;
+ wire scuba_vlo;
+
+ VHI scuba_vhi_inst (.Z(scuba_vhi));
+
+ VLO scuba_vlo_inst (.Z(scuba_vlo));
+
+ defparam PLLInst_0.PLLRST_ENA = "DISABLED" ;
+ defparam PLLInst_0.INTFB_WAKE = "DISABLED" ;
+ defparam PLLInst_0.STDBY_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.DPHASE_SOURCE = "DISABLED" ;
+ defparam PLLInst_0.CLKOS3_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS3_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_CPHASE = 11 ;
+ defparam PLLInst_0.PLL_LOCK_MODE = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.CLKOP_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOP_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXD = "DIVD" ;
+ defparam PLLInst_0.CLKOS3_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXC = "DIVC" ;
+ defparam PLLInst_0.CLKOS2_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXB = "DIVB" ;
+ defparam PLLInst_0.CLKOS_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXA = "DIVA" ;
+ defparam PLLInst_0.CLKOP_ENABLE = "ENABLED" ;
+ defparam PLLInst_0.CLKOS3_DIV = 1 ;
+ defparam PLLInst_0.CLKOS2_DIV = 1 ;
+ defparam PLLInst_0.CLKOS_DIV = 1 ;
+ defparam PLLInst_0.CLKOP_DIV = 12 ;
+ defparam PLLInst_0.CLKFB_DIV = 6 ;
+ defparam PLLInst_0.CLKI_DIV = 25 ;
+ defparam PLLInst_0.FEEDBK_PATH = "CLKOP" ;
+ EHXPLLL PLLInst_0 (.CLKI(CLKI), .CLKFB(CLKOP_t), .PHASESEL1(scuba_vlo),
+ .PHASESEL0(scuba_vlo), .PHASEDIR(scuba_vlo), .PHASESTEP(scuba_vlo),
+ .PHASELOADREG(scuba_vlo), .STDBY(scuba_vlo), .PLLWAKESYNC(scuba_vlo),
+ .RST(scuba_vlo), .ENCLKOP(scuba_vlo), .ENCLKOS(scuba_vlo), .ENCLKOS2(scuba_vlo),
+ .ENCLKOS3(scuba_vlo), .CLKOP(CLKOP_t), .CLKOS(), .CLKOS2(), .CLKOS3(),
+ .LOCK(LOCK), .INTLOCK(), .REFCLK(REFCLK), .CLKINTFB())
+ /* synthesis FREQUENCY_PIN_CLKOP="48.000000" */
+ /* synthesis FREQUENCY_PIN_CLKI="200.000000" */
+ /* synthesis ICP_CURRENT="5" */
+ /* synthesis LPF_RESISTOR="16" */;
+
+ assign CLKOP = CLKOP_t;
+
+
+ // exemplar begin
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKOP 48.000000
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKI 200.000000
+ // exemplar attribute PLLInst_0 ICP_CURRENT 5
+ // exemplar attribute PLLInst_0 LPF_RESISTOR 16
+ // exemplar end
+
+endmodule
diff --git a/boards/ulx3s-v2.0-12f-sp/clocks/clk_25M_200M.v b/boards/ulx3s-v2.0-12f-sp/clocks/clk_25M_200M.v
new file mode 100644
index 0000000..0ce5c18
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/clocks/clk_25M_200M.v
@@ -0,0 +1,75 @@
+/* Verilog netlist generated by SCUBA Diamond (64-bit) 3.7.0.96.1 */
+/* Module Version: 5.7 */
+/* /mt/lattice/diamond/3.7_x64/ispfpga/bin/lin64/scuba -w -n clk_25M_200M -lang verilog -synth synplify -bus_exp 7 -bb -arch sa5p00 -type pll -fin 25.00 -fclkop 200.00 -fclkop_tol 0.0 -phase_cntl STATIC -fb_mode 1 -fdc /home/guest/src/fpga/usbserial-core/TinyFPGA-Bootloader/boards/ulx3s/clock/clk_25M_200M/clk_25M_200M.fdc */
+/* Wed Jul 11 00:09:44 2018 */
+
+
+`timescale 1 ns / 1 ps
+module clk_25M_200M (CLKI, CLKOP)/* synthesis NGD_DRC_MASK=1 */;
+ input wire CLKI;
+ output wire CLKOP;
+
+ wire REFCLK;
+ wire LOCK;
+ wire CLKOP_t;
+ wire scuba_vhi;
+ wire scuba_vlo;
+
+ VHI scuba_vhi_inst (.Z(scuba_vhi));
+
+ VLO scuba_vlo_inst (.Z(scuba_vlo));
+
+ defparam PLLInst_0.PLLRST_ENA = "DISABLED" ;
+ defparam PLLInst_0.INTFB_WAKE = "DISABLED" ;
+ defparam PLLInst_0.STDBY_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.DPHASE_SOURCE = "DISABLED" ;
+ defparam PLLInst_0.CLKOS3_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS3_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_CPHASE = 2 ;
+ defparam PLLInst_0.PLL_LOCK_MODE = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.CLKOP_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOP_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXD = "DIVD" ;
+ defparam PLLInst_0.CLKOS3_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXC = "DIVC" ;
+ defparam PLLInst_0.CLKOS2_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXB = "DIVB" ;
+ defparam PLLInst_0.CLKOS_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXA = "DIVA" ;
+ defparam PLLInst_0.CLKOP_ENABLE = "ENABLED" ;
+ defparam PLLInst_0.CLKOS3_DIV = 1 ;
+ defparam PLLInst_0.CLKOS2_DIV = 1 ;
+ defparam PLLInst_0.CLKOS_DIV = 1 ;
+ defparam PLLInst_0.CLKOP_DIV = 3 ;
+ defparam PLLInst_0.CLKFB_DIV = 8 ;
+ defparam PLLInst_0.CLKI_DIV = 1 ;
+ defparam PLLInst_0.FEEDBK_PATH = "CLKOP" ;
+ EHXPLLL PLLInst_0 (.CLKI(CLKI), .CLKFB(CLKOP_t), .PHASESEL1(scuba_vlo),
+ .PHASESEL0(scuba_vlo), .PHASEDIR(scuba_vlo), .PHASESTEP(scuba_vlo),
+ .PHASELOADREG(scuba_vlo), .STDBY(scuba_vlo), .PLLWAKESYNC(scuba_vlo),
+ .RST(scuba_vlo), .ENCLKOP(scuba_vlo), .ENCLKOS(scuba_vlo), .ENCLKOS2(scuba_vlo),
+ .ENCLKOS3(scuba_vlo), .CLKOP(CLKOP_t), .CLKOS(), .CLKOS2(), .CLKOS3(),
+ .LOCK(LOCK), .INTLOCK(), .REFCLK(REFCLK), .CLKINTFB())
+ /* synthesis FREQUENCY_PIN_CLKOP="200.000000" */
+ /* synthesis FREQUENCY_PIN_CLKI="25.000000" */
+ /* synthesis ICP_CURRENT="5" */
+ /* synthesis LPF_RESISTOR="16" */;
+
+ assign CLKOP = CLKOP_t;
+
+
+ // exemplar begin
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKOP 200.000000
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKI 25.000000
+ // exemplar attribute PLLInst_0 ICP_CURRENT 5
+ // exemplar attribute PLLInst_0 LPF_RESISTOR 16
+ // exemplar end
+
+endmodule
diff --git a/boards/ulx3s-v2.0-12f-sp/constraints/ulx3s_v17patch.lpf b/boards/ulx3s-v2.0-12f-sp/constraints/ulx3s_v17patch.lpf
new file mode 100644
index 0000000..8e0d34c
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/constraints/ulx3s_v17patch.lpf
@@ -0,0 +1,435 @@
+BLOCK RESETPATHS;
+BLOCK ASYNCPATHS;
+## ULX3S v1.7 patched towards v1.8
+
+# The clock "usb" and "gpdi" sheet
+LOCATE COMP "clk_25mhz" SITE "G2";
+IOBUF PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33;
+FREQUENCY PORT "clk_25mhz" 25 MHZ;
+
+# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash
+SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 SLAVE_SPI_PORT=DISABLE MASTER_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE;
+
+## USBSERIAL FTDI-FPGA serial port "usb" sheet
+LOCATE COMP "ftdi_rxd" SITE "L4"; # FPGA transmits to ftdi
+LOCATE COMP "ftdi_txd" SITE "M1"; # FPGA receives from ftdi
+LOCATE COMP "ftdi_nrts" SITE "M3"; # FPGA receives
+LOCATE COMP "ftdi_ndtr" SITE "N1"; # FPGA receives
+LOCATE COMP "ftdi_txden" SITE "L3"; # FPGA receives
+IOBUF PORT "ftdi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "ftdi_txd" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_nrts" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_ndtr" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_txden" PULLMODE=UP IO_TYPE=LVCMOS33;
+
+## LED indicators "blinkey" and "gpio" sheet
+LOCATE COMP "led[7]" SITE "H3";
+LOCATE COMP "led[6]" SITE "E1";
+LOCATE COMP "led[5]" SITE "E2";
+LOCATE COMP "led[4]" SITE "D1";
+LOCATE COMP "led[3]" SITE "D2";
+LOCATE COMP "led[2]" SITE "C1";
+LOCATE COMP "led[1]" SITE "C2";
+LOCATE COMP "led[0]" SITE "B2";
+IOBUF PORT "led[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Pushbuttons "blinkey", "flash", "power", "gpdi" sheet
+LOCATE COMP "btn[0]" SITE "D6"; # BTN_PWRn (inverted logic)
+LOCATE COMP "btn[1]" SITE "R1"; # FIRE1
+LOCATE COMP "btn[2]" SITE "T1"; # FIRE2
+LOCATE COMP "btn[3]" SITE "W1"; # UP
+LOCATE COMP "btn[4]" SITE "V1"; # DOWN
+LOCATE COMP "btn[5]" SITE "U1"; # LEFT
+LOCATE COMP "btn[6]" SITE "Y2"; # RIGHT
+IOBUF PORT "btn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[4]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[5]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[6]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## DIP switch "blinkey", "gpio" sheet
+LOCATE COMP "sw[0]" SITE "E8"; # SW1
+LOCATE COMP "sw[1]" SITE "D8"; # SW2
+LOCATE COMP "sw[2]" SITE "D7"; # SW3
+LOCATE COMP "sw[3]" SITE "E7"; # SW4
+IOBUF PORT "sw[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI OLED DISPLAY SSD1331 (Color) or SSD1306 (B/W) "blinkey", "usb" sheet
+LOCATE COMP "oled_clk" SITE "P4";
+LOCATE COMP "oled_mosi" SITE "P3";
+LOCATE COMP "oled_dc" SITE "P1";
+LOCATE COMP "oled_resn" SITE "P2";
+LOCATE COMP "oled_csn" SITE "N2";
+IOBUF PORT "oled_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_dc" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_resn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI Flash chip "flash" sheet
+LOCATE COMP "flash_csn" SITE "R2";
+LOCATE COMP "flash_clk" SITE "U3";
+LOCATE COMP "flash_mosi" SITE "W2";
+LOCATE COMP "flash_miso" SITE "V2";
+#LOCATE COMP "flash_csspin" SITE "AJ3";
+#LOCATE COMP "flash_initn" SITE "AG4";
+#LOCATE COMP "flash_done" SITE "AJ4";
+#LOCATE COMP "flash_programn" SITE "AH4";
+#LOCATE COMP "flash_cfg_select[0]" SITE "AM4";
+#LOCATE COMP "flash_cfg_select[1]" SITE "AL4";
+#LOCATE COMP "flash_cfg_select[2]" SITE "AK4";
+IOBUF PORT "flash_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_clk" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_csspin" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_initn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SD card "sdcard", "usb" sheet
+LOCATE COMP "sd_clk" SITE "J1"; # sd_clk WiFi_GPIO14
+LOCATE COMP "sd_cmd" SITE "J3"; # sd_cmd_di (MOSI) WiFi GPIO15
+LOCATE COMP "sd_d[0]" SITE "K2"; # sd_dat0_do (MISO) WiFi GPIO2
+LOCATE COMP "sd_d[1]" SITE "K1"; # sd_dat1_irq WiFi GPIO4
+LOCATE COMP "sd_d[2]" SITE "H2"; # sd_dat2 WiFi_GPIO12
+LOCATE COMP "sd_d[3]" SITE "H1"; # sd_dat3_csn WiFi_GPIO13
+LOCATE COMP "sd_wp" SITE "P5"; # not connected
+LOCATE COMP "sd_cdn" SITE "N5"; # not connected
+IOBUF PORT "sd_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cmd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; # WiFi GPIO12 pulldown bootstrapping requirement
+IOBUF PORT "sd_d[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_wp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## ADC SPI (MAX11123) "analog", "ram" sheet
+LOCATE COMP "adc_csn" SITE "R17";
+LOCATE COMP "adc_mosi" SITE "R16";
+LOCATE COMP "adc_miso" SITE "U16";
+LOCATE COMP "adc_sclk" SITE "P17";
+IOBUF PORT "adc_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_sclk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Audio 4-bit DAC "analog", "gpio" sheet
+# 4-bit mode can drive down to 75 ohm load impedance.
+# Lower impedance leads to IO overload,
+# FPGA will stop working and need reboot.
+# For standard 17 ohm earphones:
+# use bits 2,3 as input (High-Z) and drive only bits 0,1.
+LOCATE COMP "audio_l[3]" SITE "B3"; # JACK TIP (left audio)
+LOCATE COMP "audio_l[2]" SITE "C3";
+LOCATE COMP "audio_l[1]" SITE "D3";
+LOCATE COMP "audio_l[0]" SITE "E4";
+LOCATE COMP "audio_r[3]" SITE "C5"; # JACK RING1 (right audio)
+LOCATE COMP "audio_r[2]" SITE "D5";
+LOCATE COMP "audio_r[1]" SITE "B5";
+LOCATE COMP "audio_r[0]" SITE "A3";
+LOCATE COMP "audio_v[3]" SITE "E5"; # JACK RING2 (video or digital audio)
+LOCATE COMP "audio_v[2]" SITE "F5";
+LOCATE COMP "audio_v[1]" SITE "F2";
+LOCATE COMP "audio_v[0]" SITE "H5";
+IOBUF PORT "audio_l[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## WiFi ESP-32 "wifi", "usb", "flash" sheet
+# other pins are shared with GP/GN, SD card and JTAG
+LOCATE COMP "wifi_en" SITE "F1"; # enable/reset WiFi
+LOCATE COMP "wifi_rxd" SITE "K3"; # FPGA transmits to WiFi
+LOCATE COMP "wifi_txd" SITE "K4"; # FPGA receives from WiFi
+LOCATE COMP "wifi_gpio0" SITE "L2";
+LOCATE COMP "wifi_gpio5" SITE "N4"; # WIFI LED
+LOCATE COMP "wifi_gpio16" SITE "L1";
+LOCATE COMP "wifi_gpio17" SITE "N3";
+# LOCATE COMP "prog_done" SITE "Y3"; # not GPIO, always active
+IOBUF PORT "wifi_en" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_txd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio16" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio17" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+# IOBUF PORT "prog_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## PCB antenna 433 MHz (may be also used for FM) "usb" sheet
+LOCATE COMP "ant_433mhz" SITE "G1";
+IOBUF PORT "ant_433mhz" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Second USB port going directly into FPGA "usb", "ram" sheet
+LOCATE COMP "usb_fpga_dp" SITE "E16";
+LOCATE COMP "usb_fpga_dn" SITE "F16";
+IOBUF PORT "usb_fpga_dp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## JTAG ESP-32 "usb" sheet
+# connected to FT231X and ESP-32
+# commented out because those are dedicated pins, not directly useable as GPIO
+# but could be used by some vendor-specific JTAG bridging (boundary scan) module
+#LOCATE COMP "jtag_tdi" SITE "R5"; # FTDI_nRI FPGA receives
+#LOCATE COMP "jtag_tdo" SITE "V4"; # FTDI_nCTS FPGA transmits
+#LOCATE COMP "jtag_tck" SITE "T5"; # FTDI_nDSR FPGA receives
+#LOCATE COMP "jtag_tms" SITE "U5"; # FTDI_nDCD FPGA receives
+#IOBUF PORT "jtag_tdi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tdo" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tck" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tms" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SDRAM "ram" sheet
+LOCATE COMP "sdram_clk" SITE "F19";
+LOCATE COMP "sdram_cke" SITE "F20";
+LOCATE COMP "sdram_csn" SITE "P20";
+LOCATE COMP "sdram_wen" SITE "T20";
+LOCATE COMP "sdram_rasn" SITE "R20";
+LOCATE COMP "sdram_casn" SITE "T19";
+LOCATE COMP "sdram_a[0]" SITE "M20";
+LOCATE COMP "sdram_a[1]" SITE "M19";
+LOCATE COMP "sdram_a[2]" SITE "L20";
+LOCATE COMP "sdram_a[3]" SITE "L19";
+LOCATE COMP "sdram_a[4]" SITE "K20";
+LOCATE COMP "sdram_a[5]" SITE "K19";
+LOCATE COMP "sdram_a[6]" SITE "K18";
+LOCATE COMP "sdram_a[7]" SITE "J20";
+LOCATE COMP "sdram_a[8]" SITE "J19";
+LOCATE COMP "sdram_a[9]" SITE "H20";
+LOCATE COMP "sdram_a[10]" SITE "N19";
+LOCATE COMP "sdram_a[11]" SITE "G20";
+LOCATE COMP "sdram_a[12]" SITE "G19";
+LOCATE COMP "sdram_ba[0]" SITE "P19";
+LOCATE COMP "sdram_ba[1]" SITE "N20";
+LOCATE COMP "sdram_dqm[0]" SITE "U19";
+LOCATE COMP "sdram_dqm[1]" SITE "E20";
+LOCATE COMP "sdram_d[0]" SITE "J16";
+LOCATE COMP "sdram_d[1]" SITE "L18";
+LOCATE COMP "sdram_d[2]" SITE "M18";
+LOCATE COMP "sdram_d[3]" SITE "N18";
+LOCATE COMP "sdram_d[4]" SITE "P18";
+LOCATE COMP "sdram_d[5]" SITE "T18";
+LOCATE COMP "sdram_d[6]" SITE "T17";
+LOCATE COMP "sdram_d[7]" SITE "U20";
+LOCATE COMP "sdram_d[8]" SITE "E19";
+LOCATE COMP "sdram_d[9]" SITE "D20";
+LOCATE COMP "sdram_d[10]" SITE "D19";
+LOCATE COMP "sdram_d[11]" SITE "C20";
+LOCATE COMP "sdram_d[12]" SITE "E18";
+LOCATE COMP "sdram_d[13]" SITE "F18";
+LOCATE COMP "sdram_d[14]" SITE "J18";
+LOCATE COMP "sdram_d[15]" SITE "J17";
+IOBUF PORT "sdram_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_cke" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_wen" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_rasn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_casn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[13]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[14]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[15]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPDI differential interface (Video) "gpdi" sheet
+LOCATE COMP "gpdi_dp[0]" SITE "A16"; # Blue +
+LOCATE COMP "gpdi_dn[0]" SITE "B16"; # Blue -
+LOCATE COMP "gpdi_dp[1]" SITE "A14"; # Green +
+LOCATE COMP "gpdi_dn[1]" SITE "C14"; # Green -
+LOCATE COMP "gpdi_dp[2]" SITE "A12"; # Red +
+LOCATE COMP "gpdi_dn[2]" SITE "A13"; # Read +
+LOCATE COMP "gpdi_ethp" SITE "A19"; # Ethernet +
+LOCATE COMP "gpdi_ethn" SITE "B20"; # Ethernet -
+LOCATE COMP "gpdi_clkp" SITE "A17"; # Clock +
+LOCATE COMP "gpdi_clkn" SITE "B18"; # Clock -
+LOCATE COMP "gpdi_cec" SITE "A18";
+LOCATE COMP "gpdi_sda" SITE "B19"; # I2C shared with RTC
+LOCATE COMP "gpdi_scl" SITE "C12"; # I2C shared with RTC
+IOBUF PORT "gpdi_dp[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_clkp" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_clkn" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethp" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethn" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_cec" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_sda" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_scl" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPIO (default single-ended) "gpio", "ram", "gpdi" sheet
+# Pins enumerated gp[0-27], gn[0-27].
+# With differential mode enabled on Lattice,
+# gp[] (+) are used, gn[] (-) are ignored from design
+# as they handle inverted signal by default.
+# To enable differential, rename LVCMOS33->LVCMOS33D
+LOCATE COMP "gp[0]" SITE "B11"; # J1_5+ GP0
+LOCATE COMP "gn[0]" SITE "C11"; # J1_5- GN0
+LOCATE COMP "gp[1]" SITE "A10"; # J1_7+ GP1
+LOCATE COMP "gn[1]" SITE "A11"; # J1_7- GN1
+LOCATE COMP "gp[2]" SITE "A9"; # J1_9+ GP2
+LOCATE COMP "gn[2]" SITE "B10"; # J1_9- GN2
+LOCATE COMP "gp[3]" SITE "B9"; # J1_11+ GP3
+LOCATE COMP "gn[3]" SITE "C10"; # J1_11- GN3
+LOCATE COMP "gp[4]" SITE "A7"; # J1_13+ GP4
+LOCATE COMP "gn[4]" SITE "A8"; # J1_13- GN4
+LOCATE COMP "gp[5]" SITE "C8"; # J1_15+ GP5
+LOCATE COMP "gn[5]" SITE "B8"; # J1_15- GN5
+LOCATE COMP "gp[6]" SITE "C6"; # J1_17+ GP6
+LOCATE COMP "gn[6]" SITE "C7"; # J1_17- GN6
+IOBUF PORT "gp[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[7]" SITE "A6"; # J1_23+ GP7
+LOCATE COMP "gn[7]" SITE "B6"; # J1_23- GN7
+LOCATE COMP "gp[8]" SITE "A4"; # J1_25+ GP8
+LOCATE COMP "gn[8]" SITE "A5"; # J1_25- GN8
+LOCATE COMP "gp[9]" SITE "A2"; # J1_27+ GP9
+LOCATE COMP "gn[9]" SITE "B1"; # J1_27- GN9
+LOCATE COMP "gp[10]" SITE "C4"; # J1_29+ GP10 WIFI_GPIO27
+LOCATE COMP "gn[10]" SITE "B4"; # J1_29- GN10
+LOCATE COMP "gp[11]" SITE "F4"; # J1_31+ GP11 WIFI_GPIO25
+LOCATE COMP "gn[11]" SITE "E3"; # J1_31- GN11 WIFI_GPIO26
+LOCATE COMP "gp[12]" SITE "G3"; # J1_33+ GP12 WIFI_GPIO32
+LOCATE COMP "gn[12]" SITE "F3"; # J1_33- GN12 WIFI_GPIO33
+LOCATE COMP "gp[13]" SITE "H4"; # J1_35+ GP13 WIFI_GPIO34
+LOCATE COMP "gn[13]" SITE "G5"; # J1_35- GN13 WIFI_GPIO35
+IOBUF PORT "gp[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[14]" SITE "U18"; # J2_5+ GP14
+LOCATE COMP "gn[14]" SITE "U17"; # J2_5- GN14
+LOCATE COMP "gp[15]" SITE "N17"; # J2_7+ GP15
+LOCATE COMP "gn[15]" SITE "P16"; # J2_7- GN15
+LOCATE COMP "gp[16]" SITE "N16"; # J2_9+ GP16
+LOCATE COMP "gn[16]" SITE "M17"; # J2_9- GN16
+LOCATE COMP "gp[17]" SITE "L16"; # J2_11+ GP17
+LOCATE COMP "gn[17]" SITE "L17"; # J2_11- GN17
+LOCATE COMP "gp[18]" SITE "H18"; # J2_13+ GP18
+LOCATE COMP "gn[18]" SITE "H17"; # J2_13- GN18
+LOCATE COMP "gp[19]" SITE "F17"; # J2_15+ GP19
+LOCATE COMP "gn[19]" SITE "G18"; # J2_15- GN19
+LOCATE COMP "gp[20]" SITE "D18"; # J2_17+ GP20
+LOCATE COMP "gn[20]" SITE "E17"; # J2_17- GN20
+IOBUF PORT "gp[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[21]" SITE "C18"; # J2_23+ GP21
+LOCATE COMP "gn[21]" SITE "D17"; # J2_23- GN21
+LOCATE COMP "gp[22]" SITE "D15"; # J2_25+ GP22
+LOCATE COMP "gn[22]" SITE "E15"; # J2_25- GN22
+LOCATE COMP "gp[23]" SITE "B17"; # J2_27+ GP23
+LOCATE COMP "gn[23]" SITE "C17"; # J2_27- GN23
+LOCATE COMP "gp[24]" SITE "C16"; # J2_29+ GP24
+LOCATE COMP "gn[24]" SITE "D16"; # J2_29- GN24
+LOCATE COMP "gp[25]" SITE "B15"; # J2_31+ GP25
+LOCATE COMP "gn[25]" SITE "C15"; # J2_31- GN25
+LOCATE COMP "gp[26]" SITE "B13"; # J2_33+ GP26
+LOCATE COMP "gn[26]" SITE "C13"; # J2_33- GN26
+LOCATE COMP "gp[27]" SITE "D13"; # J2_35+ GP27
+LOCATE COMP "gn[27]" SITE "E13"; # J2_35- GN27
+IOBUF PORT "gp[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SHUTDOWN "power", "ram" sheet (connected from PCB v1.7.5)
+# on PCB v1.7 shutdown is not connected to FPGA
+LOCATE COMP "shutdown" SITE "G16"; # FPGA receives
+IOBUF PORT "shutdown" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
diff --git a/boards/ulx3s-v2.0-12f-sp/constraints/ulx3s_v20.lpf b/boards/ulx3s-v2.0-12f-sp/constraints/ulx3s_v20.lpf
new file mode 100644
index 0000000..e04bc4f
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/constraints/ulx3s_v20.lpf
@@ -0,0 +1,452 @@
+BLOCK RESETPATHS;
+BLOCK ASYNCPATHS;
+## ULX3S v2.0 and v2.1
+
+# The clock "usb" and "gpdi" sheet
+LOCATE COMP "clk_25mhz" SITE "G2";
+IOBUF PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33;
+FREQUENCY PORT "clk_25mhz" 25 MHZ;
+
+# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash
+SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 MASTER_SPI_PORT=DISABLE SLAVE_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE;
+
+## USBSERIAL FTDI-FPGA serial port "usb" sheet
+LOCATE COMP "ftdi_rxd" SITE "L4"; # FPGA transmits to ftdi
+LOCATE COMP "ftdi_txd" SITE "M1"; # FPGA receives from ftdi
+LOCATE COMP "ftdi_nrts" SITE "M3"; # FPGA receives
+LOCATE COMP "ftdi_ndtr" SITE "N1"; # FPGA receives
+LOCATE COMP "ftdi_txden" SITE "L3"; # FPGA receives
+IOBUF PORT "ftdi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "ftdi_txd" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_nrts" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_ndtr" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_txden" PULLMODE=UP IO_TYPE=LVCMOS33;
+
+## LED indicators "blinkey" and "gpio" sheet
+LOCATE COMP "led[7]" SITE "H3";
+LOCATE COMP "led[6]" SITE "E1";
+LOCATE COMP "led[5]" SITE "E2";
+LOCATE COMP "led[4]" SITE "D1";
+LOCATE COMP "led[3]" SITE "D2";
+LOCATE COMP "led[2]" SITE "C1";
+LOCATE COMP "led[1]" SITE "C2";
+LOCATE COMP "led[0]" SITE "B2";
+IOBUF PORT "led[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Pushbuttons "blinkey", "flash", "power", "gpdi" sheet
+LOCATE COMP "btn[0]" SITE "D6"; # BTN_PWRn (inverted logic)
+LOCATE COMP "btn[1]" SITE "R1"; # FIRE1
+LOCATE COMP "btn[2]" SITE "T1"; # FIRE2
+LOCATE COMP "btn[3]" SITE "R18"; # UP W1->R18
+LOCATE COMP "btn[4]" SITE "V1"; # DOWN
+LOCATE COMP "btn[5]" SITE "U1"; # LEFT
+LOCATE COMP "btn[6]" SITE "H16"; # RIGHT Y2->H16
+IOBUF PORT "btn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[4]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[5]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[6]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## DIP switch "blinkey", "gpio" sheet
+LOCATE COMP "sw[0]" SITE "E8"; # SW1
+LOCATE COMP "sw[1]" SITE "D8"; # SW2
+LOCATE COMP "sw[2]" SITE "D7"; # SW3
+LOCATE COMP "sw[3]" SITE "E7"; # SW4
+IOBUF PORT "sw[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI OLED DISPLAY SSD1331 (Color) or SSD1306 (B/W) "blinkey", "usb" sheet
+LOCATE COMP "oled_clk" SITE "P4";
+LOCATE COMP "oled_mosi" SITE "P3";
+LOCATE COMP "oled_dc" SITE "P1";
+LOCATE COMP "oled_resn" SITE "P2";
+LOCATE COMP "oled_csn" SITE "N2";
+IOBUF PORT "oled_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_dc" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_resn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI Flash chip "flash" sheet
+LOCATE COMP "flash_csn" SITE "R2";
+LOCATE COMP "flash_mosi" SITE "W2";
+LOCATE COMP "flash_miso" SITE "V2";
+LOCATE COMP "flash_holdn" SITE "W1";
+LOCATE COMP "flash_wpn" SITE "Y2";
+#LOCATE COMP "flash_clk" SITE "U3";
+#LOCATE COMP "flash_csspin" SITE "AJ3";
+#LOCATE COMP "flash_initn" SITE "AG4";
+#LOCATE COMP "flash_done" SITE "AJ4";
+#LOCATE COMP "flash_programn" SITE "AH4";
+#LOCATE COMP "flash_cfg_select[0]" SITE "AM4";
+#LOCATE COMP "flash_cfg_select[1]" SITE "AL4";
+#LOCATE COMP "flash_cfg_select[2]" SITE "AK4";
+IOBUF PORT "flash_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_holdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_wpn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_clk" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_csspin" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_initn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SD card "sdcard", "usb" sheet
+LOCATE COMP "sd_clk" SITE "H2"; # sd_clk WiFi_GPIO14
+LOCATE COMP "sd_cmd" SITE "J1"; # sd_cmd_di (MOSI) WiFi GPIO15
+LOCATE COMP "sd_d[0]" SITE "J3"; # sd_dat0_do (MISO) WiFi GPIO2
+LOCATE COMP "sd_d[1]" SITE "H1"; # sd_dat1_irq WiFi GPIO4
+LOCATE COMP "sd_d[2]" SITE "K1"; # sd_dat2 WiFi_GPIO12
+LOCATE COMP "sd_d[3]" SITE "K2"; # sd_dat3_csn WiFi_GPIO13
+LOCATE COMP "sd_wp" SITE "P5"; # not connected
+LOCATE COMP "sd_cdn" SITE "N5"; # not connected
+IOBUF PORT "sd_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cmd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; # WiFi GPIO12 pulldown bootstrapping requirement
+IOBUF PORT "sd_d[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_wp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## ADC SPI (MAX11123) "analog", "ram" sheet
+LOCATE COMP "adc_csn" SITE "R17";
+LOCATE COMP "adc_mosi" SITE "R16";
+LOCATE COMP "adc_miso" SITE "U16";
+LOCATE COMP "adc_sclk" SITE "P17";
+IOBUF PORT "adc_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_sclk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Audio 4-bit DAC "analog", "gpio" sheet
+# 4-bit mode can drive down to 75 ohm load impedance.
+# Lower impedance leads to IO overload,
+# FPGA will stop working and need reboot.
+# For standard 17 ohm earphones:
+# use bits 2,3 as input (High-Z) and drive only bits 0,1.
+LOCATE COMP "audio_l[3]" SITE "B3"; # JACK TIP (left audio)
+LOCATE COMP "audio_l[2]" SITE "C3";
+LOCATE COMP "audio_l[1]" SITE "D3";
+LOCATE COMP "audio_l[0]" SITE "E4";
+LOCATE COMP "audio_r[3]" SITE "C5"; # JACK RING1 (right audio)
+LOCATE COMP "audio_r[2]" SITE "D5";
+LOCATE COMP "audio_r[1]" SITE "B5";
+LOCATE COMP "audio_r[0]" SITE "A3";
+LOCATE COMP "audio_v[3]" SITE "E5"; # JACK RING2 (video or digital audio)
+LOCATE COMP "audio_v[2]" SITE "F5";
+LOCATE COMP "audio_v[1]" SITE "F2";
+LOCATE COMP "audio_v[0]" SITE "H5";
+IOBUF PORT "audio_l[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## WiFi ESP-32 "wifi", "usb", "flash" sheet
+# other pins are shared with GP/GN, SD card and JTAG
+LOCATE COMP "wifi_en" SITE "F1"; # enable/reset WiFi
+LOCATE COMP "wifi_rxd" SITE "K3"; # FPGA transmits to WiFi
+LOCATE COMP "wifi_txd" SITE "K4"; # FPGA receives from WiFi
+LOCATE COMP "wifi_gpio0" SITE "L2";
+LOCATE COMP "wifi_gpio5" SITE "N4"; # WIFI LED
+LOCATE COMP "wifi_gpio16" SITE "L1"; # Serial1 RX
+LOCATE COMP "wifi_gpio17" SITE "N3"; # Serial1 TX
+# LOCATE COMP "prog_done" SITE "Y3"; # not GPIO, always active
+IOBUF PORT "wifi_en" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_txd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio16" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio17" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+# IOBUF PORT "prog_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## PCB antenna 433 MHz (may be also used for FM) "usb" sheet
+LOCATE COMP "ant_433mhz" SITE "G1";
+IOBUF PORT "ant_433mhz" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Second USB port "US2" going directly into FPGA "usb", "ram" sheet
+LOCATE COMP "usb_fpga_dp" SITE "E16"; # single ended or differential input only
+LOCATE COMP "usb_fpga_dn" SITE "F16";
+IOBUF PORT "usb_fpga_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+LOCATE COMP "usb_fpga_bd_dp" SITE "D15"; # differential bidirectional
+LOCATE COMP "usb_fpga_bd_dn" SITE "E15";
+IOBUF PORT "usb_fpga_bd_dp" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "usb_fpga_bd_dn" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=4;
+LOCATE COMP "usb_fpga_pu_dp" SITE "B12"; # pull up/down control
+LOCATE COMP "usb_fpga_pu_dn" SITE "C12";
+IOBUF PORT "usb_fpga_pu_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+IOBUF PORT "usb_fpga_pu_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+
+## JTAG ESP-32 "usb" sheet
+# connected to FT231X and ESP-32
+# commented out because those are dedicated pins, not directly useable as GPIO
+# but could be used by some vendor-specific JTAG bridging (boundary scan) module
+#LOCATE COMP "jtag_tdi" SITE "R5"; # FTDI_nRI FPGA receives
+#LOCATE COMP "jtag_tdo" SITE "V4"; # FTDI_nCTS FPGA transmits
+#LOCATE COMP "jtag_tck" SITE "T5"; # FTDI_nDSR FPGA receives
+#LOCATE COMP "jtag_tms" SITE "U5"; # FTDI_nDCD FPGA receives
+#IOBUF PORT "jtag_tdi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tdo" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tck" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tms" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SDRAM "ram" sheet
+LOCATE COMP "sdram_clk" SITE "F19";
+LOCATE COMP "sdram_cke" SITE "F20";
+LOCATE COMP "sdram_csn" SITE "P20";
+LOCATE COMP "sdram_wen" SITE "T20";
+LOCATE COMP "sdram_rasn" SITE "R20";
+LOCATE COMP "sdram_casn" SITE "T19";
+LOCATE COMP "sdram_a[0]" SITE "M20";
+LOCATE COMP "sdram_a[1]" SITE "M19";
+LOCATE COMP "sdram_a[2]" SITE "L20";
+LOCATE COMP "sdram_a[3]" SITE "L19";
+LOCATE COMP "sdram_a[4]" SITE "K20";
+LOCATE COMP "sdram_a[5]" SITE "K19";
+LOCATE COMP "sdram_a[6]" SITE "K18";
+LOCATE COMP "sdram_a[7]" SITE "J20";
+LOCATE COMP "sdram_a[8]" SITE "J19";
+LOCATE COMP "sdram_a[9]" SITE "H20";
+LOCATE COMP "sdram_a[10]" SITE "N19";
+LOCATE COMP "sdram_a[11]" SITE "G20";
+LOCATE COMP "sdram_a[12]" SITE "G19";
+LOCATE COMP "sdram_ba[0]" SITE "P19";
+LOCATE COMP "sdram_ba[1]" SITE "N20";
+LOCATE COMP "sdram_dqm[0]" SITE "U19";
+LOCATE COMP "sdram_dqm[1]" SITE "E20";
+LOCATE COMP "sdram_d[0]" SITE "J16";
+LOCATE COMP "sdram_d[1]" SITE "L18";
+LOCATE COMP "sdram_d[2]" SITE "M18";
+LOCATE COMP "sdram_d[3]" SITE "N18";
+LOCATE COMP "sdram_d[4]" SITE "P18";
+LOCATE COMP "sdram_d[5]" SITE "T18";
+LOCATE COMP "sdram_d[6]" SITE "T17";
+LOCATE COMP "sdram_d[7]" SITE "U20";
+LOCATE COMP "sdram_d[8]" SITE "E19";
+LOCATE COMP "sdram_d[9]" SITE "D20";
+LOCATE COMP "sdram_d[10]" SITE "D19";
+LOCATE COMP "sdram_d[11]" SITE "C20";
+LOCATE COMP "sdram_d[12]" SITE "E18";
+LOCATE COMP "sdram_d[13]" SITE "F18";
+LOCATE COMP "sdram_d[14]" SITE "J18";
+LOCATE COMP "sdram_d[15]" SITE "J17";
+IOBUF PORT "sdram_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_cke" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_wen" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_rasn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_casn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[13]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[14]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[15]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPDI differential interface (Video) "gpdi" sheet
+LOCATE COMP "gpdi_dp[0]" SITE "A16"; # Blue +
+LOCATE COMP "gpdi_dn[0]" SITE "B16"; # Blue -
+LOCATE COMP "gpdi_dp[1]" SITE "A14"; # Green +
+LOCATE COMP "gpdi_dn[1]" SITE "C14"; # Green -
+LOCATE COMP "gpdi_dp[2]" SITE "A12"; # Red +
+LOCATE COMP "gpdi_dn[2]" SITE "A13"; # Red -
+LOCATE COMP "gpdi_dp[3]" SITE "A17"; # Clock +
+LOCATE COMP "gpdi_dn[3]" SITE "B18"; # Clock -
+LOCATE COMP "gpdi_ethp" SITE "A19"; # Ethernet +
+LOCATE COMP "gpdi_ethn" SITE "B20"; # Ethernet -
+LOCATE COMP "gpdi_cec" SITE "A18";
+LOCATE COMP "gpdi_sda" SITE "B19"; # I2C shared with RTC
+LOCATE COMP "gpdi_scl" SITE "E12"; # I2C shared with RTC C12->E12
+IOBUF PORT "gpdi_dp[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[3]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[3]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethp" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethn" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_cec" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_sda" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_scl" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPIO (default single-ended) "gpio", "ram", "gpdi" sheet
+# Pins enumerated gp[0-27], gn[0-27].
+# With differential mode enabled on Lattice,
+# gp[] (+) are used, gn[] (-) are ignored from design
+# as they handle inverted signal by default.
+# To enable differential, rename LVCMOS33->LVCMOS33D
+LOCATE COMP "gp[0]" SITE "B11"; # J1_5+ GP0
+LOCATE COMP "gn[0]" SITE "C11"; # J1_5- GN0
+LOCATE COMP "gp[1]" SITE "A10"; # J1_7+ GP1
+LOCATE COMP "gn[1]" SITE "A11"; # J1_7- GN1
+LOCATE COMP "gp[2]" SITE "A9"; # J1_9+ GP2
+LOCATE COMP "gn[2]" SITE "B10"; # J1_9- GN2
+LOCATE COMP "gp[3]" SITE "B9"; # J1_11+ GP3
+LOCATE COMP "gn[3]" SITE "C10"; # J1_11- GN3
+LOCATE COMP "gp[4]" SITE "A7"; # J1_13+ GP4
+LOCATE COMP "gn[4]" SITE "A8"; # J1_13- GN4
+LOCATE COMP "gp[5]" SITE "C8"; # J1_15+ GP5
+LOCATE COMP "gn[5]" SITE "B8"; # J1_15- GN5
+LOCATE COMP "gp[6]" SITE "C6"; # J1_17+ GP6
+LOCATE COMP "gn[6]" SITE "C7"; # J1_17- GN6
+IOBUF PORT "gp[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[7]" SITE "A6"; # J1_23+ GP7
+LOCATE COMP "gn[7]" SITE "B6"; # J1_23- GN7
+LOCATE COMP "gp[8]" SITE "A4"; # J1_25+ GP8
+LOCATE COMP "gn[8]" SITE "A5"; # J1_25- GN8
+LOCATE COMP "gp[9]" SITE "A2"; # J1_27+ GP9
+LOCATE COMP "gn[9]" SITE "B1"; # J1_27- GN9
+LOCATE COMP "gp[10]" SITE "C4"; # J1_29+ GP10 WIFI_GPIO27
+LOCATE COMP "gn[10]" SITE "B4"; # J1_29- GN10
+LOCATE COMP "gp[11]" SITE "F4"; # J1_31+ GP11 WIFI_GPIO25
+LOCATE COMP "gn[11]" SITE "E3"; # J1_31- GN11 WIFI_GPIO26
+LOCATE COMP "gp[12]" SITE "G3"; # J1_33+ GP12 WIFI_GPIO32
+LOCATE COMP "gn[12]" SITE "F3"; # J1_33- GN12 WIFI_GPIO33
+LOCATE COMP "gp[13]" SITE "H4"; # J1_35+ GP13 WIFI_GPIO34
+LOCATE COMP "gn[13]" SITE "G5"; # J1_35- GN13 WIFI_GPIO35
+IOBUF PORT "gp[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[14]" SITE "U18"; # J2_5+ GP14
+LOCATE COMP "gn[14]" SITE "U17"; # J2_5- GN14
+LOCATE COMP "gp[15]" SITE "N17"; # J2_7+ GP15
+LOCATE COMP "gn[15]" SITE "P16"; # J2_7- GN15
+LOCATE COMP "gp[16]" SITE "N16"; # J2_9+ GP16
+LOCATE COMP "gn[16]" SITE "M17"; # J2_9- GN16
+LOCATE COMP "gp[17]" SITE "L16"; # J2_11+ GP17
+LOCATE COMP "gn[17]" SITE "L17"; # J2_11- GN17
+LOCATE COMP "gp[18]" SITE "H18"; # J2_13+ GP18
+LOCATE COMP "gn[18]" SITE "H17"; # J2_13- GN18
+LOCATE COMP "gp[19]" SITE "F17"; # J2_15+ GP19
+LOCATE COMP "gn[19]" SITE "G18"; # J2_15- GN19
+LOCATE COMP "gp[20]" SITE "D18"; # J2_17+ GP20
+LOCATE COMP "gn[20]" SITE "E17"; # J2_17- GN20
+IOBUF PORT "gp[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[21]" SITE "C18"; # J2_23+ GP21
+LOCATE COMP "gn[21]" SITE "D17"; # J2_23- GN21
+LOCATE COMP "gp[22]" SITE "B15"; # J2_25+ GP22 D15->B15
+LOCATE COMP "gn[22]" SITE "C15"; # J2_25- GN22 E15->C15
+LOCATE COMP "gp[23]" SITE "B17"; # J2_27+ GP23
+LOCATE COMP "gn[23]" SITE "C17"; # J2_27- GN23
+LOCATE COMP "gp[24]" SITE "C16"; # J2_29+ GP24
+LOCATE COMP "gn[24]" SITE "D16"; # J2_29- GN24
+LOCATE COMP "gp[25]" SITE "D14"; # J2_31+ GP25 B15->D14
+LOCATE COMP "gn[25]" SITE "E14"; # J2_31- GN25 C15->E14
+LOCATE COMP "gp[26]" SITE "B13"; # J2_33+ GP26
+LOCATE COMP "gn[26]" SITE "C13"; # J2_33- GN26
+LOCATE COMP "gp[27]" SITE "D13"; # J2_35+ GP27
+LOCATE COMP "gn[27]" SITE "E13"; # J2_35- GN27
+IOBUF PORT "gp[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## PROGRAMN (reload bitstream from FLASH, exit from bootloader)
+# PCB v2.0.5 and higher
+LOCATE COMP "user_programn" SITE "M4";
+IOBUF PORT "user_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SHUTDOWN "power", "ram" sheet (connected from PCB v1.7.5)
+# on PCB v1.7 shutdown is not connected to FPGA
+LOCATE COMP "shutdown" SITE "G16"; # FPGA receives
+IOBUF PORT "shutdown" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
diff --git a/boards/ulx3s-v2.0-12f-sp/ecp5-12f.ocd b/boards/ulx3s-v2.0-12f-sp/ecp5-12f.ocd
new file mode 100644
index 0000000..00c71ad
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/ecp5-12f.ocd
@@ -0,0 +1,16 @@
+# ecp5-XXf.cfg
+# OpenOCD commands
+
+telnet_port 4444
+gdb_port 3333
+
+# JTAG TAPs
+jtag newtap lfe5u12 tap -expected-id 0x21111043 -irlen 8 -irmask 0xFF -ircapture 0x5
+#jtag newtap lfe5u25 tap -expected-id 0x41111043 -irlen 8 -irmask 0xFF -ircapture 0x5
+#jtag newtap lfe5u45 tap -expected-id 0x41112043 -irlen 8 -irmask 0xFF -ircapture 0x5
+#jtag newtap lfe5u85 tap -expected-id 0x41113043 -irlen 8 -irmask 0xFF -ircapture 0x5
+
+init
+scan_chain
+svf -tap lfe5u12.tap -quiet -progress project/project_project_sram.svf
+shutdown
diff --git a/boards/ulx3s-v2.0-12f-sp/ft2232-fpu1.ocd b/boards/ulx3s-v2.0-12f-sp/ft2232-fpu1.ocd
new file mode 100644
index 0000000..6c41311
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/ft2232-fpu1.ocd
@@ -0,0 +1,9 @@
+#
+# PLDkit FPU1 JTAG Programmer
+#
+
+interface ftdi
+ftdi_device_desc "FPU1 JTAG Programmer"
+ftdi_vid_pid 0x0403 0x6010
+ftdi_layout_init 0x3088 0x1f8b
+adapter_khz 25000
diff --git a/boards/ulx3s-v2.0-12f-sp/ft231x.ocd b/boards/ulx3s-v2.0-12f-sp/ft231x.ocd
new file mode 100644
index 0000000..f2dee26
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/ft231x.ocd
@@ -0,0 +1,15 @@
+#
+# openocd_ft232r patched for custom jtag nums and buffer_size
+#
+
+interface ft232r
+ft232r_vid_pid 0x0403 0x6015
+# ft232r_serial_desc 12345678
+ft232r_tck_num 5
+ft232r_tms_num 6
+ft232r_tdi_num 7
+ft232r_tdo_num 3
+ft232r_trst_num 2
+ft232r_srst_num 4
+ft232r_buffer_size 16384
+adapter_khz 300
diff --git a/boards/ulx3s-v2.0-12f-sp/initialize/boardmeta4MB.bin b/boards/ulx3s-v2.0-12f-sp/initialize/boardmeta4MB.bin
new file mode 100644
index 0000000..7a525c7
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/initialize/boardmeta4MB.bin
@@ -0,0 +1,119 @@
+{
+ "boardmeta":
+ {
+ "name": "ULX3S",
+ "fpga": "LFE5U-45F-6BG381C",
+ "hver": "1.7",
+ "uuid": "00000000-0000-0000-0000-000000000000",
+ "serial": 12345
+ },
+ "bootmeta":
+ {
+ "bootloader": "TinyFPGA USB Bootloader",
+ "bver": "2.0.0",
+ "update": "https://github.com/emard/TinyFPGA-Bootloader",
+ "addrmap":
+ {
+ "bootloader": "0x000000-0x0FFFFF",
+ "golden": "0x100000-0x1FFFFF",
+ "userimage": "0x200000-0x2FFFFF",
+ "userdata": "0x300000-0x3FBFFF"
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-v2.0-12f-sp/initialize/boardmeta8MB.bin b/boards/ulx3s-v2.0-12f-sp/initialize/boardmeta8MB.bin
new file mode 100644
index 0000000..89be03c
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/initialize/boardmeta8MB.bin
@@ -0,0 +1,58 @@
+{
+ "boardmeta":
+ {
+ "name": "ULX3S",
+ "fpga": "LFE5U-45F-6BG381C",
+ "hver": "1.7",
+ "uuid": "00000000-0000-0000-0000-000000000000",
+ "serial": 12345
+ },
+ "bootmeta":
+ {
+ "bootloader": "TinyFPGA USB Bootloader",
+ "bver": "2.0.0",
+ "update": "https://github.com/emard/TinyFPGA-Bootloader",
+ "addrmap":
+ {
+ "bootloader": "0x000000-0x0FFFFF",
+ "golden": "0x100000-0x1FFFFF",
+ "userimage": "0x200000-0x3FFFFF",
+ "userdata": "0x500000-0x7FBFFF"
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-v2.0-12f-sp/initialize/initialize4MB.sh b/boards/ulx3s-v2.0-12f-sp/initialize/initialize4MB.sh
new file mode 100755
index 0000000..3d67d93
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/initialize/initialize4MB.sh
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+
+# Initializer for ECP5 dual boot.
+
+# first half of the FLASH is for user bitstram
+# bootloader bitstream starts at second half of the FLASH
+# board metadata at last 0x1000 bytes
+# Jump command at last 0x100 bytes
+
+# flash size: 16 Mbit = 2 MB = 0x200000
+# flash size: 32 Mbit = 4 MB = 0x400000
+# flash size: 64 Mbit = 8 MB = 0x800000
+# flash size: 128 Mbit = 16 MB = 0x1000000
+
+bootloader_image_address=$(printf "%d" 0x000000) # 0
+golden_image_address=$(printf "%d" 0x100000) # 0x100000 (1MB) (backup of bootloader)
+board_meta_address=$(printf "%d" 0x3FF000) # flash size - 0x1000
+jump_command_address=$(printf "%d" 0x3FFF00) # flash size - 0x100
+
+# primary image must be generated by diamond deployment tool (ddtcmd)
+# simply overwriting bootloader image will not have multiboot capability
+#tinyprog --pyserial --no-boot -a $bootloader_image_address -u ../../boards/ulx3s-v1.7-45f/tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $golden_image_address -u ../tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $(printf "%d" $board_meta_address) -u boardmeta4MB.bin
+./jump.py $golden_image_address > jump.bin
+tinyprog --pyserial --no-boot -a $(printf "%d" $jump_command_address) -u jump.bin
+# hexdump -C jump.bin
+# check that's board is recognized by tingprog
+tinyprog --pyserial -l
+#tinyprog -m
diff --git a/boards/ulx3s-v2.0-12f-sp/initialize/initialize8MB.sh b/boards/ulx3s-v2.0-12f-sp/initialize/initialize8MB.sh
new file mode 100755
index 0000000..b127f53
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/initialize/initialize8MB.sh
@@ -0,0 +1,31 @@
+#!/bin/sh -e
+
+# Initializer for ECP5 dual boot.
+
+# first half of the FLASH is for user bitstram
+# bootloader bitstream starts at second half of the FLASH
+# board metadata at last 0x1000 bytes
+# Jump command at last 0x100 bytes
+
+# flash size: 8 Mbit = 1 MB = 0x100000
+# flash size: 16 Mbit = 2 MB = 0x200000
+# flash size: 32 Mbit = 4 MB = 0x400000
+# flash size: 64 Mbit = 8 MB = 0x800000
+# flash size: 128 Mbit = 16 MB = 0x1000000
+
+bootloader_image_address=$(printf "%d" 0x000000) # 0
+golden_image_address=$(printf "%d" 0x100000) # 0x100000 (1MB) (backup of bootloader)
+board_meta_address=$(printf "%d" 0x7FF000) # flash size - 0x1000 (-4KB)
+jump_command_address=$(printf "%d" 0x7FFF00) # flash size - 0x100 (-256)
+
+# primary image must be generated by diamond deployment tool (ddtcmd)
+# simply overwriting bootloader image will not have multiboot capability
+#tinyprog --pyserial --no-boot -a $bootloader_image_address -u ../../boards/ulx3s-v1.7-45f/tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $golden_image_address -u ../tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $(printf "%d" $board_meta_address) -u boardmeta8MB.bin
+./jump.py $golden_image_address > jump.bin
+tinyprog --pyserial --no-boot -a $(printf "%d" $jump_command_address) -u jump.bin
+# hexdump -C jump.bin
+# check that's board is recognized by tingprog
+tinyprog --pyserial -l
+#tinyprog -m
diff --git a/boards/ulx3s-v2.0-12f-sp/initialize/jump.bin b/boards/ulx3s-v2.0-12f-sp/initialize/jump.bin
new file mode 100644
index 0000000..d39691f
Binary files /dev/null and b/boards/ulx3s-v2.0-12f-sp/initialize/jump.bin differ
diff --git a/boards/ulx3s-v2.0-12f-sp/initialize/jump.py b/boards/ulx3s-v2.0-12f-sp/initialize/jump.py
new file mode 100755
index 0000000..b1ff948
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/initialize/jump.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+
+# Lattice ECP5 jump command generator
+# TN1216 p.23 describes the jump command syntax which does not work.
+# The syntax has been fixed by looking at dual boot intel hex file
+# generated by diamond, this actually works.
+
+import struct
+import sys
+
+# write output of this funtion at FLASH address:
+# jump_command_address = 0x3FFF00 = 4194048
+
+# write "golden" bitstream at FLASH address:
+golden_image_address = 0x140000
+golden_image_address = int(sys.argv[1])
+
+# normally both 0
+reverse_bytes = 0
+reverse_bits = 0
+
+# to compare with intel HEX file generated by diamond:
+# (not for normal use)
+# reverse_bytes = 1
+# reverse_bits = 1
+# ./jump.py | hexdump -C
+
+def reverse_Bits(n, no_of_bits):
+ result = 0
+ for i in range(no_of_bits):
+ result <<= 1
+ result |= n & 1
+ n >>= 1
+ return result
+
+def uint8(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 8)
+ return struct.pack(">B", n)
+
+def uint16(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 16)
+ if reverse_bytes:
+ return struct.pack("H", n)
+
+def uint24(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 24)
+ if reverse_bytes:
+ return struct.pack("> 8 )
+ else:
+ return struct.pack(">HB", n >> 8, n & 0xFF )
+
+def uint32(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 32)
+ if reverse_bytes:
+ return struct.pack("L", n)
+
+packet = b''
+# Frame (START) 18 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint16(0xFFFF) # 2 dummy bytes (diamond generates this 2 bytes more)
+# Preamble
+packet += uint16(0xBDB3) # Preamble
+# Frame (Control Register 0) commented out, diamond doesn't output this
+# if uncommented, jump won't work:
+#packet += uint8(0xC4) # Write control register 0 command
+#packet += uint24(0) # 24-bit Command Information
+#packet += uint32(0) # Control Register 0 data
+# This is generated by diamond:
+packet += uint32(0xFFFFFFFF) # I don't know what it does but it works
+# Framme (Jump Command)
+#packet += uint8(0xFE) # Jump command Wrong noted in TN1216
+packet += uint8(0x7E) # Jump command generated by diamond
+packet += uint24(0) # 24-bit Command Information
+packet += uint8(0x03) # SPI Flash Read opcode (0x03 = regular read, 0x0B = fast read)
+packet += uint24(golden_image_address) # 24-bit SPI Flash Sector X address
+# Frame (END) 18 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint16(0xFFFF) # 2 dummy bytes (diamond generates this 2 bytes more)
+
+sys.stdout.write(packet)
+# print([elem.encode("hex") for elem in packet])
diff --git a/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k.bit b/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k.bit
new file mode 120000
index 0000000..59e9556
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k.bit
@@ -0,0 +1 @@
+project/project_project.bit
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_multiboot_flash_is25lp032d.svf b/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_multiboot_flash_is25lp032d.svf
new file mode 120000
index 0000000..a01da25
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_multiboot_flash_is25lp032d.svf
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_is25lp032d.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_multiboot_flash_is25lp032d.vme b/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_multiboot_flash_is25lp032d.vme
new file mode 120000
index 0000000..7d99dc6
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_multiboot_flash_is25lp032d.vme
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_is25lp032d.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_multiboot_flash_is25lp128f.svf b/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_multiboot_flash_is25lp128f.svf
new file mode 120000
index 0000000..1b8f717
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_multiboot_flash_is25lp128f.svf
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_is25lp128f.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_multiboot_flash_is25lp128f.vme b/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_multiboot_flash_is25lp128f.vme
new file mode 120000
index 0000000..c736cfa
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_multiboot_flash_is25lp128f.vme
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_is25lp128f.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_multiboot_flash_s25fl164k.svf b/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_multiboot_flash_s25fl164k.svf
new file mode 120000
index 0000000..7232663
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_multiboot_flash_s25fl164k.svf
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_s25fl164k.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_multiboot_flash_s25fl164k.vme b/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_multiboot_flash_s25fl164k.vme
new file mode 120000
index 0000000..cadb80a
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_multiboot_flash_s25fl164k.vme
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_s25fl164k.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_sram.svf b/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_sram.svf
new file mode 120000
index 0000000..bb7617d
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_sram.svf
@@ -0,0 +1 @@
+project/project_project_sram.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_sram.vme b/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_sram.vme
new file mode 120000
index 0000000..d098048
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/tinyfpga_12k_sram.vme
@@ -0,0 +1 @@
+project/project_project_sram.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-12f-sp/top/bootloader_sp_ulx3s.v b/boards/ulx3s-v2.0-12f-sp/top/bootloader_sp_ulx3s.v
new file mode 100644
index 0000000..95e7e0b
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/top/bootloader_sp_ulx3s.v
@@ -0,0 +1,148 @@
+module bootloader_sp_ulx3s (
+ input clk_25mhz,
+
+ inout usb_fpga_dp,
+ inout usb_fpga_dn,
+
+ output usb_fpga_pu_dp,
+ inout user_programn,
+
+ output [7:0] led,
+
+ input flash_miso,
+ output flash_mosi,
+ output flash_csn,
+ output flash_wpn,
+ output flash_holdn,
+
+ input [6:0] btn,
+ output wifi_gpio0
+);
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// generate 48 mhz clock
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ wire clk_200mhz;
+ clk_25M_200M clk_200M_inst (
+ .CLKI(clk_25mhz),
+ .CLKOP(clk_200mhz)
+ );
+
+ wire clk_48mhz;
+ wire clk_ready;
+ clk_200M_48M clk_48M_inst (
+ .CLKI(clk_200mhz),
+ .CLKOP(clk_48mhz),
+ .LOCK(clk_ready)
+ );
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// instantiate tinyfpga bootloader
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ reg [15:0] reset_counter = 0; // counter for debouce and prolong reset
+ wire reset;
+ assign reset = ~reset_counter[15];
+ wire usb_p_tx;
+ wire usb_n_tx;
+ wire usb_p_rx;
+ wire usb_n_rx;
+ wire usb_tx_en;
+ wire pin_led;
+ wire [7:0] debug_led;
+ wire boot;
+ wire S_flash_clk;
+ wire S_flash_csn;
+
+ tinyfpgasp_bootloader tinyfpgasp_bootloader_inst (
+ .clk_48mhz(clk_48mhz),
+ .reset(reset),
+ .usb_p_tx(usb_p_tx),
+ .usb_n_tx(usb_n_tx),
+ .usb_p_rx(usb_p_rx),
+ .usb_n_rx(usb_n_rx),
+ .usb_tx_en(usb_tx_en),
+ .led(pin_led),
+ .debug_led(debug_led),
+ .spi_miso(flash_miso),
+ .spi_mosi(flash_mosi),
+ .spi_sck(S_flash_clk),
+ .spi_cs(S_flash_csn),
+ .boot(boot)
+ );
+
+ assign usb_fpga_dp = reset ? 1'b0 : (usb_tx_en ? usb_p_tx : 1'bz);
+ assign usb_fpga_dn = reset ? 1'b0 : (usb_tx_en ? usb_n_tx : 1'bz);
+ assign usb_p_rx = usb_tx_en ? 1'b1 : usb_fpga_dp;
+ assign usb_n_rx = usb_tx_en ? 1'b0 : usb_fpga_dn;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// Vendor-specific clock output to SPI config flash
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ USRMCLK usrmclk_inst (
+ .USRMCLKI(S_flash_clk),
+ .USRMCLKTS(S_flash_csn)
+ ) /* synthesis syn_noprune=1 */;
+ assign flash_csn = S_flash_csn;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// Debonuce and prolong RESET
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ always @(posedge clk_48mhz)
+ begin
+ if (btn[1] | ~clk_ready)
+ reset_counter <= 0;
+ else
+ if (reset_counter[15] == 0)
+ reset_counter <= reset_counter + 1;
+ end
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// ULX3S board buttons and LEDs
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ assign wifi_gpio0 = btn[0];
+ assign led[0] = pin_led;
+ assign led[1] = ~pin_led;
+ assign led[5] = debug_led;
+ assign led[7] = boot;
+ // assign led[3:0] = {flash_miso, flash_mosi, S_flash_clk, S_flash_csn};
+
+ // PULLUP 1.5k D+
+ assign usb_fpga_pu_dp = 1;
+
+ // set 1 to holdn wpn for use as single bit mode spi
+ assign flash_holdn = 1;
+ assign flash_wpn = 1;
+
+ // delay for BTN0 is required
+ reg [3:0] R_progn = 0;
+ always @(posedge clk_25mhz)
+ if(btn[0])
+ R_progn <= 0;
+ else
+ R_progn <= R_progn + 1;
+
+ // EXIT from BOOTLOADER
+ assign user_programn = ~boot & ~R_progn[3];
+
+endmodule
diff --git a/boards/ulx3s-v2.0-12f-sp/ulx3s_12f_multiboot_flash_is25lp032d.xcf b/boards/ulx3s-v2.0-12f-sp/ulx3s_12f_multiboot_flash_is25lp032d.xcf
new file mode 100644
index 0000000..3a1c5a8
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/ulx3s_12f_multiboot_flash_is25lp032d.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-12F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project_multiboot_flash_is25lp032d.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-12F
+ 0x21111043
+ All
+ LFE5U-12F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ Micron
+ SPI Serial Flash
+ SPI-M25P32
+ 0x15
+ 8-pin VDFPN8
+ SPI Flash Erase,Program
+ project/project_project_multiboot_flash_is25lp032d.mcs
+ 0x00000000
+ 0x00400000
+ 32
+ 4194304
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project_multiboot_flash_is25lp032d.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v2.0-12f-sp/ulx3s_12f_multiboot_flash_is25lp128f.xcf b/boards/ulx3s-v2.0-12f-sp/ulx3s_12f_multiboot_flash_is25lp128f.xcf
new file mode 100644
index 0000000..97e9f80
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/ulx3s_12f_multiboot_flash_is25lp128f.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-12F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project_multiboot_flash_is25lp128f.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-12F
+ 0x21111043
+ All
+ LFE5U-12F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ SPANSION
+ SPI Serial Flash
+ SPI-S25FL128S
+ 0x17
+ 8-lead WSON
+ SPI Flash Erase,Program
+ project/project_project_multiboot_flash_is25lp128f.mcs
+ 0x00000000
+ 0x01000000
+ 128
+ 16777216
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project_multiboot_flash_is25lp128f.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v2.0-12f-sp/ulx3s_12f_multiboot_flash_s25fl164k.xcf b/boards/ulx3s-v2.0-12f-sp/ulx3s_12f_multiboot_flash_s25fl164k.xcf
new file mode 100644
index 0000000..9823a48
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/ulx3s_12f_multiboot_flash_s25fl164k.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ SPANSION
+ ECP5U
+ LFE5U-12F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project_multiboot_flash_s25fl164k.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-12F
+ 0x21111043
+ All
+ LFE5U-12F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ SPANSION
+ SPI Serial Flash
+ SPI-S25FL164K
+ 0x16
+ 8-lead SOIC
+ SPI Flash Erase,Program
+ project/project_project_multiboot_flash_s25fl164k.mcs
+ 0x00000000
+ 0x00800000
+ 64
+ 8388608
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project_multiboot_flash_s25fl164k.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v2.0-12f-sp/ulx3s_12f_sram.xcf b/boards/ulx3s-v2.0-12f-sp/ulx3s_12f_sram.xcf
new file mode 100644
index 0000000..7d59714
--- /dev/null
+++ b/boards/ulx3s-v2.0-12f-sp/ulx3s_12f_sram.xcf
@@ -0,0 +1,48 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-12F
+ 0x21111043
+ All
+ LFE5U-12F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project.bit
+ Fast Program
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ DUAL RS232-HS A Location 0000 Serial Dual RS232-HS A
+
+
diff --git a/boards/ulx3s-v2.0-25f-sp/Makefile b/boards/ulx3s-v2.0-25f-sp/Makefile
new file mode 100644
index 0000000..e7c2a17
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/Makefile
@@ -0,0 +1,140 @@
+
+PROJ_FILE := $(shell ls *.ldf | head -1)
+PROJ_NAME := $(shell fgrep default_implementation ${PROJ_FILE} | cut -d'"' -f 4)
+IMPL_NAME := $(shell fgrep default_implementation ${PROJ_FILE} | cut -d'"' -f 8)
+IMPL_DIR := $(shell fgrep default_strategy ${PROJ_FILE} | cut -d'"' -f 4)
+
+DIAMOND_BASE := /usr/local/diamond
+DIAMOND_BIN := $(shell find ${DIAMOND_BASE}/ -maxdepth 2 -name bin | sort -rn | head -1)
+DIAMONDC := $(shell find ${DIAMOND_BIN}/ -name diamondc)
+DDTCMD := $(shell find ${DIAMOND_BIN}/ -name ddtcmd)
+
+OPENOCD = openocd_ft232r
+# OPENOCD_BASE := ../../programmer/openocd/ulx3s
+OPENOCD_BASE := .
+
+# name of the project as defined in project file
+PROJECT = project
+
+# FPGA flashing device for programming
+FPGA_DEVICE = LFE5U-25F
+
+JUNK = ${IMPL_DIR} .recovery ._Real_._Math_.vhd *.sty reportview.xml
+JUNK += dummy_sym.sort project_tcl.html promote.xml
+JUNK += generate_core.tcl generate_ngd.tcl msg_file.log
+JUNK += project_tcr.dir
+
+all: $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.svf \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.svf \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.svf \
+
+
+$(PROJECT)/$(PROJECT)_$(PROJECT).bit:
+ echo prj_project open ${PROJ_FILE} \; prj_run Export -task Bitgen | ${DIAMONDC}
+
+# same file with different name required for multiboot to work
+$(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ cp $< $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_25f_sram.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_25f_sram.xcf -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT).mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit -oft -int -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -oft -advanced -format int -flashsize 32 -header -quad 4 \
+ -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -golden $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -multi 1 -altfile $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit -address 0x200000 -next prim -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.vme: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_25f_multiboot_flash_is25lp032d.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.svf: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.mcs
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_25f_multiboot_flash_is25lp032d.xcf -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -oft -advanced -format int -flashsize 64 -header -quad 4 \
+ -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -golden $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -multi 1 -altfile $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit -address 0x200000 -next prim -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.vme: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_25f_multiboot_flash_s25fl164k.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.svf: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.mcs
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_25f_multiboot_flash_s25fl164k.xcf -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -oft -advanced -format int -flashsize 128 -header -quad 4 \
+ -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -golden $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -multi 1 -altfile $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit -address 0x200000 -next prim -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.vme: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_25f_multiboot_flash_is25lp128f.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.svf: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.mcs
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_25f_multiboot_flash_is25lp128f.xcf -of $@
+
+program: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ echo pgr_project open ulx3s_25f_sram.xcf \; pgr_program run | ${DIAMONDC}
+
+program_wifi: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ openocd --file=$(OPENOCD_BASE)/remote.ocd --file=$(OPENOCD_BASE)/ecp5-25f.ocd
+
+program_web: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ svfupload.py ulx3s.lan $<
+
+program_web_flash: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.svf
+ svfupload.py ulx3s.lan $<
+
+program_ft2232: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ openocd --file=$(OPENOCD_BASE)/ft2232-fpu1.ocd --file=$(OPENOCD_BASE)/ecp5-25f.ocd
+
+program_ft231x: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ openocd_ft232r --file=$(OPENOCD_BASE)/ft231x.ocd --file=$(OPENOCD_BASE)/ecp5-25f.ocd
+
+program_flea: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme
+ FleaFPGA-JTAG $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme
+
+program_flea_flash: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.vme
+ FleaFPGA-JTAG $<
+
+program_flea_flash_spansion: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.vme
+ FleaFPGA-JTAG $<
+
+#$(PROJECT)/$(PROJECT)_$(PROJECT).jed:
+# echo prj_project open ${PROJ_FILE} \; prj_run Export -task Jedecgen | ${DIAMONDC}
+
+#$(PROJECT)/$(PROJECT)_$(PROJECT)_flash.vme: $(PROJECT)/$(PROJECT)_$(PROJECT).jed
+# ${DDTCMD} -oft -fullvme -if sparrowhawk_flash_is25lp128f.xcf -nocompress -noheader -of $@
+
+#$(PROJECT)/$(PROJECT)_$(PROJECT)_flash.svf: $(PROJECT)/$(PROJECT)_$(PROJECT).jed
+# ${DDTCMD} -oft -svfsingle -op "FLASH Erase,Program,Verify" -if $< -of $@
+
+flash: $(PROJECT)/$(PROJECT)_$(PROJECT)_flash.vme
+ ${PROGRAMMERC} $<
+ # after this, to gain access to serial port on linux
+ # rmmod ftdi_sio; modprobe ftdi_sio
+
+# example another project
+#%.svf : %.jed
+# ${DDTCMD} -oft -svfsingle -op "FLASH Erase,Program,Verify" -if $< -of $@
+# mv -f $@ $@.flash
+# ${DDTCMD} -oft -svfsingle -revd -op "SRAM Fast Program" -if $< -of $@
+# mv -f $@ $@.sram
+# ./svf_to_urjtag.pl <$@.flash | sed 's/,/./g' > $@
+
+clean:
+ rm -rf $(JUNK) *~
diff --git a/boards/ulx3s-v2.0-25f-sp/bootloader.ldf b/boards/ulx3s-v2.0-25f-sp/bootloader.ldf
new file mode 100644
index 0000000..cfc465c
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/bootloader.ldf
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-v2.0-25f-sp/clocks/clk_200M_48M.v b/boards/ulx3s-v2.0-25f-sp/clocks/clk_200M_48M.v
new file mode 100644
index 0000000..2e9bb80
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/clocks/clk_200M_48M.v
@@ -0,0 +1,75 @@
+/* Verilog netlist generated by SCUBA Diamond (64-bit) 3.7.0.96.1 */
+/* Module Version: 5.7 */
+/* /mt/lattice/diamond/3.7_x64/ispfpga/bin/lin64/scuba -w -n clk_200M_48M -lang verilog -synth synplify -bus_exp 7 -bb -arch sa5p00 -type pll -fin 200.00 -fclkop 48.00 -fclkop_tol 0.0 -phase_cntl STATIC -fb_mode 1 -fdc /home/guest/src/fpga/usbserial-core/TinyFPGA-Bootloader/boards/ulx3s/clock/clk_200M_48M/clk_200M_48M.fdc */
+/* Wed Jul 11 00:10:22 2018 */
+
+
+`timescale 1 ns / 1 ps
+module clk_200M_48M (CLKI, CLKOP, LOCK)/* synthesis NGD_DRC_MASK=1 */;
+ input wire CLKI;
+ output wire CLKOP;
+ output wire LOCK;
+
+ wire REFCLK;
+ wire CLKOP_t;
+ wire scuba_vhi;
+ wire scuba_vlo;
+
+ VHI scuba_vhi_inst (.Z(scuba_vhi));
+
+ VLO scuba_vlo_inst (.Z(scuba_vlo));
+
+ defparam PLLInst_0.PLLRST_ENA = "DISABLED" ;
+ defparam PLLInst_0.INTFB_WAKE = "DISABLED" ;
+ defparam PLLInst_0.STDBY_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.DPHASE_SOURCE = "DISABLED" ;
+ defparam PLLInst_0.CLKOS3_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS3_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_CPHASE = 11 ;
+ defparam PLLInst_0.PLL_LOCK_MODE = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.CLKOP_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOP_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXD = "DIVD" ;
+ defparam PLLInst_0.CLKOS3_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXC = "DIVC" ;
+ defparam PLLInst_0.CLKOS2_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXB = "DIVB" ;
+ defparam PLLInst_0.CLKOS_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXA = "DIVA" ;
+ defparam PLLInst_0.CLKOP_ENABLE = "ENABLED" ;
+ defparam PLLInst_0.CLKOS3_DIV = 1 ;
+ defparam PLLInst_0.CLKOS2_DIV = 1 ;
+ defparam PLLInst_0.CLKOS_DIV = 1 ;
+ defparam PLLInst_0.CLKOP_DIV = 12 ;
+ defparam PLLInst_0.CLKFB_DIV = 6 ;
+ defparam PLLInst_0.CLKI_DIV = 25 ;
+ defparam PLLInst_0.FEEDBK_PATH = "CLKOP" ;
+ EHXPLLL PLLInst_0 (.CLKI(CLKI), .CLKFB(CLKOP_t), .PHASESEL1(scuba_vlo),
+ .PHASESEL0(scuba_vlo), .PHASEDIR(scuba_vlo), .PHASESTEP(scuba_vlo),
+ .PHASELOADREG(scuba_vlo), .STDBY(scuba_vlo), .PLLWAKESYNC(scuba_vlo),
+ .RST(scuba_vlo), .ENCLKOP(scuba_vlo), .ENCLKOS(scuba_vlo), .ENCLKOS2(scuba_vlo),
+ .ENCLKOS3(scuba_vlo), .CLKOP(CLKOP_t), .CLKOS(), .CLKOS2(), .CLKOS3(),
+ .LOCK(LOCK), .INTLOCK(), .REFCLK(REFCLK), .CLKINTFB())
+ /* synthesis FREQUENCY_PIN_CLKOP="48.000000" */
+ /* synthesis FREQUENCY_PIN_CLKI="200.000000" */
+ /* synthesis ICP_CURRENT="5" */
+ /* synthesis LPF_RESISTOR="16" */;
+
+ assign CLKOP = CLKOP_t;
+
+
+ // exemplar begin
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKOP 48.000000
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKI 200.000000
+ // exemplar attribute PLLInst_0 ICP_CURRENT 5
+ // exemplar attribute PLLInst_0 LPF_RESISTOR 16
+ // exemplar end
+
+endmodule
diff --git a/boards/ulx3s-v2.0-25f-sp/clocks/clk_25M_200M.v b/boards/ulx3s-v2.0-25f-sp/clocks/clk_25M_200M.v
new file mode 100644
index 0000000..0ce5c18
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/clocks/clk_25M_200M.v
@@ -0,0 +1,75 @@
+/* Verilog netlist generated by SCUBA Diamond (64-bit) 3.7.0.96.1 */
+/* Module Version: 5.7 */
+/* /mt/lattice/diamond/3.7_x64/ispfpga/bin/lin64/scuba -w -n clk_25M_200M -lang verilog -synth synplify -bus_exp 7 -bb -arch sa5p00 -type pll -fin 25.00 -fclkop 200.00 -fclkop_tol 0.0 -phase_cntl STATIC -fb_mode 1 -fdc /home/guest/src/fpga/usbserial-core/TinyFPGA-Bootloader/boards/ulx3s/clock/clk_25M_200M/clk_25M_200M.fdc */
+/* Wed Jul 11 00:09:44 2018 */
+
+
+`timescale 1 ns / 1 ps
+module clk_25M_200M (CLKI, CLKOP)/* synthesis NGD_DRC_MASK=1 */;
+ input wire CLKI;
+ output wire CLKOP;
+
+ wire REFCLK;
+ wire LOCK;
+ wire CLKOP_t;
+ wire scuba_vhi;
+ wire scuba_vlo;
+
+ VHI scuba_vhi_inst (.Z(scuba_vhi));
+
+ VLO scuba_vlo_inst (.Z(scuba_vlo));
+
+ defparam PLLInst_0.PLLRST_ENA = "DISABLED" ;
+ defparam PLLInst_0.INTFB_WAKE = "DISABLED" ;
+ defparam PLLInst_0.STDBY_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.DPHASE_SOURCE = "DISABLED" ;
+ defparam PLLInst_0.CLKOS3_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS3_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_CPHASE = 2 ;
+ defparam PLLInst_0.PLL_LOCK_MODE = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.CLKOP_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOP_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXD = "DIVD" ;
+ defparam PLLInst_0.CLKOS3_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXC = "DIVC" ;
+ defparam PLLInst_0.CLKOS2_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXB = "DIVB" ;
+ defparam PLLInst_0.CLKOS_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXA = "DIVA" ;
+ defparam PLLInst_0.CLKOP_ENABLE = "ENABLED" ;
+ defparam PLLInst_0.CLKOS3_DIV = 1 ;
+ defparam PLLInst_0.CLKOS2_DIV = 1 ;
+ defparam PLLInst_0.CLKOS_DIV = 1 ;
+ defparam PLLInst_0.CLKOP_DIV = 3 ;
+ defparam PLLInst_0.CLKFB_DIV = 8 ;
+ defparam PLLInst_0.CLKI_DIV = 1 ;
+ defparam PLLInst_0.FEEDBK_PATH = "CLKOP" ;
+ EHXPLLL PLLInst_0 (.CLKI(CLKI), .CLKFB(CLKOP_t), .PHASESEL1(scuba_vlo),
+ .PHASESEL0(scuba_vlo), .PHASEDIR(scuba_vlo), .PHASESTEP(scuba_vlo),
+ .PHASELOADREG(scuba_vlo), .STDBY(scuba_vlo), .PLLWAKESYNC(scuba_vlo),
+ .RST(scuba_vlo), .ENCLKOP(scuba_vlo), .ENCLKOS(scuba_vlo), .ENCLKOS2(scuba_vlo),
+ .ENCLKOS3(scuba_vlo), .CLKOP(CLKOP_t), .CLKOS(), .CLKOS2(), .CLKOS3(),
+ .LOCK(LOCK), .INTLOCK(), .REFCLK(REFCLK), .CLKINTFB())
+ /* synthesis FREQUENCY_PIN_CLKOP="200.000000" */
+ /* synthesis FREQUENCY_PIN_CLKI="25.000000" */
+ /* synthesis ICP_CURRENT="5" */
+ /* synthesis LPF_RESISTOR="16" */;
+
+ assign CLKOP = CLKOP_t;
+
+
+ // exemplar begin
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKOP 200.000000
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKI 25.000000
+ // exemplar attribute PLLInst_0 ICP_CURRENT 5
+ // exemplar attribute PLLInst_0 LPF_RESISTOR 16
+ // exemplar end
+
+endmodule
diff --git a/boards/ulx3s-v2.0-25f-sp/constraints/ulx3s_v17patch.lpf b/boards/ulx3s-v2.0-25f-sp/constraints/ulx3s_v17patch.lpf
new file mode 100644
index 0000000..8e0d34c
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/constraints/ulx3s_v17patch.lpf
@@ -0,0 +1,435 @@
+BLOCK RESETPATHS;
+BLOCK ASYNCPATHS;
+## ULX3S v1.7 patched towards v1.8
+
+# The clock "usb" and "gpdi" sheet
+LOCATE COMP "clk_25mhz" SITE "G2";
+IOBUF PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33;
+FREQUENCY PORT "clk_25mhz" 25 MHZ;
+
+# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash
+SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 SLAVE_SPI_PORT=DISABLE MASTER_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE;
+
+## USBSERIAL FTDI-FPGA serial port "usb" sheet
+LOCATE COMP "ftdi_rxd" SITE "L4"; # FPGA transmits to ftdi
+LOCATE COMP "ftdi_txd" SITE "M1"; # FPGA receives from ftdi
+LOCATE COMP "ftdi_nrts" SITE "M3"; # FPGA receives
+LOCATE COMP "ftdi_ndtr" SITE "N1"; # FPGA receives
+LOCATE COMP "ftdi_txden" SITE "L3"; # FPGA receives
+IOBUF PORT "ftdi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "ftdi_txd" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_nrts" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_ndtr" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_txden" PULLMODE=UP IO_TYPE=LVCMOS33;
+
+## LED indicators "blinkey" and "gpio" sheet
+LOCATE COMP "led[7]" SITE "H3";
+LOCATE COMP "led[6]" SITE "E1";
+LOCATE COMP "led[5]" SITE "E2";
+LOCATE COMP "led[4]" SITE "D1";
+LOCATE COMP "led[3]" SITE "D2";
+LOCATE COMP "led[2]" SITE "C1";
+LOCATE COMP "led[1]" SITE "C2";
+LOCATE COMP "led[0]" SITE "B2";
+IOBUF PORT "led[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Pushbuttons "blinkey", "flash", "power", "gpdi" sheet
+LOCATE COMP "btn[0]" SITE "D6"; # BTN_PWRn (inverted logic)
+LOCATE COMP "btn[1]" SITE "R1"; # FIRE1
+LOCATE COMP "btn[2]" SITE "T1"; # FIRE2
+LOCATE COMP "btn[3]" SITE "W1"; # UP
+LOCATE COMP "btn[4]" SITE "V1"; # DOWN
+LOCATE COMP "btn[5]" SITE "U1"; # LEFT
+LOCATE COMP "btn[6]" SITE "Y2"; # RIGHT
+IOBUF PORT "btn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[4]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[5]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[6]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## DIP switch "blinkey", "gpio" sheet
+LOCATE COMP "sw[0]" SITE "E8"; # SW1
+LOCATE COMP "sw[1]" SITE "D8"; # SW2
+LOCATE COMP "sw[2]" SITE "D7"; # SW3
+LOCATE COMP "sw[3]" SITE "E7"; # SW4
+IOBUF PORT "sw[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI OLED DISPLAY SSD1331 (Color) or SSD1306 (B/W) "blinkey", "usb" sheet
+LOCATE COMP "oled_clk" SITE "P4";
+LOCATE COMP "oled_mosi" SITE "P3";
+LOCATE COMP "oled_dc" SITE "P1";
+LOCATE COMP "oled_resn" SITE "P2";
+LOCATE COMP "oled_csn" SITE "N2";
+IOBUF PORT "oled_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_dc" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_resn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI Flash chip "flash" sheet
+LOCATE COMP "flash_csn" SITE "R2";
+LOCATE COMP "flash_clk" SITE "U3";
+LOCATE COMP "flash_mosi" SITE "W2";
+LOCATE COMP "flash_miso" SITE "V2";
+#LOCATE COMP "flash_csspin" SITE "AJ3";
+#LOCATE COMP "flash_initn" SITE "AG4";
+#LOCATE COMP "flash_done" SITE "AJ4";
+#LOCATE COMP "flash_programn" SITE "AH4";
+#LOCATE COMP "flash_cfg_select[0]" SITE "AM4";
+#LOCATE COMP "flash_cfg_select[1]" SITE "AL4";
+#LOCATE COMP "flash_cfg_select[2]" SITE "AK4";
+IOBUF PORT "flash_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_clk" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_csspin" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_initn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SD card "sdcard", "usb" sheet
+LOCATE COMP "sd_clk" SITE "J1"; # sd_clk WiFi_GPIO14
+LOCATE COMP "sd_cmd" SITE "J3"; # sd_cmd_di (MOSI) WiFi GPIO15
+LOCATE COMP "sd_d[0]" SITE "K2"; # sd_dat0_do (MISO) WiFi GPIO2
+LOCATE COMP "sd_d[1]" SITE "K1"; # sd_dat1_irq WiFi GPIO4
+LOCATE COMP "sd_d[2]" SITE "H2"; # sd_dat2 WiFi_GPIO12
+LOCATE COMP "sd_d[3]" SITE "H1"; # sd_dat3_csn WiFi_GPIO13
+LOCATE COMP "sd_wp" SITE "P5"; # not connected
+LOCATE COMP "sd_cdn" SITE "N5"; # not connected
+IOBUF PORT "sd_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cmd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; # WiFi GPIO12 pulldown bootstrapping requirement
+IOBUF PORT "sd_d[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_wp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## ADC SPI (MAX11123) "analog", "ram" sheet
+LOCATE COMP "adc_csn" SITE "R17";
+LOCATE COMP "adc_mosi" SITE "R16";
+LOCATE COMP "adc_miso" SITE "U16";
+LOCATE COMP "adc_sclk" SITE "P17";
+IOBUF PORT "adc_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_sclk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Audio 4-bit DAC "analog", "gpio" sheet
+# 4-bit mode can drive down to 75 ohm load impedance.
+# Lower impedance leads to IO overload,
+# FPGA will stop working and need reboot.
+# For standard 17 ohm earphones:
+# use bits 2,3 as input (High-Z) and drive only bits 0,1.
+LOCATE COMP "audio_l[3]" SITE "B3"; # JACK TIP (left audio)
+LOCATE COMP "audio_l[2]" SITE "C3";
+LOCATE COMP "audio_l[1]" SITE "D3";
+LOCATE COMP "audio_l[0]" SITE "E4";
+LOCATE COMP "audio_r[3]" SITE "C5"; # JACK RING1 (right audio)
+LOCATE COMP "audio_r[2]" SITE "D5";
+LOCATE COMP "audio_r[1]" SITE "B5";
+LOCATE COMP "audio_r[0]" SITE "A3";
+LOCATE COMP "audio_v[3]" SITE "E5"; # JACK RING2 (video or digital audio)
+LOCATE COMP "audio_v[2]" SITE "F5";
+LOCATE COMP "audio_v[1]" SITE "F2";
+LOCATE COMP "audio_v[0]" SITE "H5";
+IOBUF PORT "audio_l[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## WiFi ESP-32 "wifi", "usb", "flash" sheet
+# other pins are shared with GP/GN, SD card and JTAG
+LOCATE COMP "wifi_en" SITE "F1"; # enable/reset WiFi
+LOCATE COMP "wifi_rxd" SITE "K3"; # FPGA transmits to WiFi
+LOCATE COMP "wifi_txd" SITE "K4"; # FPGA receives from WiFi
+LOCATE COMP "wifi_gpio0" SITE "L2";
+LOCATE COMP "wifi_gpio5" SITE "N4"; # WIFI LED
+LOCATE COMP "wifi_gpio16" SITE "L1";
+LOCATE COMP "wifi_gpio17" SITE "N3";
+# LOCATE COMP "prog_done" SITE "Y3"; # not GPIO, always active
+IOBUF PORT "wifi_en" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_txd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio16" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio17" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+# IOBUF PORT "prog_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## PCB antenna 433 MHz (may be also used for FM) "usb" sheet
+LOCATE COMP "ant_433mhz" SITE "G1";
+IOBUF PORT "ant_433mhz" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Second USB port going directly into FPGA "usb", "ram" sheet
+LOCATE COMP "usb_fpga_dp" SITE "E16";
+LOCATE COMP "usb_fpga_dn" SITE "F16";
+IOBUF PORT "usb_fpga_dp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## JTAG ESP-32 "usb" sheet
+# connected to FT231X and ESP-32
+# commented out because those are dedicated pins, not directly useable as GPIO
+# but could be used by some vendor-specific JTAG bridging (boundary scan) module
+#LOCATE COMP "jtag_tdi" SITE "R5"; # FTDI_nRI FPGA receives
+#LOCATE COMP "jtag_tdo" SITE "V4"; # FTDI_nCTS FPGA transmits
+#LOCATE COMP "jtag_tck" SITE "T5"; # FTDI_nDSR FPGA receives
+#LOCATE COMP "jtag_tms" SITE "U5"; # FTDI_nDCD FPGA receives
+#IOBUF PORT "jtag_tdi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tdo" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tck" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tms" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SDRAM "ram" sheet
+LOCATE COMP "sdram_clk" SITE "F19";
+LOCATE COMP "sdram_cke" SITE "F20";
+LOCATE COMP "sdram_csn" SITE "P20";
+LOCATE COMP "sdram_wen" SITE "T20";
+LOCATE COMP "sdram_rasn" SITE "R20";
+LOCATE COMP "sdram_casn" SITE "T19";
+LOCATE COMP "sdram_a[0]" SITE "M20";
+LOCATE COMP "sdram_a[1]" SITE "M19";
+LOCATE COMP "sdram_a[2]" SITE "L20";
+LOCATE COMP "sdram_a[3]" SITE "L19";
+LOCATE COMP "sdram_a[4]" SITE "K20";
+LOCATE COMP "sdram_a[5]" SITE "K19";
+LOCATE COMP "sdram_a[6]" SITE "K18";
+LOCATE COMP "sdram_a[7]" SITE "J20";
+LOCATE COMP "sdram_a[8]" SITE "J19";
+LOCATE COMP "sdram_a[9]" SITE "H20";
+LOCATE COMP "sdram_a[10]" SITE "N19";
+LOCATE COMP "sdram_a[11]" SITE "G20";
+LOCATE COMP "sdram_a[12]" SITE "G19";
+LOCATE COMP "sdram_ba[0]" SITE "P19";
+LOCATE COMP "sdram_ba[1]" SITE "N20";
+LOCATE COMP "sdram_dqm[0]" SITE "U19";
+LOCATE COMP "sdram_dqm[1]" SITE "E20";
+LOCATE COMP "sdram_d[0]" SITE "J16";
+LOCATE COMP "sdram_d[1]" SITE "L18";
+LOCATE COMP "sdram_d[2]" SITE "M18";
+LOCATE COMP "sdram_d[3]" SITE "N18";
+LOCATE COMP "sdram_d[4]" SITE "P18";
+LOCATE COMP "sdram_d[5]" SITE "T18";
+LOCATE COMP "sdram_d[6]" SITE "T17";
+LOCATE COMP "sdram_d[7]" SITE "U20";
+LOCATE COMP "sdram_d[8]" SITE "E19";
+LOCATE COMP "sdram_d[9]" SITE "D20";
+LOCATE COMP "sdram_d[10]" SITE "D19";
+LOCATE COMP "sdram_d[11]" SITE "C20";
+LOCATE COMP "sdram_d[12]" SITE "E18";
+LOCATE COMP "sdram_d[13]" SITE "F18";
+LOCATE COMP "sdram_d[14]" SITE "J18";
+LOCATE COMP "sdram_d[15]" SITE "J17";
+IOBUF PORT "sdram_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_cke" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_wen" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_rasn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_casn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[13]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[14]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[15]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPDI differential interface (Video) "gpdi" sheet
+LOCATE COMP "gpdi_dp[0]" SITE "A16"; # Blue +
+LOCATE COMP "gpdi_dn[0]" SITE "B16"; # Blue -
+LOCATE COMP "gpdi_dp[1]" SITE "A14"; # Green +
+LOCATE COMP "gpdi_dn[1]" SITE "C14"; # Green -
+LOCATE COMP "gpdi_dp[2]" SITE "A12"; # Red +
+LOCATE COMP "gpdi_dn[2]" SITE "A13"; # Read +
+LOCATE COMP "gpdi_ethp" SITE "A19"; # Ethernet +
+LOCATE COMP "gpdi_ethn" SITE "B20"; # Ethernet -
+LOCATE COMP "gpdi_clkp" SITE "A17"; # Clock +
+LOCATE COMP "gpdi_clkn" SITE "B18"; # Clock -
+LOCATE COMP "gpdi_cec" SITE "A18";
+LOCATE COMP "gpdi_sda" SITE "B19"; # I2C shared with RTC
+LOCATE COMP "gpdi_scl" SITE "C12"; # I2C shared with RTC
+IOBUF PORT "gpdi_dp[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_clkp" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_clkn" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethp" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethn" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_cec" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_sda" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_scl" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPIO (default single-ended) "gpio", "ram", "gpdi" sheet
+# Pins enumerated gp[0-27], gn[0-27].
+# With differential mode enabled on Lattice,
+# gp[] (+) are used, gn[] (-) are ignored from design
+# as they handle inverted signal by default.
+# To enable differential, rename LVCMOS33->LVCMOS33D
+LOCATE COMP "gp[0]" SITE "B11"; # J1_5+ GP0
+LOCATE COMP "gn[0]" SITE "C11"; # J1_5- GN0
+LOCATE COMP "gp[1]" SITE "A10"; # J1_7+ GP1
+LOCATE COMP "gn[1]" SITE "A11"; # J1_7- GN1
+LOCATE COMP "gp[2]" SITE "A9"; # J1_9+ GP2
+LOCATE COMP "gn[2]" SITE "B10"; # J1_9- GN2
+LOCATE COMP "gp[3]" SITE "B9"; # J1_11+ GP3
+LOCATE COMP "gn[3]" SITE "C10"; # J1_11- GN3
+LOCATE COMP "gp[4]" SITE "A7"; # J1_13+ GP4
+LOCATE COMP "gn[4]" SITE "A8"; # J1_13- GN4
+LOCATE COMP "gp[5]" SITE "C8"; # J1_15+ GP5
+LOCATE COMP "gn[5]" SITE "B8"; # J1_15- GN5
+LOCATE COMP "gp[6]" SITE "C6"; # J1_17+ GP6
+LOCATE COMP "gn[6]" SITE "C7"; # J1_17- GN6
+IOBUF PORT "gp[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[7]" SITE "A6"; # J1_23+ GP7
+LOCATE COMP "gn[7]" SITE "B6"; # J1_23- GN7
+LOCATE COMP "gp[8]" SITE "A4"; # J1_25+ GP8
+LOCATE COMP "gn[8]" SITE "A5"; # J1_25- GN8
+LOCATE COMP "gp[9]" SITE "A2"; # J1_27+ GP9
+LOCATE COMP "gn[9]" SITE "B1"; # J1_27- GN9
+LOCATE COMP "gp[10]" SITE "C4"; # J1_29+ GP10 WIFI_GPIO27
+LOCATE COMP "gn[10]" SITE "B4"; # J1_29- GN10
+LOCATE COMP "gp[11]" SITE "F4"; # J1_31+ GP11 WIFI_GPIO25
+LOCATE COMP "gn[11]" SITE "E3"; # J1_31- GN11 WIFI_GPIO26
+LOCATE COMP "gp[12]" SITE "G3"; # J1_33+ GP12 WIFI_GPIO32
+LOCATE COMP "gn[12]" SITE "F3"; # J1_33- GN12 WIFI_GPIO33
+LOCATE COMP "gp[13]" SITE "H4"; # J1_35+ GP13 WIFI_GPIO34
+LOCATE COMP "gn[13]" SITE "G5"; # J1_35- GN13 WIFI_GPIO35
+IOBUF PORT "gp[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[14]" SITE "U18"; # J2_5+ GP14
+LOCATE COMP "gn[14]" SITE "U17"; # J2_5- GN14
+LOCATE COMP "gp[15]" SITE "N17"; # J2_7+ GP15
+LOCATE COMP "gn[15]" SITE "P16"; # J2_7- GN15
+LOCATE COMP "gp[16]" SITE "N16"; # J2_9+ GP16
+LOCATE COMP "gn[16]" SITE "M17"; # J2_9- GN16
+LOCATE COMP "gp[17]" SITE "L16"; # J2_11+ GP17
+LOCATE COMP "gn[17]" SITE "L17"; # J2_11- GN17
+LOCATE COMP "gp[18]" SITE "H18"; # J2_13+ GP18
+LOCATE COMP "gn[18]" SITE "H17"; # J2_13- GN18
+LOCATE COMP "gp[19]" SITE "F17"; # J2_15+ GP19
+LOCATE COMP "gn[19]" SITE "G18"; # J2_15- GN19
+LOCATE COMP "gp[20]" SITE "D18"; # J2_17+ GP20
+LOCATE COMP "gn[20]" SITE "E17"; # J2_17- GN20
+IOBUF PORT "gp[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[21]" SITE "C18"; # J2_23+ GP21
+LOCATE COMP "gn[21]" SITE "D17"; # J2_23- GN21
+LOCATE COMP "gp[22]" SITE "D15"; # J2_25+ GP22
+LOCATE COMP "gn[22]" SITE "E15"; # J2_25- GN22
+LOCATE COMP "gp[23]" SITE "B17"; # J2_27+ GP23
+LOCATE COMP "gn[23]" SITE "C17"; # J2_27- GN23
+LOCATE COMP "gp[24]" SITE "C16"; # J2_29+ GP24
+LOCATE COMP "gn[24]" SITE "D16"; # J2_29- GN24
+LOCATE COMP "gp[25]" SITE "B15"; # J2_31+ GP25
+LOCATE COMP "gn[25]" SITE "C15"; # J2_31- GN25
+LOCATE COMP "gp[26]" SITE "B13"; # J2_33+ GP26
+LOCATE COMP "gn[26]" SITE "C13"; # J2_33- GN26
+LOCATE COMP "gp[27]" SITE "D13"; # J2_35+ GP27
+LOCATE COMP "gn[27]" SITE "E13"; # J2_35- GN27
+IOBUF PORT "gp[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SHUTDOWN "power", "ram" sheet (connected from PCB v1.7.5)
+# on PCB v1.7 shutdown is not connected to FPGA
+LOCATE COMP "shutdown" SITE "G16"; # FPGA receives
+IOBUF PORT "shutdown" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
diff --git a/boards/ulx3s-v2.0-25f-sp/constraints/ulx3s_v20.lpf b/boards/ulx3s-v2.0-25f-sp/constraints/ulx3s_v20.lpf
new file mode 100644
index 0000000..e04bc4f
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/constraints/ulx3s_v20.lpf
@@ -0,0 +1,452 @@
+BLOCK RESETPATHS;
+BLOCK ASYNCPATHS;
+## ULX3S v2.0 and v2.1
+
+# The clock "usb" and "gpdi" sheet
+LOCATE COMP "clk_25mhz" SITE "G2";
+IOBUF PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33;
+FREQUENCY PORT "clk_25mhz" 25 MHZ;
+
+# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash
+SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 MASTER_SPI_PORT=DISABLE SLAVE_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE;
+
+## USBSERIAL FTDI-FPGA serial port "usb" sheet
+LOCATE COMP "ftdi_rxd" SITE "L4"; # FPGA transmits to ftdi
+LOCATE COMP "ftdi_txd" SITE "M1"; # FPGA receives from ftdi
+LOCATE COMP "ftdi_nrts" SITE "M3"; # FPGA receives
+LOCATE COMP "ftdi_ndtr" SITE "N1"; # FPGA receives
+LOCATE COMP "ftdi_txden" SITE "L3"; # FPGA receives
+IOBUF PORT "ftdi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "ftdi_txd" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_nrts" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_ndtr" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_txden" PULLMODE=UP IO_TYPE=LVCMOS33;
+
+## LED indicators "blinkey" and "gpio" sheet
+LOCATE COMP "led[7]" SITE "H3";
+LOCATE COMP "led[6]" SITE "E1";
+LOCATE COMP "led[5]" SITE "E2";
+LOCATE COMP "led[4]" SITE "D1";
+LOCATE COMP "led[3]" SITE "D2";
+LOCATE COMP "led[2]" SITE "C1";
+LOCATE COMP "led[1]" SITE "C2";
+LOCATE COMP "led[0]" SITE "B2";
+IOBUF PORT "led[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Pushbuttons "blinkey", "flash", "power", "gpdi" sheet
+LOCATE COMP "btn[0]" SITE "D6"; # BTN_PWRn (inverted logic)
+LOCATE COMP "btn[1]" SITE "R1"; # FIRE1
+LOCATE COMP "btn[2]" SITE "T1"; # FIRE2
+LOCATE COMP "btn[3]" SITE "R18"; # UP W1->R18
+LOCATE COMP "btn[4]" SITE "V1"; # DOWN
+LOCATE COMP "btn[5]" SITE "U1"; # LEFT
+LOCATE COMP "btn[6]" SITE "H16"; # RIGHT Y2->H16
+IOBUF PORT "btn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[4]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[5]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[6]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## DIP switch "blinkey", "gpio" sheet
+LOCATE COMP "sw[0]" SITE "E8"; # SW1
+LOCATE COMP "sw[1]" SITE "D8"; # SW2
+LOCATE COMP "sw[2]" SITE "D7"; # SW3
+LOCATE COMP "sw[3]" SITE "E7"; # SW4
+IOBUF PORT "sw[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI OLED DISPLAY SSD1331 (Color) or SSD1306 (B/W) "blinkey", "usb" sheet
+LOCATE COMP "oled_clk" SITE "P4";
+LOCATE COMP "oled_mosi" SITE "P3";
+LOCATE COMP "oled_dc" SITE "P1";
+LOCATE COMP "oled_resn" SITE "P2";
+LOCATE COMP "oled_csn" SITE "N2";
+IOBUF PORT "oled_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_dc" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_resn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI Flash chip "flash" sheet
+LOCATE COMP "flash_csn" SITE "R2";
+LOCATE COMP "flash_mosi" SITE "W2";
+LOCATE COMP "flash_miso" SITE "V2";
+LOCATE COMP "flash_holdn" SITE "W1";
+LOCATE COMP "flash_wpn" SITE "Y2";
+#LOCATE COMP "flash_clk" SITE "U3";
+#LOCATE COMP "flash_csspin" SITE "AJ3";
+#LOCATE COMP "flash_initn" SITE "AG4";
+#LOCATE COMP "flash_done" SITE "AJ4";
+#LOCATE COMP "flash_programn" SITE "AH4";
+#LOCATE COMP "flash_cfg_select[0]" SITE "AM4";
+#LOCATE COMP "flash_cfg_select[1]" SITE "AL4";
+#LOCATE COMP "flash_cfg_select[2]" SITE "AK4";
+IOBUF PORT "flash_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_holdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_wpn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_clk" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_csspin" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_initn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SD card "sdcard", "usb" sheet
+LOCATE COMP "sd_clk" SITE "H2"; # sd_clk WiFi_GPIO14
+LOCATE COMP "sd_cmd" SITE "J1"; # sd_cmd_di (MOSI) WiFi GPIO15
+LOCATE COMP "sd_d[0]" SITE "J3"; # sd_dat0_do (MISO) WiFi GPIO2
+LOCATE COMP "sd_d[1]" SITE "H1"; # sd_dat1_irq WiFi GPIO4
+LOCATE COMP "sd_d[2]" SITE "K1"; # sd_dat2 WiFi_GPIO12
+LOCATE COMP "sd_d[3]" SITE "K2"; # sd_dat3_csn WiFi_GPIO13
+LOCATE COMP "sd_wp" SITE "P5"; # not connected
+LOCATE COMP "sd_cdn" SITE "N5"; # not connected
+IOBUF PORT "sd_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cmd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; # WiFi GPIO12 pulldown bootstrapping requirement
+IOBUF PORT "sd_d[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_wp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## ADC SPI (MAX11123) "analog", "ram" sheet
+LOCATE COMP "adc_csn" SITE "R17";
+LOCATE COMP "adc_mosi" SITE "R16";
+LOCATE COMP "adc_miso" SITE "U16";
+LOCATE COMP "adc_sclk" SITE "P17";
+IOBUF PORT "adc_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_sclk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Audio 4-bit DAC "analog", "gpio" sheet
+# 4-bit mode can drive down to 75 ohm load impedance.
+# Lower impedance leads to IO overload,
+# FPGA will stop working and need reboot.
+# For standard 17 ohm earphones:
+# use bits 2,3 as input (High-Z) and drive only bits 0,1.
+LOCATE COMP "audio_l[3]" SITE "B3"; # JACK TIP (left audio)
+LOCATE COMP "audio_l[2]" SITE "C3";
+LOCATE COMP "audio_l[1]" SITE "D3";
+LOCATE COMP "audio_l[0]" SITE "E4";
+LOCATE COMP "audio_r[3]" SITE "C5"; # JACK RING1 (right audio)
+LOCATE COMP "audio_r[2]" SITE "D5";
+LOCATE COMP "audio_r[1]" SITE "B5";
+LOCATE COMP "audio_r[0]" SITE "A3";
+LOCATE COMP "audio_v[3]" SITE "E5"; # JACK RING2 (video or digital audio)
+LOCATE COMP "audio_v[2]" SITE "F5";
+LOCATE COMP "audio_v[1]" SITE "F2";
+LOCATE COMP "audio_v[0]" SITE "H5";
+IOBUF PORT "audio_l[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## WiFi ESP-32 "wifi", "usb", "flash" sheet
+# other pins are shared with GP/GN, SD card and JTAG
+LOCATE COMP "wifi_en" SITE "F1"; # enable/reset WiFi
+LOCATE COMP "wifi_rxd" SITE "K3"; # FPGA transmits to WiFi
+LOCATE COMP "wifi_txd" SITE "K4"; # FPGA receives from WiFi
+LOCATE COMP "wifi_gpio0" SITE "L2";
+LOCATE COMP "wifi_gpio5" SITE "N4"; # WIFI LED
+LOCATE COMP "wifi_gpio16" SITE "L1"; # Serial1 RX
+LOCATE COMP "wifi_gpio17" SITE "N3"; # Serial1 TX
+# LOCATE COMP "prog_done" SITE "Y3"; # not GPIO, always active
+IOBUF PORT "wifi_en" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_txd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio16" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio17" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+# IOBUF PORT "prog_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## PCB antenna 433 MHz (may be also used for FM) "usb" sheet
+LOCATE COMP "ant_433mhz" SITE "G1";
+IOBUF PORT "ant_433mhz" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Second USB port "US2" going directly into FPGA "usb", "ram" sheet
+LOCATE COMP "usb_fpga_dp" SITE "E16"; # single ended or differential input only
+LOCATE COMP "usb_fpga_dn" SITE "F16";
+IOBUF PORT "usb_fpga_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+LOCATE COMP "usb_fpga_bd_dp" SITE "D15"; # differential bidirectional
+LOCATE COMP "usb_fpga_bd_dn" SITE "E15";
+IOBUF PORT "usb_fpga_bd_dp" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "usb_fpga_bd_dn" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=4;
+LOCATE COMP "usb_fpga_pu_dp" SITE "B12"; # pull up/down control
+LOCATE COMP "usb_fpga_pu_dn" SITE "C12";
+IOBUF PORT "usb_fpga_pu_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+IOBUF PORT "usb_fpga_pu_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+
+## JTAG ESP-32 "usb" sheet
+# connected to FT231X and ESP-32
+# commented out because those are dedicated pins, not directly useable as GPIO
+# but could be used by some vendor-specific JTAG bridging (boundary scan) module
+#LOCATE COMP "jtag_tdi" SITE "R5"; # FTDI_nRI FPGA receives
+#LOCATE COMP "jtag_tdo" SITE "V4"; # FTDI_nCTS FPGA transmits
+#LOCATE COMP "jtag_tck" SITE "T5"; # FTDI_nDSR FPGA receives
+#LOCATE COMP "jtag_tms" SITE "U5"; # FTDI_nDCD FPGA receives
+#IOBUF PORT "jtag_tdi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tdo" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tck" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tms" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SDRAM "ram" sheet
+LOCATE COMP "sdram_clk" SITE "F19";
+LOCATE COMP "sdram_cke" SITE "F20";
+LOCATE COMP "sdram_csn" SITE "P20";
+LOCATE COMP "sdram_wen" SITE "T20";
+LOCATE COMP "sdram_rasn" SITE "R20";
+LOCATE COMP "sdram_casn" SITE "T19";
+LOCATE COMP "sdram_a[0]" SITE "M20";
+LOCATE COMP "sdram_a[1]" SITE "M19";
+LOCATE COMP "sdram_a[2]" SITE "L20";
+LOCATE COMP "sdram_a[3]" SITE "L19";
+LOCATE COMP "sdram_a[4]" SITE "K20";
+LOCATE COMP "sdram_a[5]" SITE "K19";
+LOCATE COMP "sdram_a[6]" SITE "K18";
+LOCATE COMP "sdram_a[7]" SITE "J20";
+LOCATE COMP "sdram_a[8]" SITE "J19";
+LOCATE COMP "sdram_a[9]" SITE "H20";
+LOCATE COMP "sdram_a[10]" SITE "N19";
+LOCATE COMP "sdram_a[11]" SITE "G20";
+LOCATE COMP "sdram_a[12]" SITE "G19";
+LOCATE COMP "sdram_ba[0]" SITE "P19";
+LOCATE COMP "sdram_ba[1]" SITE "N20";
+LOCATE COMP "sdram_dqm[0]" SITE "U19";
+LOCATE COMP "sdram_dqm[1]" SITE "E20";
+LOCATE COMP "sdram_d[0]" SITE "J16";
+LOCATE COMP "sdram_d[1]" SITE "L18";
+LOCATE COMP "sdram_d[2]" SITE "M18";
+LOCATE COMP "sdram_d[3]" SITE "N18";
+LOCATE COMP "sdram_d[4]" SITE "P18";
+LOCATE COMP "sdram_d[5]" SITE "T18";
+LOCATE COMP "sdram_d[6]" SITE "T17";
+LOCATE COMP "sdram_d[7]" SITE "U20";
+LOCATE COMP "sdram_d[8]" SITE "E19";
+LOCATE COMP "sdram_d[9]" SITE "D20";
+LOCATE COMP "sdram_d[10]" SITE "D19";
+LOCATE COMP "sdram_d[11]" SITE "C20";
+LOCATE COMP "sdram_d[12]" SITE "E18";
+LOCATE COMP "sdram_d[13]" SITE "F18";
+LOCATE COMP "sdram_d[14]" SITE "J18";
+LOCATE COMP "sdram_d[15]" SITE "J17";
+IOBUF PORT "sdram_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_cke" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_wen" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_rasn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_casn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[13]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[14]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[15]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPDI differential interface (Video) "gpdi" sheet
+LOCATE COMP "gpdi_dp[0]" SITE "A16"; # Blue +
+LOCATE COMP "gpdi_dn[0]" SITE "B16"; # Blue -
+LOCATE COMP "gpdi_dp[1]" SITE "A14"; # Green +
+LOCATE COMP "gpdi_dn[1]" SITE "C14"; # Green -
+LOCATE COMP "gpdi_dp[2]" SITE "A12"; # Red +
+LOCATE COMP "gpdi_dn[2]" SITE "A13"; # Red -
+LOCATE COMP "gpdi_dp[3]" SITE "A17"; # Clock +
+LOCATE COMP "gpdi_dn[3]" SITE "B18"; # Clock -
+LOCATE COMP "gpdi_ethp" SITE "A19"; # Ethernet +
+LOCATE COMP "gpdi_ethn" SITE "B20"; # Ethernet -
+LOCATE COMP "gpdi_cec" SITE "A18";
+LOCATE COMP "gpdi_sda" SITE "B19"; # I2C shared with RTC
+LOCATE COMP "gpdi_scl" SITE "E12"; # I2C shared with RTC C12->E12
+IOBUF PORT "gpdi_dp[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[3]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[3]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethp" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethn" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_cec" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_sda" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_scl" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPIO (default single-ended) "gpio", "ram", "gpdi" sheet
+# Pins enumerated gp[0-27], gn[0-27].
+# With differential mode enabled on Lattice,
+# gp[] (+) are used, gn[] (-) are ignored from design
+# as they handle inverted signal by default.
+# To enable differential, rename LVCMOS33->LVCMOS33D
+LOCATE COMP "gp[0]" SITE "B11"; # J1_5+ GP0
+LOCATE COMP "gn[0]" SITE "C11"; # J1_5- GN0
+LOCATE COMP "gp[1]" SITE "A10"; # J1_7+ GP1
+LOCATE COMP "gn[1]" SITE "A11"; # J1_7- GN1
+LOCATE COMP "gp[2]" SITE "A9"; # J1_9+ GP2
+LOCATE COMP "gn[2]" SITE "B10"; # J1_9- GN2
+LOCATE COMP "gp[3]" SITE "B9"; # J1_11+ GP3
+LOCATE COMP "gn[3]" SITE "C10"; # J1_11- GN3
+LOCATE COMP "gp[4]" SITE "A7"; # J1_13+ GP4
+LOCATE COMP "gn[4]" SITE "A8"; # J1_13- GN4
+LOCATE COMP "gp[5]" SITE "C8"; # J1_15+ GP5
+LOCATE COMP "gn[5]" SITE "B8"; # J1_15- GN5
+LOCATE COMP "gp[6]" SITE "C6"; # J1_17+ GP6
+LOCATE COMP "gn[6]" SITE "C7"; # J1_17- GN6
+IOBUF PORT "gp[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[7]" SITE "A6"; # J1_23+ GP7
+LOCATE COMP "gn[7]" SITE "B6"; # J1_23- GN7
+LOCATE COMP "gp[8]" SITE "A4"; # J1_25+ GP8
+LOCATE COMP "gn[8]" SITE "A5"; # J1_25- GN8
+LOCATE COMP "gp[9]" SITE "A2"; # J1_27+ GP9
+LOCATE COMP "gn[9]" SITE "B1"; # J1_27- GN9
+LOCATE COMP "gp[10]" SITE "C4"; # J1_29+ GP10 WIFI_GPIO27
+LOCATE COMP "gn[10]" SITE "B4"; # J1_29- GN10
+LOCATE COMP "gp[11]" SITE "F4"; # J1_31+ GP11 WIFI_GPIO25
+LOCATE COMP "gn[11]" SITE "E3"; # J1_31- GN11 WIFI_GPIO26
+LOCATE COMP "gp[12]" SITE "G3"; # J1_33+ GP12 WIFI_GPIO32
+LOCATE COMP "gn[12]" SITE "F3"; # J1_33- GN12 WIFI_GPIO33
+LOCATE COMP "gp[13]" SITE "H4"; # J1_35+ GP13 WIFI_GPIO34
+LOCATE COMP "gn[13]" SITE "G5"; # J1_35- GN13 WIFI_GPIO35
+IOBUF PORT "gp[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[14]" SITE "U18"; # J2_5+ GP14
+LOCATE COMP "gn[14]" SITE "U17"; # J2_5- GN14
+LOCATE COMP "gp[15]" SITE "N17"; # J2_7+ GP15
+LOCATE COMP "gn[15]" SITE "P16"; # J2_7- GN15
+LOCATE COMP "gp[16]" SITE "N16"; # J2_9+ GP16
+LOCATE COMP "gn[16]" SITE "M17"; # J2_9- GN16
+LOCATE COMP "gp[17]" SITE "L16"; # J2_11+ GP17
+LOCATE COMP "gn[17]" SITE "L17"; # J2_11- GN17
+LOCATE COMP "gp[18]" SITE "H18"; # J2_13+ GP18
+LOCATE COMP "gn[18]" SITE "H17"; # J2_13- GN18
+LOCATE COMP "gp[19]" SITE "F17"; # J2_15+ GP19
+LOCATE COMP "gn[19]" SITE "G18"; # J2_15- GN19
+LOCATE COMP "gp[20]" SITE "D18"; # J2_17+ GP20
+LOCATE COMP "gn[20]" SITE "E17"; # J2_17- GN20
+IOBUF PORT "gp[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[21]" SITE "C18"; # J2_23+ GP21
+LOCATE COMP "gn[21]" SITE "D17"; # J2_23- GN21
+LOCATE COMP "gp[22]" SITE "B15"; # J2_25+ GP22 D15->B15
+LOCATE COMP "gn[22]" SITE "C15"; # J2_25- GN22 E15->C15
+LOCATE COMP "gp[23]" SITE "B17"; # J2_27+ GP23
+LOCATE COMP "gn[23]" SITE "C17"; # J2_27- GN23
+LOCATE COMP "gp[24]" SITE "C16"; # J2_29+ GP24
+LOCATE COMP "gn[24]" SITE "D16"; # J2_29- GN24
+LOCATE COMP "gp[25]" SITE "D14"; # J2_31+ GP25 B15->D14
+LOCATE COMP "gn[25]" SITE "E14"; # J2_31- GN25 C15->E14
+LOCATE COMP "gp[26]" SITE "B13"; # J2_33+ GP26
+LOCATE COMP "gn[26]" SITE "C13"; # J2_33- GN26
+LOCATE COMP "gp[27]" SITE "D13"; # J2_35+ GP27
+LOCATE COMP "gn[27]" SITE "E13"; # J2_35- GN27
+IOBUF PORT "gp[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## PROGRAMN (reload bitstream from FLASH, exit from bootloader)
+# PCB v2.0.5 and higher
+LOCATE COMP "user_programn" SITE "M4";
+IOBUF PORT "user_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SHUTDOWN "power", "ram" sheet (connected from PCB v1.7.5)
+# on PCB v1.7 shutdown is not connected to FPGA
+LOCATE COMP "shutdown" SITE "G16"; # FPGA receives
+IOBUF PORT "shutdown" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
diff --git a/boards/ulx3s-v2.0-25f-sp/ecp5-25f.ocd b/boards/ulx3s-v2.0-25f-sp/ecp5-25f.ocd
new file mode 100644
index 0000000..36d4c40
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/ecp5-25f.ocd
@@ -0,0 +1,16 @@
+# ecp5-XXf.cfg
+# OpenOCD commands
+
+telnet_port 4444
+gdb_port 3333
+
+# JTAG TAPs
+#jtag newtap lfe5u12 tap -expected-id 0x21111043 -irlen 8 -irmask 0xFF -ircapture 0x5
+jtag newtap lfe5u25 tap -expected-id 0x41111043 -irlen 8 -irmask 0xFF -ircapture 0x5
+#jtag newtap lfe5u45 tap -expected-id 0x41112043 -irlen 8 -irmask 0xFF -ircapture 0x5
+#jtag newtap lfe5u85 tap -expected-id 0x41113043 -irlen 8 -irmask 0xFF -ircapture 0x5
+
+init
+scan_chain
+svf -tap lfe5u25.tap -quiet -progress project/project_project_sram.svf
+shutdown
diff --git a/boards/ulx3s-v2.0-25f-sp/ft2232-fpu1.ocd b/boards/ulx3s-v2.0-25f-sp/ft2232-fpu1.ocd
new file mode 100644
index 0000000..6c41311
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/ft2232-fpu1.ocd
@@ -0,0 +1,9 @@
+#
+# PLDkit FPU1 JTAG Programmer
+#
+
+interface ftdi
+ftdi_device_desc "FPU1 JTAG Programmer"
+ftdi_vid_pid 0x0403 0x6010
+ftdi_layout_init 0x3088 0x1f8b
+adapter_khz 25000
diff --git a/boards/ulx3s-v2.0-25f-sp/ft231x.ocd b/boards/ulx3s-v2.0-25f-sp/ft231x.ocd
new file mode 100644
index 0000000..f2dee26
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/ft231x.ocd
@@ -0,0 +1,15 @@
+#
+# openocd_ft232r patched for custom jtag nums and buffer_size
+#
+
+interface ft232r
+ft232r_vid_pid 0x0403 0x6015
+# ft232r_serial_desc 12345678
+ft232r_tck_num 5
+ft232r_tms_num 6
+ft232r_tdi_num 7
+ft232r_tdo_num 3
+ft232r_trst_num 2
+ft232r_srst_num 4
+ft232r_buffer_size 16384
+adapter_khz 300
diff --git a/boards/ulx3s-v2.0-25f-sp/initialize/boardmeta4MB.bin b/boards/ulx3s-v2.0-25f-sp/initialize/boardmeta4MB.bin
new file mode 100644
index 0000000..7a525c7
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/initialize/boardmeta4MB.bin
@@ -0,0 +1,119 @@
+{
+ "boardmeta":
+ {
+ "name": "ULX3S",
+ "fpga": "LFE5U-45F-6BG381C",
+ "hver": "1.7",
+ "uuid": "00000000-0000-0000-0000-000000000000",
+ "serial": 12345
+ },
+ "bootmeta":
+ {
+ "bootloader": "TinyFPGA USB Bootloader",
+ "bver": "2.0.0",
+ "update": "https://github.com/emard/TinyFPGA-Bootloader",
+ "addrmap":
+ {
+ "bootloader": "0x000000-0x0FFFFF",
+ "golden": "0x100000-0x1FFFFF",
+ "userimage": "0x200000-0x2FFFFF",
+ "userdata": "0x300000-0x3FBFFF"
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-v2.0-25f-sp/initialize/boardmeta8MB.bin b/boards/ulx3s-v2.0-25f-sp/initialize/boardmeta8MB.bin
new file mode 100644
index 0000000..89be03c
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/initialize/boardmeta8MB.bin
@@ -0,0 +1,58 @@
+{
+ "boardmeta":
+ {
+ "name": "ULX3S",
+ "fpga": "LFE5U-45F-6BG381C",
+ "hver": "1.7",
+ "uuid": "00000000-0000-0000-0000-000000000000",
+ "serial": 12345
+ },
+ "bootmeta":
+ {
+ "bootloader": "TinyFPGA USB Bootloader",
+ "bver": "2.0.0",
+ "update": "https://github.com/emard/TinyFPGA-Bootloader",
+ "addrmap":
+ {
+ "bootloader": "0x000000-0x0FFFFF",
+ "golden": "0x100000-0x1FFFFF",
+ "userimage": "0x200000-0x3FFFFF",
+ "userdata": "0x500000-0x7FBFFF"
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-v2.0-25f-sp/initialize/initialize4MB.sh b/boards/ulx3s-v2.0-25f-sp/initialize/initialize4MB.sh
new file mode 100755
index 0000000..3d67d93
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/initialize/initialize4MB.sh
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+
+# Initializer for ECP5 dual boot.
+
+# first half of the FLASH is for user bitstram
+# bootloader bitstream starts at second half of the FLASH
+# board metadata at last 0x1000 bytes
+# Jump command at last 0x100 bytes
+
+# flash size: 16 Mbit = 2 MB = 0x200000
+# flash size: 32 Mbit = 4 MB = 0x400000
+# flash size: 64 Mbit = 8 MB = 0x800000
+# flash size: 128 Mbit = 16 MB = 0x1000000
+
+bootloader_image_address=$(printf "%d" 0x000000) # 0
+golden_image_address=$(printf "%d" 0x100000) # 0x100000 (1MB) (backup of bootloader)
+board_meta_address=$(printf "%d" 0x3FF000) # flash size - 0x1000
+jump_command_address=$(printf "%d" 0x3FFF00) # flash size - 0x100
+
+# primary image must be generated by diamond deployment tool (ddtcmd)
+# simply overwriting bootloader image will not have multiboot capability
+#tinyprog --pyserial --no-boot -a $bootloader_image_address -u ../../boards/ulx3s-v1.7-45f/tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $golden_image_address -u ../tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $(printf "%d" $board_meta_address) -u boardmeta4MB.bin
+./jump.py $golden_image_address > jump.bin
+tinyprog --pyserial --no-boot -a $(printf "%d" $jump_command_address) -u jump.bin
+# hexdump -C jump.bin
+# check that's board is recognized by tingprog
+tinyprog --pyserial -l
+#tinyprog -m
diff --git a/boards/ulx3s-v2.0-25f-sp/initialize/initialize8MB.sh b/boards/ulx3s-v2.0-25f-sp/initialize/initialize8MB.sh
new file mode 100755
index 0000000..b127f53
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/initialize/initialize8MB.sh
@@ -0,0 +1,31 @@
+#!/bin/sh -e
+
+# Initializer for ECP5 dual boot.
+
+# first half of the FLASH is for user bitstram
+# bootloader bitstream starts at second half of the FLASH
+# board metadata at last 0x1000 bytes
+# Jump command at last 0x100 bytes
+
+# flash size: 8 Mbit = 1 MB = 0x100000
+# flash size: 16 Mbit = 2 MB = 0x200000
+# flash size: 32 Mbit = 4 MB = 0x400000
+# flash size: 64 Mbit = 8 MB = 0x800000
+# flash size: 128 Mbit = 16 MB = 0x1000000
+
+bootloader_image_address=$(printf "%d" 0x000000) # 0
+golden_image_address=$(printf "%d" 0x100000) # 0x100000 (1MB) (backup of bootloader)
+board_meta_address=$(printf "%d" 0x7FF000) # flash size - 0x1000 (-4KB)
+jump_command_address=$(printf "%d" 0x7FFF00) # flash size - 0x100 (-256)
+
+# primary image must be generated by diamond deployment tool (ddtcmd)
+# simply overwriting bootloader image will not have multiboot capability
+#tinyprog --pyserial --no-boot -a $bootloader_image_address -u ../../boards/ulx3s-v1.7-45f/tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $golden_image_address -u ../tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $(printf "%d" $board_meta_address) -u boardmeta8MB.bin
+./jump.py $golden_image_address > jump.bin
+tinyprog --pyserial --no-boot -a $(printf "%d" $jump_command_address) -u jump.bin
+# hexdump -C jump.bin
+# check that's board is recognized by tingprog
+tinyprog --pyserial -l
+#tinyprog -m
diff --git a/boards/ulx3s-v2.0-25f-sp/initialize/jump.bin b/boards/ulx3s-v2.0-25f-sp/initialize/jump.bin
new file mode 100644
index 0000000..d39691f
Binary files /dev/null and b/boards/ulx3s-v2.0-25f-sp/initialize/jump.bin differ
diff --git a/boards/ulx3s-v2.0-25f-sp/initialize/jump.py b/boards/ulx3s-v2.0-25f-sp/initialize/jump.py
new file mode 100755
index 0000000..b1ff948
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/initialize/jump.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+
+# Lattice ECP5 jump command generator
+# TN1216 p.23 describes the jump command syntax which does not work.
+# The syntax has been fixed by looking at dual boot intel hex file
+# generated by diamond, this actually works.
+
+import struct
+import sys
+
+# write output of this funtion at FLASH address:
+# jump_command_address = 0x3FFF00 = 4194048
+
+# write "golden" bitstream at FLASH address:
+golden_image_address = 0x140000
+golden_image_address = int(sys.argv[1])
+
+# normally both 0
+reverse_bytes = 0
+reverse_bits = 0
+
+# to compare with intel HEX file generated by diamond:
+# (not for normal use)
+# reverse_bytes = 1
+# reverse_bits = 1
+# ./jump.py | hexdump -C
+
+def reverse_Bits(n, no_of_bits):
+ result = 0
+ for i in range(no_of_bits):
+ result <<= 1
+ result |= n & 1
+ n >>= 1
+ return result
+
+def uint8(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 8)
+ return struct.pack(">B", n)
+
+def uint16(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 16)
+ if reverse_bytes:
+ return struct.pack("H", n)
+
+def uint24(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 24)
+ if reverse_bytes:
+ return struct.pack("> 8 )
+ else:
+ return struct.pack(">HB", n >> 8, n & 0xFF )
+
+def uint32(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 32)
+ if reverse_bytes:
+ return struct.pack("L", n)
+
+packet = b''
+# Frame (START) 18 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint16(0xFFFF) # 2 dummy bytes (diamond generates this 2 bytes more)
+# Preamble
+packet += uint16(0xBDB3) # Preamble
+# Frame (Control Register 0) commented out, diamond doesn't output this
+# if uncommented, jump won't work:
+#packet += uint8(0xC4) # Write control register 0 command
+#packet += uint24(0) # 24-bit Command Information
+#packet += uint32(0) # Control Register 0 data
+# This is generated by diamond:
+packet += uint32(0xFFFFFFFF) # I don't know what it does but it works
+# Framme (Jump Command)
+#packet += uint8(0xFE) # Jump command Wrong noted in TN1216
+packet += uint8(0x7E) # Jump command generated by diamond
+packet += uint24(0) # 24-bit Command Information
+packet += uint8(0x03) # SPI Flash Read opcode (0x03 = regular read, 0x0B = fast read)
+packet += uint24(golden_image_address) # 24-bit SPI Flash Sector X address
+# Frame (END) 18 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint16(0xFFFF) # 2 dummy bytes (diamond generates this 2 bytes more)
+
+sys.stdout.write(packet)
+# print([elem.encode("hex") for elem in packet])
diff --git a/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k.bit b/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k.bit
new file mode 120000
index 0000000..59e9556
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k.bit
@@ -0,0 +1 @@
+project/project_project.bit
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_multiboot_flash_is25lp032d.svf b/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_multiboot_flash_is25lp032d.svf
new file mode 120000
index 0000000..a01da25
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_multiboot_flash_is25lp032d.svf
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_is25lp032d.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_multiboot_flash_is25lp032d.vme b/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_multiboot_flash_is25lp032d.vme
new file mode 120000
index 0000000..7d99dc6
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_multiboot_flash_is25lp032d.vme
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_is25lp032d.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_multiboot_flash_is25lp128f.svf b/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_multiboot_flash_is25lp128f.svf
new file mode 120000
index 0000000..1b8f717
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_multiboot_flash_is25lp128f.svf
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_is25lp128f.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_multiboot_flash_is25lp128f.vme b/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_multiboot_flash_is25lp128f.vme
new file mode 120000
index 0000000..c736cfa
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_multiboot_flash_is25lp128f.vme
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_is25lp128f.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_multiboot_flash_s25fl164k.svf b/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_multiboot_flash_s25fl164k.svf
new file mode 120000
index 0000000..7232663
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_multiboot_flash_s25fl164k.svf
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_s25fl164k.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_multiboot_flash_s25fl164k.vme b/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_multiboot_flash_s25fl164k.vme
new file mode 120000
index 0000000..cadb80a
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_multiboot_flash_s25fl164k.vme
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_s25fl164k.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_sram.svf b/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_sram.svf
new file mode 120000
index 0000000..bb7617d
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_sram.svf
@@ -0,0 +1 @@
+project/project_project_sram.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_sram.vme b/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_sram.vme
new file mode 120000
index 0000000..d098048
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/tinyfpga_25k_sram.vme
@@ -0,0 +1 @@
+project/project_project_sram.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-25f-sp/top/bootloader_sp_ulx3s.v b/boards/ulx3s-v2.0-25f-sp/top/bootloader_sp_ulx3s.v
new file mode 100644
index 0000000..e106183
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/top/bootloader_sp_ulx3s.v
@@ -0,0 +1,141 @@
+module bootloader_sp_ulx3s (
+ input clk_25mhz,
+
+ inout usb_fpga_dp,
+ inout usb_fpga_dn,
+
+ output usb_fpga_pu_dp,
+ inout user_programn,
+
+ output [7:0] led,
+
+ input flash_miso,
+ output flash_mosi,
+ output flash_csn,
+ output flash_wpn,
+ output flash_holdn,
+
+ input [6:0] btn,
+ output wifi_gpio0
+);
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// generate 48 mhz clock
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ wire clk_200mhz;
+ clk_25M_200M clk_200M_inst (
+ .CLKI(clk_25mhz),
+ .CLKOP(clk_200mhz)
+ );
+
+ wire clk_48mhz;
+ wire clk_ready;
+ clk_200M_48M clk_48M_inst (
+ .CLKI(clk_200mhz),
+ .CLKOP(clk_48mhz),
+ .LOCK(clk_ready)
+ );
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// instantiate tinyfpga bootloader
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ reg [15:0] reset_counter = 0; // counter for debouce and prolong reset
+ wire reset;
+ assign reset = ~reset_counter[15];
+ wire usb_p_tx;
+ wire usb_n_tx;
+ wire usb_p_rx;
+ wire usb_n_rx;
+ wire usb_tx_en;
+ wire pin_led;
+ wire [7:0] debug_led;
+ wire boot;
+ wire S_flash_clk;
+ wire S_flash_csn;
+
+ tinyfpgasp_bootloader tinyfpgasp_bootloader_inst (
+ .clk_48mhz(clk_48mhz),
+ .reset(reset),
+ .usb_p_tx(usb_p_tx),
+ .usb_n_tx(usb_n_tx),
+ .usb_p_rx(usb_p_rx),
+ .usb_n_rx(usb_n_rx),
+ .usb_tx_en(usb_tx_en),
+ .led(pin_led),
+ .debug_led(debug_led),
+ .spi_miso(flash_miso),
+ .spi_mosi(flash_mosi),
+ .spi_sck(S_flash_clk),
+ .spi_cs(S_flash_csn),
+ .boot(boot)
+ );
+
+ assign usb_fpga_dp = reset ? 1'b0 : (usb_tx_en ? usb_p_tx : 1'bz);
+ assign usb_fpga_dn = reset ? 1'b0 : (usb_tx_en ? usb_n_tx : 1'bz);
+ assign usb_p_rx = usb_tx_en ? 1'b1 : usb_fpga_dp;
+ assign usb_n_rx = usb_tx_en ? 1'b0 : usb_fpga_dn;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// Vendor-specific clock output to SPI config flash
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ USRMCLK usrmclk_inst (
+ .USRMCLKI(S_flash_clk),
+ .USRMCLKTS(S_flash_csn)
+ ) /* synthesis syn_noprune=1 */;
+ assign flash_csn = S_flash_csn;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// Debonuce and prolong RESET
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ always @(posedge clk_48mhz)
+ begin
+ if (btn[1] | ~clk_ready)
+ reset_counter <= 0;
+ else
+ if (reset_counter[15] == 0)
+ reset_counter <= reset_counter + 1;
+ end
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// ULX3S board buttons and LEDs
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ assign wifi_gpio0 = btn[0];
+ assign led[0] = pin_led;
+ assign led[1] = ~pin_led;
+ assign led[5] = debug_led;
+ assign led[7] = boot;
+ // assign led[3:0] = {flash_miso, flash_mosi, S_flash_clk, S_flash_csn};
+
+ // PULLUP 1.5k D+
+ assign usb_fpga_pu_dp = 1;
+
+ // set 1 to holdn wpn for use as single bit mode spi
+ assign flash_holdn = 1;
+ assign flash_wpn = 1;
+
+ // EXIT from BOOTLOADER
+ assign user_programn = ~boot;
+
+
+endmodule
diff --git a/boards/ulx3s-v2.0-25f-sp/ulx3s_25f_multiboot_flash_is25lp032d.xcf b/boards/ulx3s-v2.0-25f-sp/ulx3s_25f_multiboot_flash_is25lp032d.xcf
new file mode 100644
index 0000000..475cb87
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/ulx3s_25f_multiboot_flash_is25lp032d.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-25F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project_multiboot_flash_is25lp032d.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-25F
+ 0x41111043
+ All
+ LFE5U-25F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ Micron
+ SPI Serial Flash
+ SPI-M25P128
+ 0x15
+ 8-pin VDFPN8
+ SPI Flash Erase,Program
+ project/project_project_multiboot_flash_is25lp032d.mcs
+ 0x00000000
+ 0x01000000
+ 128
+ 16777216
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project_multiboot_flash_is25lp032d.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v2.0-25f-sp/ulx3s_25f_multiboot_flash_is25lp128f.xcf b/boards/ulx3s-v2.0-25f-sp/ulx3s_25f_multiboot_flash_is25lp128f.xcf
new file mode 100644
index 0000000..b8e7592
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/ulx3s_25f_multiboot_flash_is25lp128f.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-25F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project_multiboot_flash_is25lp128f.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-25F
+ 0x41111043
+ All
+ LFE5U-25F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ SPANSION
+ SPI Serial Flash
+ SPI-S25FL128S
+ 0x17
+ 8-lead WSON
+ SPI Flash Erase,Program
+ project/project_project_multiboot_flash_is25lp128f.mcs
+ 0x00000000
+ 0x01000000
+ 128
+ 16777216
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project_multiboot_flash_is25lp128f.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v2.0-25f-sp/ulx3s_25f_multiboot_flash_s25fl164k.xcf b/boards/ulx3s-v2.0-25f-sp/ulx3s_25f_multiboot_flash_s25fl164k.xcf
new file mode 100644
index 0000000..663e7c8
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/ulx3s_25f_multiboot_flash_s25fl164k.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-25F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project_multiboot_flash_s25fl164k.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-25F
+ 0x41111043
+ All
+ LFE5U-25F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ SPANSION
+ SPI Serial Flash
+ SPI-S25FL164K
+ 0x16
+ 8-lead SOIC
+ SPI Flash Erase,Program
+ project/project_project_multiboot_flash_s25fl164k.mcs
+ 0x00000000
+ 0x00800000
+ 64
+ 8388608
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project_multiboot_flash_s25fl164k.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v2.0-25f-sp/ulx3s_25f_sram.xcf b/boards/ulx3s-v2.0-25f-sp/ulx3s_25f_sram.xcf
new file mode 100644
index 0000000..dd6a770
--- /dev/null
+++ b/boards/ulx3s-v2.0-25f-sp/ulx3s_25f_sram.xcf
@@ -0,0 +1,48 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-25F
+ 0x41111043
+ All
+ LFE5U-25F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project.bit
+ Fast Program
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ DUAL RS232-HS A Location 0000 Serial Dual RS232-HS A
+
+
diff --git a/boards/ulx3s-v2.0-45f-sp/Makefile b/boards/ulx3s-v2.0-45f-sp/Makefile
new file mode 100644
index 0000000..cabda75
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/Makefile
@@ -0,0 +1,140 @@
+
+PROJ_FILE := $(shell ls *.ldf | head -1)
+PROJ_NAME := $(shell fgrep default_implementation ${PROJ_FILE} | cut -d'"' -f 4)
+IMPL_NAME := $(shell fgrep default_implementation ${PROJ_FILE} | cut -d'"' -f 8)
+IMPL_DIR := $(shell fgrep default_strategy ${PROJ_FILE} | cut -d'"' -f 4)
+
+DIAMOND_BASE := /usr/local/diamond
+DIAMOND_BIN := $(shell find ${DIAMOND_BASE}/ -maxdepth 2 -name bin | sort -rn | head -1)
+DIAMONDC := $(shell find ${DIAMOND_BIN}/ -name diamondc)
+DDTCMD := $(shell find ${DIAMOND_BIN}/ -name ddtcmd)
+
+OPENOCD = openocd_ft232r
+# OPENOCD_BASE := ../../programmer/openocd/ulx3s
+OPENOCD_BASE := .
+
+# name of the project as defined in project file
+PROJECT = project
+
+# FPGA flashing device for programming
+FPGA_DEVICE = LFE5U-45F
+
+JUNK = ${IMPL_DIR} .recovery ._Real_._Math_.vhd *.sty reportview.xml
+JUNK += dummy_sym.sort project_tcl.html promote.xml
+JUNK += generate_core.tcl generate_ngd.tcl msg_file.log
+JUNK += project_tcr.dir
+
+all: $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.svf \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.svf \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.svf \
+
+
+$(PROJECT)/$(PROJECT)_$(PROJECT).bit:
+ echo prj_project open ${PROJ_FILE} \; prj_run Export -task Bitgen | ${DIAMONDC}
+
+# same file with different name required for multiboot to work
+$(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ cp $< $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_45f_sram.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_45f_sram.xcf -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT).mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit -oft -int -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -oft -advanced -format int -flashsize 32 -header -quad 4 \
+ -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -golden $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -multi 1 -altfile $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit -address 0x200000 -next prim -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.vme: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_45f_multiboot_flash_is25lp032d.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.svf: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.mcs
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_45f_multiboot_flash_is25lp032d.xcf -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -oft -advanced -format int -flashsize 64 -header -quad 4 \
+ -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -golden $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -multi 1 -altfile $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit -address 0x200000 -next prim -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.vme: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_45f_multiboot_flash_s25fl164k.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.svf: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.mcs
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_45f_multiboot_flash_s25fl164k.xcf -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -oft -advanced -format int -flashsize 128 -header -quad 4 \
+ -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -golden $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -multi 1 -altfile $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit -address 0x200000 -next prim -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.vme: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_45f_multiboot_flash_is25lp128f.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.svf: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.mcs
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_45f_multiboot_flash_is25lp128f.xcf -of $@
+
+program: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ echo pgr_project open ulx3s_45f_sram.xcf \; pgr_program run | ${DIAMONDC}
+
+program_wifi: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ openocd --file=$(OPENOCD_BASE)/remote.ocd --file=$(OPENOCD_BASE)/ecp5-45f.ocd
+
+program_web: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ svfupload.py ulx3s.lan $<
+
+program_web_flash: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.svf
+ svfupload.py ulx3s.lan $<
+
+program_ft2232: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ openocd --file=$(OPENOCD_BASE)/ft2232-fpu1.ocd --file=$(OPENOCD_BASE)/ecp5-45f.ocd
+
+program_ft231x: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ openocd_ft232r --file=$(OPENOCD_BASE)/ft231x.ocd --file=$(OPENOCD_BASE)/ecp5-45f.ocd
+
+program_flea: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme
+ FleaFPGA-JTAG $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme
+
+program_flea_flash: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.vme
+ FleaFPGA-JTAG $<
+
+program_flea_flash_spansion: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.vme
+ FleaFPGA-JTAG $<
+
+#$(PROJECT)/$(PROJECT)_$(PROJECT).jed:
+# echo prj_project open ${PROJ_FILE} \; prj_run Export -task Jedecgen | ${DIAMONDC}
+
+#$(PROJECT)/$(PROJECT)_$(PROJECT)_flash.vme: $(PROJECT)/$(PROJECT)_$(PROJECT).jed
+# ${DDTCMD} -oft -fullvme -if sparrowhawk_flash_is25lp128f.xcf -nocompress -noheader -of $@
+
+#$(PROJECT)/$(PROJECT)_$(PROJECT)_flash.svf: $(PROJECT)/$(PROJECT)_$(PROJECT).jed
+# ${DDTCMD} -oft -svfsingle -op "FLASH Erase,Program,Verify" -if $< -of $@
+
+flash: $(PROJECT)/$(PROJECT)_$(PROJECT)_flash.vme
+ ${PROGRAMMERC} $<
+ # after this, to gain access to serial port on linux
+ # rmmod ftdi_sio; modprobe ftdi_sio
+
+# example another project
+#%.svf : %.jed
+# ${DDTCMD} -oft -svfsingle -op "FLASH Erase,Program,Verify" -if $< -of $@
+# mv -f $@ $@.flash
+# ${DDTCMD} -oft -svfsingle -revd -op "SRAM Fast Program" -if $< -of $@
+# mv -f $@ $@.sram
+# ./svf_to_urjtag.pl <$@.flash | sed 's/,/./g' > $@
+
+clean:
+ rm -rf $(JUNK) *~
diff --git a/boards/ulx3s-v2.0-45f-sp/bootloader.ldf b/boards/ulx3s-v2.0-45f-sp/bootloader.ldf
new file mode 100644
index 0000000..a125c79
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/bootloader.ldf
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-v2.0-45f-sp/clocks/clk_200M_48M.v b/boards/ulx3s-v2.0-45f-sp/clocks/clk_200M_48M.v
new file mode 100644
index 0000000..2e9bb80
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/clocks/clk_200M_48M.v
@@ -0,0 +1,75 @@
+/* Verilog netlist generated by SCUBA Diamond (64-bit) 3.7.0.96.1 */
+/* Module Version: 5.7 */
+/* /mt/lattice/diamond/3.7_x64/ispfpga/bin/lin64/scuba -w -n clk_200M_48M -lang verilog -synth synplify -bus_exp 7 -bb -arch sa5p00 -type pll -fin 200.00 -fclkop 48.00 -fclkop_tol 0.0 -phase_cntl STATIC -fb_mode 1 -fdc /home/guest/src/fpga/usbserial-core/TinyFPGA-Bootloader/boards/ulx3s/clock/clk_200M_48M/clk_200M_48M.fdc */
+/* Wed Jul 11 00:10:22 2018 */
+
+
+`timescale 1 ns / 1 ps
+module clk_200M_48M (CLKI, CLKOP, LOCK)/* synthesis NGD_DRC_MASK=1 */;
+ input wire CLKI;
+ output wire CLKOP;
+ output wire LOCK;
+
+ wire REFCLK;
+ wire CLKOP_t;
+ wire scuba_vhi;
+ wire scuba_vlo;
+
+ VHI scuba_vhi_inst (.Z(scuba_vhi));
+
+ VLO scuba_vlo_inst (.Z(scuba_vlo));
+
+ defparam PLLInst_0.PLLRST_ENA = "DISABLED" ;
+ defparam PLLInst_0.INTFB_WAKE = "DISABLED" ;
+ defparam PLLInst_0.STDBY_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.DPHASE_SOURCE = "DISABLED" ;
+ defparam PLLInst_0.CLKOS3_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS3_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_CPHASE = 11 ;
+ defparam PLLInst_0.PLL_LOCK_MODE = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.CLKOP_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOP_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXD = "DIVD" ;
+ defparam PLLInst_0.CLKOS3_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXC = "DIVC" ;
+ defparam PLLInst_0.CLKOS2_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXB = "DIVB" ;
+ defparam PLLInst_0.CLKOS_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXA = "DIVA" ;
+ defparam PLLInst_0.CLKOP_ENABLE = "ENABLED" ;
+ defparam PLLInst_0.CLKOS3_DIV = 1 ;
+ defparam PLLInst_0.CLKOS2_DIV = 1 ;
+ defparam PLLInst_0.CLKOS_DIV = 1 ;
+ defparam PLLInst_0.CLKOP_DIV = 12 ;
+ defparam PLLInst_0.CLKFB_DIV = 6 ;
+ defparam PLLInst_0.CLKI_DIV = 25 ;
+ defparam PLLInst_0.FEEDBK_PATH = "CLKOP" ;
+ EHXPLLL PLLInst_0 (.CLKI(CLKI), .CLKFB(CLKOP_t), .PHASESEL1(scuba_vlo),
+ .PHASESEL0(scuba_vlo), .PHASEDIR(scuba_vlo), .PHASESTEP(scuba_vlo),
+ .PHASELOADREG(scuba_vlo), .STDBY(scuba_vlo), .PLLWAKESYNC(scuba_vlo),
+ .RST(scuba_vlo), .ENCLKOP(scuba_vlo), .ENCLKOS(scuba_vlo), .ENCLKOS2(scuba_vlo),
+ .ENCLKOS3(scuba_vlo), .CLKOP(CLKOP_t), .CLKOS(), .CLKOS2(), .CLKOS3(),
+ .LOCK(LOCK), .INTLOCK(), .REFCLK(REFCLK), .CLKINTFB())
+ /* synthesis FREQUENCY_PIN_CLKOP="48.000000" */
+ /* synthesis FREQUENCY_PIN_CLKI="200.000000" */
+ /* synthesis ICP_CURRENT="5" */
+ /* synthesis LPF_RESISTOR="16" */;
+
+ assign CLKOP = CLKOP_t;
+
+
+ // exemplar begin
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKOP 48.000000
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKI 200.000000
+ // exemplar attribute PLLInst_0 ICP_CURRENT 5
+ // exemplar attribute PLLInst_0 LPF_RESISTOR 16
+ // exemplar end
+
+endmodule
diff --git a/boards/ulx3s-v2.0-45f-sp/clocks/clk_25M_200M.v b/boards/ulx3s-v2.0-45f-sp/clocks/clk_25M_200M.v
new file mode 100644
index 0000000..0ce5c18
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/clocks/clk_25M_200M.v
@@ -0,0 +1,75 @@
+/* Verilog netlist generated by SCUBA Diamond (64-bit) 3.7.0.96.1 */
+/* Module Version: 5.7 */
+/* /mt/lattice/diamond/3.7_x64/ispfpga/bin/lin64/scuba -w -n clk_25M_200M -lang verilog -synth synplify -bus_exp 7 -bb -arch sa5p00 -type pll -fin 25.00 -fclkop 200.00 -fclkop_tol 0.0 -phase_cntl STATIC -fb_mode 1 -fdc /home/guest/src/fpga/usbserial-core/TinyFPGA-Bootloader/boards/ulx3s/clock/clk_25M_200M/clk_25M_200M.fdc */
+/* Wed Jul 11 00:09:44 2018 */
+
+
+`timescale 1 ns / 1 ps
+module clk_25M_200M (CLKI, CLKOP)/* synthesis NGD_DRC_MASK=1 */;
+ input wire CLKI;
+ output wire CLKOP;
+
+ wire REFCLK;
+ wire LOCK;
+ wire CLKOP_t;
+ wire scuba_vhi;
+ wire scuba_vlo;
+
+ VHI scuba_vhi_inst (.Z(scuba_vhi));
+
+ VLO scuba_vlo_inst (.Z(scuba_vlo));
+
+ defparam PLLInst_0.PLLRST_ENA = "DISABLED" ;
+ defparam PLLInst_0.INTFB_WAKE = "DISABLED" ;
+ defparam PLLInst_0.STDBY_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.DPHASE_SOURCE = "DISABLED" ;
+ defparam PLLInst_0.CLKOS3_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS3_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_CPHASE = 2 ;
+ defparam PLLInst_0.PLL_LOCK_MODE = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.CLKOP_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOP_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXD = "DIVD" ;
+ defparam PLLInst_0.CLKOS3_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXC = "DIVC" ;
+ defparam PLLInst_0.CLKOS2_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXB = "DIVB" ;
+ defparam PLLInst_0.CLKOS_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXA = "DIVA" ;
+ defparam PLLInst_0.CLKOP_ENABLE = "ENABLED" ;
+ defparam PLLInst_0.CLKOS3_DIV = 1 ;
+ defparam PLLInst_0.CLKOS2_DIV = 1 ;
+ defparam PLLInst_0.CLKOS_DIV = 1 ;
+ defparam PLLInst_0.CLKOP_DIV = 3 ;
+ defparam PLLInst_0.CLKFB_DIV = 8 ;
+ defparam PLLInst_0.CLKI_DIV = 1 ;
+ defparam PLLInst_0.FEEDBK_PATH = "CLKOP" ;
+ EHXPLLL PLLInst_0 (.CLKI(CLKI), .CLKFB(CLKOP_t), .PHASESEL1(scuba_vlo),
+ .PHASESEL0(scuba_vlo), .PHASEDIR(scuba_vlo), .PHASESTEP(scuba_vlo),
+ .PHASELOADREG(scuba_vlo), .STDBY(scuba_vlo), .PLLWAKESYNC(scuba_vlo),
+ .RST(scuba_vlo), .ENCLKOP(scuba_vlo), .ENCLKOS(scuba_vlo), .ENCLKOS2(scuba_vlo),
+ .ENCLKOS3(scuba_vlo), .CLKOP(CLKOP_t), .CLKOS(), .CLKOS2(), .CLKOS3(),
+ .LOCK(LOCK), .INTLOCK(), .REFCLK(REFCLK), .CLKINTFB())
+ /* synthesis FREQUENCY_PIN_CLKOP="200.000000" */
+ /* synthesis FREQUENCY_PIN_CLKI="25.000000" */
+ /* synthesis ICP_CURRENT="5" */
+ /* synthesis LPF_RESISTOR="16" */;
+
+ assign CLKOP = CLKOP_t;
+
+
+ // exemplar begin
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKOP 200.000000
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKI 25.000000
+ // exemplar attribute PLLInst_0 ICP_CURRENT 5
+ // exemplar attribute PLLInst_0 LPF_RESISTOR 16
+ // exemplar end
+
+endmodule
diff --git a/boards/ulx3s-v2.0-45f-sp/constraints/ulx3s_v17patch.lpf b/boards/ulx3s-v2.0-45f-sp/constraints/ulx3s_v17patch.lpf
new file mode 100644
index 0000000..8e0d34c
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/constraints/ulx3s_v17patch.lpf
@@ -0,0 +1,435 @@
+BLOCK RESETPATHS;
+BLOCK ASYNCPATHS;
+## ULX3S v1.7 patched towards v1.8
+
+# The clock "usb" and "gpdi" sheet
+LOCATE COMP "clk_25mhz" SITE "G2";
+IOBUF PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33;
+FREQUENCY PORT "clk_25mhz" 25 MHZ;
+
+# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash
+SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 SLAVE_SPI_PORT=DISABLE MASTER_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE;
+
+## USBSERIAL FTDI-FPGA serial port "usb" sheet
+LOCATE COMP "ftdi_rxd" SITE "L4"; # FPGA transmits to ftdi
+LOCATE COMP "ftdi_txd" SITE "M1"; # FPGA receives from ftdi
+LOCATE COMP "ftdi_nrts" SITE "M3"; # FPGA receives
+LOCATE COMP "ftdi_ndtr" SITE "N1"; # FPGA receives
+LOCATE COMP "ftdi_txden" SITE "L3"; # FPGA receives
+IOBUF PORT "ftdi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "ftdi_txd" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_nrts" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_ndtr" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_txden" PULLMODE=UP IO_TYPE=LVCMOS33;
+
+## LED indicators "blinkey" and "gpio" sheet
+LOCATE COMP "led[7]" SITE "H3";
+LOCATE COMP "led[6]" SITE "E1";
+LOCATE COMP "led[5]" SITE "E2";
+LOCATE COMP "led[4]" SITE "D1";
+LOCATE COMP "led[3]" SITE "D2";
+LOCATE COMP "led[2]" SITE "C1";
+LOCATE COMP "led[1]" SITE "C2";
+LOCATE COMP "led[0]" SITE "B2";
+IOBUF PORT "led[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Pushbuttons "blinkey", "flash", "power", "gpdi" sheet
+LOCATE COMP "btn[0]" SITE "D6"; # BTN_PWRn (inverted logic)
+LOCATE COMP "btn[1]" SITE "R1"; # FIRE1
+LOCATE COMP "btn[2]" SITE "T1"; # FIRE2
+LOCATE COMP "btn[3]" SITE "W1"; # UP
+LOCATE COMP "btn[4]" SITE "V1"; # DOWN
+LOCATE COMP "btn[5]" SITE "U1"; # LEFT
+LOCATE COMP "btn[6]" SITE "Y2"; # RIGHT
+IOBUF PORT "btn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[4]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[5]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[6]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## DIP switch "blinkey", "gpio" sheet
+LOCATE COMP "sw[0]" SITE "E8"; # SW1
+LOCATE COMP "sw[1]" SITE "D8"; # SW2
+LOCATE COMP "sw[2]" SITE "D7"; # SW3
+LOCATE COMP "sw[3]" SITE "E7"; # SW4
+IOBUF PORT "sw[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI OLED DISPLAY SSD1331 (Color) or SSD1306 (B/W) "blinkey", "usb" sheet
+LOCATE COMP "oled_clk" SITE "P4";
+LOCATE COMP "oled_mosi" SITE "P3";
+LOCATE COMP "oled_dc" SITE "P1";
+LOCATE COMP "oled_resn" SITE "P2";
+LOCATE COMP "oled_csn" SITE "N2";
+IOBUF PORT "oled_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_dc" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_resn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI Flash chip "flash" sheet
+LOCATE COMP "flash_csn" SITE "R2";
+LOCATE COMP "flash_clk" SITE "U3";
+LOCATE COMP "flash_mosi" SITE "W2";
+LOCATE COMP "flash_miso" SITE "V2";
+#LOCATE COMP "flash_csspin" SITE "AJ3";
+#LOCATE COMP "flash_initn" SITE "AG4";
+#LOCATE COMP "flash_done" SITE "AJ4";
+#LOCATE COMP "flash_programn" SITE "AH4";
+#LOCATE COMP "flash_cfg_select[0]" SITE "AM4";
+#LOCATE COMP "flash_cfg_select[1]" SITE "AL4";
+#LOCATE COMP "flash_cfg_select[2]" SITE "AK4";
+IOBUF PORT "flash_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_clk" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_csspin" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_initn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SD card "sdcard", "usb" sheet
+LOCATE COMP "sd_clk" SITE "J1"; # sd_clk WiFi_GPIO14
+LOCATE COMP "sd_cmd" SITE "J3"; # sd_cmd_di (MOSI) WiFi GPIO15
+LOCATE COMP "sd_d[0]" SITE "K2"; # sd_dat0_do (MISO) WiFi GPIO2
+LOCATE COMP "sd_d[1]" SITE "K1"; # sd_dat1_irq WiFi GPIO4
+LOCATE COMP "sd_d[2]" SITE "H2"; # sd_dat2 WiFi_GPIO12
+LOCATE COMP "sd_d[3]" SITE "H1"; # sd_dat3_csn WiFi_GPIO13
+LOCATE COMP "sd_wp" SITE "P5"; # not connected
+LOCATE COMP "sd_cdn" SITE "N5"; # not connected
+IOBUF PORT "sd_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cmd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; # WiFi GPIO12 pulldown bootstrapping requirement
+IOBUF PORT "sd_d[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_wp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## ADC SPI (MAX11123) "analog", "ram" sheet
+LOCATE COMP "adc_csn" SITE "R17";
+LOCATE COMP "adc_mosi" SITE "R16";
+LOCATE COMP "adc_miso" SITE "U16";
+LOCATE COMP "adc_sclk" SITE "P17";
+IOBUF PORT "adc_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_sclk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Audio 4-bit DAC "analog", "gpio" sheet
+# 4-bit mode can drive down to 75 ohm load impedance.
+# Lower impedance leads to IO overload,
+# FPGA will stop working and need reboot.
+# For standard 17 ohm earphones:
+# use bits 2,3 as input (High-Z) and drive only bits 0,1.
+LOCATE COMP "audio_l[3]" SITE "B3"; # JACK TIP (left audio)
+LOCATE COMP "audio_l[2]" SITE "C3";
+LOCATE COMP "audio_l[1]" SITE "D3";
+LOCATE COMP "audio_l[0]" SITE "E4";
+LOCATE COMP "audio_r[3]" SITE "C5"; # JACK RING1 (right audio)
+LOCATE COMP "audio_r[2]" SITE "D5";
+LOCATE COMP "audio_r[1]" SITE "B5";
+LOCATE COMP "audio_r[0]" SITE "A3";
+LOCATE COMP "audio_v[3]" SITE "E5"; # JACK RING2 (video or digital audio)
+LOCATE COMP "audio_v[2]" SITE "F5";
+LOCATE COMP "audio_v[1]" SITE "F2";
+LOCATE COMP "audio_v[0]" SITE "H5";
+IOBUF PORT "audio_l[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## WiFi ESP-32 "wifi", "usb", "flash" sheet
+# other pins are shared with GP/GN, SD card and JTAG
+LOCATE COMP "wifi_en" SITE "F1"; # enable/reset WiFi
+LOCATE COMP "wifi_rxd" SITE "K3"; # FPGA transmits to WiFi
+LOCATE COMP "wifi_txd" SITE "K4"; # FPGA receives from WiFi
+LOCATE COMP "wifi_gpio0" SITE "L2";
+LOCATE COMP "wifi_gpio5" SITE "N4"; # WIFI LED
+LOCATE COMP "wifi_gpio16" SITE "L1";
+LOCATE COMP "wifi_gpio17" SITE "N3";
+# LOCATE COMP "prog_done" SITE "Y3"; # not GPIO, always active
+IOBUF PORT "wifi_en" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_txd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio16" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio17" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+# IOBUF PORT "prog_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## PCB antenna 433 MHz (may be also used for FM) "usb" sheet
+LOCATE COMP "ant_433mhz" SITE "G1";
+IOBUF PORT "ant_433mhz" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Second USB port going directly into FPGA "usb", "ram" sheet
+LOCATE COMP "usb_fpga_dp" SITE "E16";
+LOCATE COMP "usb_fpga_dn" SITE "F16";
+IOBUF PORT "usb_fpga_dp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## JTAG ESP-32 "usb" sheet
+# connected to FT231X and ESP-32
+# commented out because those are dedicated pins, not directly useable as GPIO
+# but could be used by some vendor-specific JTAG bridging (boundary scan) module
+#LOCATE COMP "jtag_tdi" SITE "R5"; # FTDI_nRI FPGA receives
+#LOCATE COMP "jtag_tdo" SITE "V4"; # FTDI_nCTS FPGA transmits
+#LOCATE COMP "jtag_tck" SITE "T5"; # FTDI_nDSR FPGA receives
+#LOCATE COMP "jtag_tms" SITE "U5"; # FTDI_nDCD FPGA receives
+#IOBUF PORT "jtag_tdi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tdo" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tck" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tms" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SDRAM "ram" sheet
+LOCATE COMP "sdram_clk" SITE "F19";
+LOCATE COMP "sdram_cke" SITE "F20";
+LOCATE COMP "sdram_csn" SITE "P20";
+LOCATE COMP "sdram_wen" SITE "T20";
+LOCATE COMP "sdram_rasn" SITE "R20";
+LOCATE COMP "sdram_casn" SITE "T19";
+LOCATE COMP "sdram_a[0]" SITE "M20";
+LOCATE COMP "sdram_a[1]" SITE "M19";
+LOCATE COMP "sdram_a[2]" SITE "L20";
+LOCATE COMP "sdram_a[3]" SITE "L19";
+LOCATE COMP "sdram_a[4]" SITE "K20";
+LOCATE COMP "sdram_a[5]" SITE "K19";
+LOCATE COMP "sdram_a[6]" SITE "K18";
+LOCATE COMP "sdram_a[7]" SITE "J20";
+LOCATE COMP "sdram_a[8]" SITE "J19";
+LOCATE COMP "sdram_a[9]" SITE "H20";
+LOCATE COMP "sdram_a[10]" SITE "N19";
+LOCATE COMP "sdram_a[11]" SITE "G20";
+LOCATE COMP "sdram_a[12]" SITE "G19";
+LOCATE COMP "sdram_ba[0]" SITE "P19";
+LOCATE COMP "sdram_ba[1]" SITE "N20";
+LOCATE COMP "sdram_dqm[0]" SITE "U19";
+LOCATE COMP "sdram_dqm[1]" SITE "E20";
+LOCATE COMP "sdram_d[0]" SITE "J16";
+LOCATE COMP "sdram_d[1]" SITE "L18";
+LOCATE COMP "sdram_d[2]" SITE "M18";
+LOCATE COMP "sdram_d[3]" SITE "N18";
+LOCATE COMP "sdram_d[4]" SITE "P18";
+LOCATE COMP "sdram_d[5]" SITE "T18";
+LOCATE COMP "sdram_d[6]" SITE "T17";
+LOCATE COMP "sdram_d[7]" SITE "U20";
+LOCATE COMP "sdram_d[8]" SITE "E19";
+LOCATE COMP "sdram_d[9]" SITE "D20";
+LOCATE COMP "sdram_d[10]" SITE "D19";
+LOCATE COMP "sdram_d[11]" SITE "C20";
+LOCATE COMP "sdram_d[12]" SITE "E18";
+LOCATE COMP "sdram_d[13]" SITE "F18";
+LOCATE COMP "sdram_d[14]" SITE "J18";
+LOCATE COMP "sdram_d[15]" SITE "J17";
+IOBUF PORT "sdram_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_cke" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_wen" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_rasn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_casn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[13]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[14]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[15]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPDI differential interface (Video) "gpdi" sheet
+LOCATE COMP "gpdi_dp[0]" SITE "A16"; # Blue +
+LOCATE COMP "gpdi_dn[0]" SITE "B16"; # Blue -
+LOCATE COMP "gpdi_dp[1]" SITE "A14"; # Green +
+LOCATE COMP "gpdi_dn[1]" SITE "C14"; # Green -
+LOCATE COMP "gpdi_dp[2]" SITE "A12"; # Red +
+LOCATE COMP "gpdi_dn[2]" SITE "A13"; # Read +
+LOCATE COMP "gpdi_ethp" SITE "A19"; # Ethernet +
+LOCATE COMP "gpdi_ethn" SITE "B20"; # Ethernet -
+LOCATE COMP "gpdi_clkp" SITE "A17"; # Clock +
+LOCATE COMP "gpdi_clkn" SITE "B18"; # Clock -
+LOCATE COMP "gpdi_cec" SITE "A18";
+LOCATE COMP "gpdi_sda" SITE "B19"; # I2C shared with RTC
+LOCATE COMP "gpdi_scl" SITE "C12"; # I2C shared with RTC
+IOBUF PORT "gpdi_dp[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_clkp" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_clkn" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethp" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethn" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_cec" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_sda" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_scl" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPIO (default single-ended) "gpio", "ram", "gpdi" sheet
+# Pins enumerated gp[0-27], gn[0-27].
+# With differential mode enabled on Lattice,
+# gp[] (+) are used, gn[] (-) are ignored from design
+# as they handle inverted signal by default.
+# To enable differential, rename LVCMOS33->LVCMOS33D
+LOCATE COMP "gp[0]" SITE "B11"; # J1_5+ GP0
+LOCATE COMP "gn[0]" SITE "C11"; # J1_5- GN0
+LOCATE COMP "gp[1]" SITE "A10"; # J1_7+ GP1
+LOCATE COMP "gn[1]" SITE "A11"; # J1_7- GN1
+LOCATE COMP "gp[2]" SITE "A9"; # J1_9+ GP2
+LOCATE COMP "gn[2]" SITE "B10"; # J1_9- GN2
+LOCATE COMP "gp[3]" SITE "B9"; # J1_11+ GP3
+LOCATE COMP "gn[3]" SITE "C10"; # J1_11- GN3
+LOCATE COMP "gp[4]" SITE "A7"; # J1_13+ GP4
+LOCATE COMP "gn[4]" SITE "A8"; # J1_13- GN4
+LOCATE COMP "gp[5]" SITE "C8"; # J1_15+ GP5
+LOCATE COMP "gn[5]" SITE "B8"; # J1_15- GN5
+LOCATE COMP "gp[6]" SITE "C6"; # J1_17+ GP6
+LOCATE COMP "gn[6]" SITE "C7"; # J1_17- GN6
+IOBUF PORT "gp[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[7]" SITE "A6"; # J1_23+ GP7
+LOCATE COMP "gn[7]" SITE "B6"; # J1_23- GN7
+LOCATE COMP "gp[8]" SITE "A4"; # J1_25+ GP8
+LOCATE COMP "gn[8]" SITE "A5"; # J1_25- GN8
+LOCATE COMP "gp[9]" SITE "A2"; # J1_27+ GP9
+LOCATE COMP "gn[9]" SITE "B1"; # J1_27- GN9
+LOCATE COMP "gp[10]" SITE "C4"; # J1_29+ GP10 WIFI_GPIO27
+LOCATE COMP "gn[10]" SITE "B4"; # J1_29- GN10
+LOCATE COMP "gp[11]" SITE "F4"; # J1_31+ GP11 WIFI_GPIO25
+LOCATE COMP "gn[11]" SITE "E3"; # J1_31- GN11 WIFI_GPIO26
+LOCATE COMP "gp[12]" SITE "G3"; # J1_33+ GP12 WIFI_GPIO32
+LOCATE COMP "gn[12]" SITE "F3"; # J1_33- GN12 WIFI_GPIO33
+LOCATE COMP "gp[13]" SITE "H4"; # J1_35+ GP13 WIFI_GPIO34
+LOCATE COMP "gn[13]" SITE "G5"; # J1_35- GN13 WIFI_GPIO35
+IOBUF PORT "gp[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[14]" SITE "U18"; # J2_5+ GP14
+LOCATE COMP "gn[14]" SITE "U17"; # J2_5- GN14
+LOCATE COMP "gp[15]" SITE "N17"; # J2_7+ GP15
+LOCATE COMP "gn[15]" SITE "P16"; # J2_7- GN15
+LOCATE COMP "gp[16]" SITE "N16"; # J2_9+ GP16
+LOCATE COMP "gn[16]" SITE "M17"; # J2_9- GN16
+LOCATE COMP "gp[17]" SITE "L16"; # J2_11+ GP17
+LOCATE COMP "gn[17]" SITE "L17"; # J2_11- GN17
+LOCATE COMP "gp[18]" SITE "H18"; # J2_13+ GP18
+LOCATE COMP "gn[18]" SITE "H17"; # J2_13- GN18
+LOCATE COMP "gp[19]" SITE "F17"; # J2_15+ GP19
+LOCATE COMP "gn[19]" SITE "G18"; # J2_15- GN19
+LOCATE COMP "gp[20]" SITE "D18"; # J2_17+ GP20
+LOCATE COMP "gn[20]" SITE "E17"; # J2_17- GN20
+IOBUF PORT "gp[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[21]" SITE "C18"; # J2_23+ GP21
+LOCATE COMP "gn[21]" SITE "D17"; # J2_23- GN21
+LOCATE COMP "gp[22]" SITE "D15"; # J2_25+ GP22
+LOCATE COMP "gn[22]" SITE "E15"; # J2_25- GN22
+LOCATE COMP "gp[23]" SITE "B17"; # J2_27+ GP23
+LOCATE COMP "gn[23]" SITE "C17"; # J2_27- GN23
+LOCATE COMP "gp[24]" SITE "C16"; # J2_29+ GP24
+LOCATE COMP "gn[24]" SITE "D16"; # J2_29- GN24
+LOCATE COMP "gp[25]" SITE "B15"; # J2_31+ GP25
+LOCATE COMP "gn[25]" SITE "C15"; # J2_31- GN25
+LOCATE COMP "gp[26]" SITE "B13"; # J2_33+ GP26
+LOCATE COMP "gn[26]" SITE "C13"; # J2_33- GN26
+LOCATE COMP "gp[27]" SITE "D13"; # J2_35+ GP27
+LOCATE COMP "gn[27]" SITE "E13"; # J2_35- GN27
+IOBUF PORT "gp[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SHUTDOWN "power", "ram" sheet (connected from PCB v1.7.5)
+# on PCB v1.7 shutdown is not connected to FPGA
+LOCATE COMP "shutdown" SITE "G16"; # FPGA receives
+IOBUF PORT "shutdown" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
diff --git a/boards/ulx3s-v2.0-45f-sp/constraints/ulx3s_v20.lpf b/boards/ulx3s-v2.0-45f-sp/constraints/ulx3s_v20.lpf
new file mode 100644
index 0000000..e04bc4f
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/constraints/ulx3s_v20.lpf
@@ -0,0 +1,452 @@
+BLOCK RESETPATHS;
+BLOCK ASYNCPATHS;
+## ULX3S v2.0 and v2.1
+
+# The clock "usb" and "gpdi" sheet
+LOCATE COMP "clk_25mhz" SITE "G2";
+IOBUF PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33;
+FREQUENCY PORT "clk_25mhz" 25 MHZ;
+
+# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash
+SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 MASTER_SPI_PORT=DISABLE SLAVE_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE;
+
+## USBSERIAL FTDI-FPGA serial port "usb" sheet
+LOCATE COMP "ftdi_rxd" SITE "L4"; # FPGA transmits to ftdi
+LOCATE COMP "ftdi_txd" SITE "M1"; # FPGA receives from ftdi
+LOCATE COMP "ftdi_nrts" SITE "M3"; # FPGA receives
+LOCATE COMP "ftdi_ndtr" SITE "N1"; # FPGA receives
+LOCATE COMP "ftdi_txden" SITE "L3"; # FPGA receives
+IOBUF PORT "ftdi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "ftdi_txd" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_nrts" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_ndtr" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_txden" PULLMODE=UP IO_TYPE=LVCMOS33;
+
+## LED indicators "blinkey" and "gpio" sheet
+LOCATE COMP "led[7]" SITE "H3";
+LOCATE COMP "led[6]" SITE "E1";
+LOCATE COMP "led[5]" SITE "E2";
+LOCATE COMP "led[4]" SITE "D1";
+LOCATE COMP "led[3]" SITE "D2";
+LOCATE COMP "led[2]" SITE "C1";
+LOCATE COMP "led[1]" SITE "C2";
+LOCATE COMP "led[0]" SITE "B2";
+IOBUF PORT "led[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Pushbuttons "blinkey", "flash", "power", "gpdi" sheet
+LOCATE COMP "btn[0]" SITE "D6"; # BTN_PWRn (inverted logic)
+LOCATE COMP "btn[1]" SITE "R1"; # FIRE1
+LOCATE COMP "btn[2]" SITE "T1"; # FIRE2
+LOCATE COMP "btn[3]" SITE "R18"; # UP W1->R18
+LOCATE COMP "btn[4]" SITE "V1"; # DOWN
+LOCATE COMP "btn[5]" SITE "U1"; # LEFT
+LOCATE COMP "btn[6]" SITE "H16"; # RIGHT Y2->H16
+IOBUF PORT "btn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[4]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[5]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[6]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## DIP switch "blinkey", "gpio" sheet
+LOCATE COMP "sw[0]" SITE "E8"; # SW1
+LOCATE COMP "sw[1]" SITE "D8"; # SW2
+LOCATE COMP "sw[2]" SITE "D7"; # SW3
+LOCATE COMP "sw[3]" SITE "E7"; # SW4
+IOBUF PORT "sw[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI OLED DISPLAY SSD1331 (Color) or SSD1306 (B/W) "blinkey", "usb" sheet
+LOCATE COMP "oled_clk" SITE "P4";
+LOCATE COMP "oled_mosi" SITE "P3";
+LOCATE COMP "oled_dc" SITE "P1";
+LOCATE COMP "oled_resn" SITE "P2";
+LOCATE COMP "oled_csn" SITE "N2";
+IOBUF PORT "oled_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_dc" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_resn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI Flash chip "flash" sheet
+LOCATE COMP "flash_csn" SITE "R2";
+LOCATE COMP "flash_mosi" SITE "W2";
+LOCATE COMP "flash_miso" SITE "V2";
+LOCATE COMP "flash_holdn" SITE "W1";
+LOCATE COMP "flash_wpn" SITE "Y2";
+#LOCATE COMP "flash_clk" SITE "U3";
+#LOCATE COMP "flash_csspin" SITE "AJ3";
+#LOCATE COMP "flash_initn" SITE "AG4";
+#LOCATE COMP "flash_done" SITE "AJ4";
+#LOCATE COMP "flash_programn" SITE "AH4";
+#LOCATE COMP "flash_cfg_select[0]" SITE "AM4";
+#LOCATE COMP "flash_cfg_select[1]" SITE "AL4";
+#LOCATE COMP "flash_cfg_select[2]" SITE "AK4";
+IOBUF PORT "flash_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_holdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_wpn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_clk" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_csspin" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_initn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SD card "sdcard", "usb" sheet
+LOCATE COMP "sd_clk" SITE "H2"; # sd_clk WiFi_GPIO14
+LOCATE COMP "sd_cmd" SITE "J1"; # sd_cmd_di (MOSI) WiFi GPIO15
+LOCATE COMP "sd_d[0]" SITE "J3"; # sd_dat0_do (MISO) WiFi GPIO2
+LOCATE COMP "sd_d[1]" SITE "H1"; # sd_dat1_irq WiFi GPIO4
+LOCATE COMP "sd_d[2]" SITE "K1"; # sd_dat2 WiFi_GPIO12
+LOCATE COMP "sd_d[3]" SITE "K2"; # sd_dat3_csn WiFi_GPIO13
+LOCATE COMP "sd_wp" SITE "P5"; # not connected
+LOCATE COMP "sd_cdn" SITE "N5"; # not connected
+IOBUF PORT "sd_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cmd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; # WiFi GPIO12 pulldown bootstrapping requirement
+IOBUF PORT "sd_d[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_wp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## ADC SPI (MAX11123) "analog", "ram" sheet
+LOCATE COMP "adc_csn" SITE "R17";
+LOCATE COMP "adc_mosi" SITE "R16";
+LOCATE COMP "adc_miso" SITE "U16";
+LOCATE COMP "adc_sclk" SITE "P17";
+IOBUF PORT "adc_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_sclk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Audio 4-bit DAC "analog", "gpio" sheet
+# 4-bit mode can drive down to 75 ohm load impedance.
+# Lower impedance leads to IO overload,
+# FPGA will stop working and need reboot.
+# For standard 17 ohm earphones:
+# use bits 2,3 as input (High-Z) and drive only bits 0,1.
+LOCATE COMP "audio_l[3]" SITE "B3"; # JACK TIP (left audio)
+LOCATE COMP "audio_l[2]" SITE "C3";
+LOCATE COMP "audio_l[1]" SITE "D3";
+LOCATE COMP "audio_l[0]" SITE "E4";
+LOCATE COMP "audio_r[3]" SITE "C5"; # JACK RING1 (right audio)
+LOCATE COMP "audio_r[2]" SITE "D5";
+LOCATE COMP "audio_r[1]" SITE "B5";
+LOCATE COMP "audio_r[0]" SITE "A3";
+LOCATE COMP "audio_v[3]" SITE "E5"; # JACK RING2 (video or digital audio)
+LOCATE COMP "audio_v[2]" SITE "F5";
+LOCATE COMP "audio_v[1]" SITE "F2";
+LOCATE COMP "audio_v[0]" SITE "H5";
+IOBUF PORT "audio_l[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## WiFi ESP-32 "wifi", "usb", "flash" sheet
+# other pins are shared with GP/GN, SD card and JTAG
+LOCATE COMP "wifi_en" SITE "F1"; # enable/reset WiFi
+LOCATE COMP "wifi_rxd" SITE "K3"; # FPGA transmits to WiFi
+LOCATE COMP "wifi_txd" SITE "K4"; # FPGA receives from WiFi
+LOCATE COMP "wifi_gpio0" SITE "L2";
+LOCATE COMP "wifi_gpio5" SITE "N4"; # WIFI LED
+LOCATE COMP "wifi_gpio16" SITE "L1"; # Serial1 RX
+LOCATE COMP "wifi_gpio17" SITE "N3"; # Serial1 TX
+# LOCATE COMP "prog_done" SITE "Y3"; # not GPIO, always active
+IOBUF PORT "wifi_en" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_txd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio16" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio17" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+# IOBUF PORT "prog_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## PCB antenna 433 MHz (may be also used for FM) "usb" sheet
+LOCATE COMP "ant_433mhz" SITE "G1";
+IOBUF PORT "ant_433mhz" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Second USB port "US2" going directly into FPGA "usb", "ram" sheet
+LOCATE COMP "usb_fpga_dp" SITE "E16"; # single ended or differential input only
+LOCATE COMP "usb_fpga_dn" SITE "F16";
+IOBUF PORT "usb_fpga_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+LOCATE COMP "usb_fpga_bd_dp" SITE "D15"; # differential bidirectional
+LOCATE COMP "usb_fpga_bd_dn" SITE "E15";
+IOBUF PORT "usb_fpga_bd_dp" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "usb_fpga_bd_dn" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=4;
+LOCATE COMP "usb_fpga_pu_dp" SITE "B12"; # pull up/down control
+LOCATE COMP "usb_fpga_pu_dn" SITE "C12";
+IOBUF PORT "usb_fpga_pu_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+IOBUF PORT "usb_fpga_pu_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+
+## JTAG ESP-32 "usb" sheet
+# connected to FT231X and ESP-32
+# commented out because those are dedicated pins, not directly useable as GPIO
+# but could be used by some vendor-specific JTAG bridging (boundary scan) module
+#LOCATE COMP "jtag_tdi" SITE "R5"; # FTDI_nRI FPGA receives
+#LOCATE COMP "jtag_tdo" SITE "V4"; # FTDI_nCTS FPGA transmits
+#LOCATE COMP "jtag_tck" SITE "T5"; # FTDI_nDSR FPGA receives
+#LOCATE COMP "jtag_tms" SITE "U5"; # FTDI_nDCD FPGA receives
+#IOBUF PORT "jtag_tdi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tdo" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tck" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tms" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SDRAM "ram" sheet
+LOCATE COMP "sdram_clk" SITE "F19";
+LOCATE COMP "sdram_cke" SITE "F20";
+LOCATE COMP "sdram_csn" SITE "P20";
+LOCATE COMP "sdram_wen" SITE "T20";
+LOCATE COMP "sdram_rasn" SITE "R20";
+LOCATE COMP "sdram_casn" SITE "T19";
+LOCATE COMP "sdram_a[0]" SITE "M20";
+LOCATE COMP "sdram_a[1]" SITE "M19";
+LOCATE COMP "sdram_a[2]" SITE "L20";
+LOCATE COMP "sdram_a[3]" SITE "L19";
+LOCATE COMP "sdram_a[4]" SITE "K20";
+LOCATE COMP "sdram_a[5]" SITE "K19";
+LOCATE COMP "sdram_a[6]" SITE "K18";
+LOCATE COMP "sdram_a[7]" SITE "J20";
+LOCATE COMP "sdram_a[8]" SITE "J19";
+LOCATE COMP "sdram_a[9]" SITE "H20";
+LOCATE COMP "sdram_a[10]" SITE "N19";
+LOCATE COMP "sdram_a[11]" SITE "G20";
+LOCATE COMP "sdram_a[12]" SITE "G19";
+LOCATE COMP "sdram_ba[0]" SITE "P19";
+LOCATE COMP "sdram_ba[1]" SITE "N20";
+LOCATE COMP "sdram_dqm[0]" SITE "U19";
+LOCATE COMP "sdram_dqm[1]" SITE "E20";
+LOCATE COMP "sdram_d[0]" SITE "J16";
+LOCATE COMP "sdram_d[1]" SITE "L18";
+LOCATE COMP "sdram_d[2]" SITE "M18";
+LOCATE COMP "sdram_d[3]" SITE "N18";
+LOCATE COMP "sdram_d[4]" SITE "P18";
+LOCATE COMP "sdram_d[5]" SITE "T18";
+LOCATE COMP "sdram_d[6]" SITE "T17";
+LOCATE COMP "sdram_d[7]" SITE "U20";
+LOCATE COMP "sdram_d[8]" SITE "E19";
+LOCATE COMP "sdram_d[9]" SITE "D20";
+LOCATE COMP "sdram_d[10]" SITE "D19";
+LOCATE COMP "sdram_d[11]" SITE "C20";
+LOCATE COMP "sdram_d[12]" SITE "E18";
+LOCATE COMP "sdram_d[13]" SITE "F18";
+LOCATE COMP "sdram_d[14]" SITE "J18";
+LOCATE COMP "sdram_d[15]" SITE "J17";
+IOBUF PORT "sdram_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_cke" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_wen" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_rasn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_casn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[13]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[14]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[15]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPDI differential interface (Video) "gpdi" sheet
+LOCATE COMP "gpdi_dp[0]" SITE "A16"; # Blue +
+LOCATE COMP "gpdi_dn[0]" SITE "B16"; # Blue -
+LOCATE COMP "gpdi_dp[1]" SITE "A14"; # Green +
+LOCATE COMP "gpdi_dn[1]" SITE "C14"; # Green -
+LOCATE COMP "gpdi_dp[2]" SITE "A12"; # Red +
+LOCATE COMP "gpdi_dn[2]" SITE "A13"; # Red -
+LOCATE COMP "gpdi_dp[3]" SITE "A17"; # Clock +
+LOCATE COMP "gpdi_dn[3]" SITE "B18"; # Clock -
+LOCATE COMP "gpdi_ethp" SITE "A19"; # Ethernet +
+LOCATE COMP "gpdi_ethn" SITE "B20"; # Ethernet -
+LOCATE COMP "gpdi_cec" SITE "A18";
+LOCATE COMP "gpdi_sda" SITE "B19"; # I2C shared with RTC
+LOCATE COMP "gpdi_scl" SITE "E12"; # I2C shared with RTC C12->E12
+IOBUF PORT "gpdi_dp[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[3]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[3]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethp" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethn" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_cec" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_sda" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_scl" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPIO (default single-ended) "gpio", "ram", "gpdi" sheet
+# Pins enumerated gp[0-27], gn[0-27].
+# With differential mode enabled on Lattice,
+# gp[] (+) are used, gn[] (-) are ignored from design
+# as they handle inverted signal by default.
+# To enable differential, rename LVCMOS33->LVCMOS33D
+LOCATE COMP "gp[0]" SITE "B11"; # J1_5+ GP0
+LOCATE COMP "gn[0]" SITE "C11"; # J1_5- GN0
+LOCATE COMP "gp[1]" SITE "A10"; # J1_7+ GP1
+LOCATE COMP "gn[1]" SITE "A11"; # J1_7- GN1
+LOCATE COMP "gp[2]" SITE "A9"; # J1_9+ GP2
+LOCATE COMP "gn[2]" SITE "B10"; # J1_9- GN2
+LOCATE COMP "gp[3]" SITE "B9"; # J1_11+ GP3
+LOCATE COMP "gn[3]" SITE "C10"; # J1_11- GN3
+LOCATE COMP "gp[4]" SITE "A7"; # J1_13+ GP4
+LOCATE COMP "gn[4]" SITE "A8"; # J1_13- GN4
+LOCATE COMP "gp[5]" SITE "C8"; # J1_15+ GP5
+LOCATE COMP "gn[5]" SITE "B8"; # J1_15- GN5
+LOCATE COMP "gp[6]" SITE "C6"; # J1_17+ GP6
+LOCATE COMP "gn[6]" SITE "C7"; # J1_17- GN6
+IOBUF PORT "gp[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[7]" SITE "A6"; # J1_23+ GP7
+LOCATE COMP "gn[7]" SITE "B6"; # J1_23- GN7
+LOCATE COMP "gp[8]" SITE "A4"; # J1_25+ GP8
+LOCATE COMP "gn[8]" SITE "A5"; # J1_25- GN8
+LOCATE COMP "gp[9]" SITE "A2"; # J1_27+ GP9
+LOCATE COMP "gn[9]" SITE "B1"; # J1_27- GN9
+LOCATE COMP "gp[10]" SITE "C4"; # J1_29+ GP10 WIFI_GPIO27
+LOCATE COMP "gn[10]" SITE "B4"; # J1_29- GN10
+LOCATE COMP "gp[11]" SITE "F4"; # J1_31+ GP11 WIFI_GPIO25
+LOCATE COMP "gn[11]" SITE "E3"; # J1_31- GN11 WIFI_GPIO26
+LOCATE COMP "gp[12]" SITE "G3"; # J1_33+ GP12 WIFI_GPIO32
+LOCATE COMP "gn[12]" SITE "F3"; # J1_33- GN12 WIFI_GPIO33
+LOCATE COMP "gp[13]" SITE "H4"; # J1_35+ GP13 WIFI_GPIO34
+LOCATE COMP "gn[13]" SITE "G5"; # J1_35- GN13 WIFI_GPIO35
+IOBUF PORT "gp[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[14]" SITE "U18"; # J2_5+ GP14
+LOCATE COMP "gn[14]" SITE "U17"; # J2_5- GN14
+LOCATE COMP "gp[15]" SITE "N17"; # J2_7+ GP15
+LOCATE COMP "gn[15]" SITE "P16"; # J2_7- GN15
+LOCATE COMP "gp[16]" SITE "N16"; # J2_9+ GP16
+LOCATE COMP "gn[16]" SITE "M17"; # J2_9- GN16
+LOCATE COMP "gp[17]" SITE "L16"; # J2_11+ GP17
+LOCATE COMP "gn[17]" SITE "L17"; # J2_11- GN17
+LOCATE COMP "gp[18]" SITE "H18"; # J2_13+ GP18
+LOCATE COMP "gn[18]" SITE "H17"; # J2_13- GN18
+LOCATE COMP "gp[19]" SITE "F17"; # J2_15+ GP19
+LOCATE COMP "gn[19]" SITE "G18"; # J2_15- GN19
+LOCATE COMP "gp[20]" SITE "D18"; # J2_17+ GP20
+LOCATE COMP "gn[20]" SITE "E17"; # J2_17- GN20
+IOBUF PORT "gp[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[21]" SITE "C18"; # J2_23+ GP21
+LOCATE COMP "gn[21]" SITE "D17"; # J2_23- GN21
+LOCATE COMP "gp[22]" SITE "B15"; # J2_25+ GP22 D15->B15
+LOCATE COMP "gn[22]" SITE "C15"; # J2_25- GN22 E15->C15
+LOCATE COMP "gp[23]" SITE "B17"; # J2_27+ GP23
+LOCATE COMP "gn[23]" SITE "C17"; # J2_27- GN23
+LOCATE COMP "gp[24]" SITE "C16"; # J2_29+ GP24
+LOCATE COMP "gn[24]" SITE "D16"; # J2_29- GN24
+LOCATE COMP "gp[25]" SITE "D14"; # J2_31+ GP25 B15->D14
+LOCATE COMP "gn[25]" SITE "E14"; # J2_31- GN25 C15->E14
+LOCATE COMP "gp[26]" SITE "B13"; # J2_33+ GP26
+LOCATE COMP "gn[26]" SITE "C13"; # J2_33- GN26
+LOCATE COMP "gp[27]" SITE "D13"; # J2_35+ GP27
+LOCATE COMP "gn[27]" SITE "E13"; # J2_35- GN27
+IOBUF PORT "gp[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## PROGRAMN (reload bitstream from FLASH, exit from bootloader)
+# PCB v2.0.5 and higher
+LOCATE COMP "user_programn" SITE "M4";
+IOBUF PORT "user_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SHUTDOWN "power", "ram" sheet (connected from PCB v1.7.5)
+# on PCB v1.7 shutdown is not connected to FPGA
+LOCATE COMP "shutdown" SITE "G16"; # FPGA receives
+IOBUF PORT "shutdown" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
diff --git a/boards/ulx3s-v2.0-45f-sp/ecp5-45f.ocd b/boards/ulx3s-v2.0-45f-sp/ecp5-45f.ocd
new file mode 100644
index 0000000..b45c997
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/ecp5-45f.ocd
@@ -0,0 +1,16 @@
+# ecp5-XXf.cfg
+# OpenOCD commands
+
+telnet_port 4444
+gdb_port 3333
+
+# JTAG TAPs
+#jtag newtap lfe5u12 tap -expected-id 0x21111043 -irlen 8 -irmask 0xFF -ircapture 0x5
+#jtag newtap lfe5u25 tap -expected-id 0x41111043 -irlen 8 -irmask 0xFF -ircapture 0x5
+jtag newtap lfe5u45 tap -expected-id 0x41112043 -irlen 8 -irmask 0xFF -ircapture 0x5
+#jtag newtap lfe5u85 tap -expected-id 0x41113043 -irlen 8 -irmask 0xFF -ircapture 0x5
+
+init
+scan_chain
+svf -tap lfe5u45.tap -quiet -progress project/project_project_sram.svf
+shutdown
diff --git a/boards/ulx3s-v2.0-45f-sp/ft2232-fpu1.ocd b/boards/ulx3s-v2.0-45f-sp/ft2232-fpu1.ocd
new file mode 100644
index 0000000..6c41311
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/ft2232-fpu1.ocd
@@ -0,0 +1,9 @@
+#
+# PLDkit FPU1 JTAG Programmer
+#
+
+interface ftdi
+ftdi_device_desc "FPU1 JTAG Programmer"
+ftdi_vid_pid 0x0403 0x6010
+ftdi_layout_init 0x3088 0x1f8b
+adapter_khz 25000
diff --git a/boards/ulx3s-v2.0-45f-sp/ft231x.ocd b/boards/ulx3s-v2.0-45f-sp/ft231x.ocd
new file mode 100644
index 0000000..f2dee26
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/ft231x.ocd
@@ -0,0 +1,15 @@
+#
+# openocd_ft232r patched for custom jtag nums and buffer_size
+#
+
+interface ft232r
+ft232r_vid_pid 0x0403 0x6015
+# ft232r_serial_desc 12345678
+ft232r_tck_num 5
+ft232r_tms_num 6
+ft232r_tdi_num 7
+ft232r_tdo_num 3
+ft232r_trst_num 2
+ft232r_srst_num 4
+ft232r_buffer_size 16384
+adapter_khz 300
diff --git a/boards/ulx3s-v2.0-45f-sp/initialize/boardmeta4MB.bin b/boards/ulx3s-v2.0-45f-sp/initialize/boardmeta4MB.bin
new file mode 100644
index 0000000..7a525c7
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/initialize/boardmeta4MB.bin
@@ -0,0 +1,119 @@
+{
+ "boardmeta":
+ {
+ "name": "ULX3S",
+ "fpga": "LFE5U-45F-6BG381C",
+ "hver": "1.7",
+ "uuid": "00000000-0000-0000-0000-000000000000",
+ "serial": 12345
+ },
+ "bootmeta":
+ {
+ "bootloader": "TinyFPGA USB Bootloader",
+ "bver": "2.0.0",
+ "update": "https://github.com/emard/TinyFPGA-Bootloader",
+ "addrmap":
+ {
+ "bootloader": "0x000000-0x0FFFFF",
+ "golden": "0x100000-0x1FFFFF",
+ "userimage": "0x200000-0x2FFFFF",
+ "userdata": "0x300000-0x3FBFFF"
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-v2.0-45f-sp/initialize/boardmeta8MB.bin b/boards/ulx3s-v2.0-45f-sp/initialize/boardmeta8MB.bin
new file mode 100644
index 0000000..89be03c
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/initialize/boardmeta8MB.bin
@@ -0,0 +1,58 @@
+{
+ "boardmeta":
+ {
+ "name": "ULX3S",
+ "fpga": "LFE5U-45F-6BG381C",
+ "hver": "1.7",
+ "uuid": "00000000-0000-0000-0000-000000000000",
+ "serial": 12345
+ },
+ "bootmeta":
+ {
+ "bootloader": "TinyFPGA USB Bootloader",
+ "bver": "2.0.0",
+ "update": "https://github.com/emard/TinyFPGA-Bootloader",
+ "addrmap":
+ {
+ "bootloader": "0x000000-0x0FFFFF",
+ "golden": "0x100000-0x1FFFFF",
+ "userimage": "0x200000-0x3FFFFF",
+ "userdata": "0x500000-0x7FBFFF"
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-v2.0-45f-sp/initialize/initialize4MB.sh b/boards/ulx3s-v2.0-45f-sp/initialize/initialize4MB.sh
new file mode 100755
index 0000000..3d67d93
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/initialize/initialize4MB.sh
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+
+# Initializer for ECP5 dual boot.
+
+# first half of the FLASH is for user bitstram
+# bootloader bitstream starts at second half of the FLASH
+# board metadata at last 0x1000 bytes
+# Jump command at last 0x100 bytes
+
+# flash size: 16 Mbit = 2 MB = 0x200000
+# flash size: 32 Mbit = 4 MB = 0x400000
+# flash size: 64 Mbit = 8 MB = 0x800000
+# flash size: 128 Mbit = 16 MB = 0x1000000
+
+bootloader_image_address=$(printf "%d" 0x000000) # 0
+golden_image_address=$(printf "%d" 0x100000) # 0x100000 (1MB) (backup of bootloader)
+board_meta_address=$(printf "%d" 0x3FF000) # flash size - 0x1000
+jump_command_address=$(printf "%d" 0x3FFF00) # flash size - 0x100
+
+# primary image must be generated by diamond deployment tool (ddtcmd)
+# simply overwriting bootloader image will not have multiboot capability
+#tinyprog --pyserial --no-boot -a $bootloader_image_address -u ../../boards/ulx3s-v1.7-45f/tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $golden_image_address -u ../tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $(printf "%d" $board_meta_address) -u boardmeta4MB.bin
+./jump.py $golden_image_address > jump.bin
+tinyprog --pyserial --no-boot -a $(printf "%d" $jump_command_address) -u jump.bin
+# hexdump -C jump.bin
+# check that's board is recognized by tingprog
+tinyprog --pyserial -l
+#tinyprog -m
diff --git a/boards/ulx3s-v2.0-45f-sp/initialize/initialize8MB.sh b/boards/ulx3s-v2.0-45f-sp/initialize/initialize8MB.sh
new file mode 100755
index 0000000..b127f53
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/initialize/initialize8MB.sh
@@ -0,0 +1,31 @@
+#!/bin/sh -e
+
+# Initializer for ECP5 dual boot.
+
+# first half of the FLASH is for user bitstram
+# bootloader bitstream starts at second half of the FLASH
+# board metadata at last 0x1000 bytes
+# Jump command at last 0x100 bytes
+
+# flash size: 8 Mbit = 1 MB = 0x100000
+# flash size: 16 Mbit = 2 MB = 0x200000
+# flash size: 32 Mbit = 4 MB = 0x400000
+# flash size: 64 Mbit = 8 MB = 0x800000
+# flash size: 128 Mbit = 16 MB = 0x1000000
+
+bootloader_image_address=$(printf "%d" 0x000000) # 0
+golden_image_address=$(printf "%d" 0x100000) # 0x100000 (1MB) (backup of bootloader)
+board_meta_address=$(printf "%d" 0x7FF000) # flash size - 0x1000 (-4KB)
+jump_command_address=$(printf "%d" 0x7FFF00) # flash size - 0x100 (-256)
+
+# primary image must be generated by diamond deployment tool (ddtcmd)
+# simply overwriting bootloader image will not have multiboot capability
+#tinyprog --pyserial --no-boot -a $bootloader_image_address -u ../../boards/ulx3s-v1.7-45f/tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $golden_image_address -u ../tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $(printf "%d" $board_meta_address) -u boardmeta8MB.bin
+./jump.py $golden_image_address > jump.bin
+tinyprog --pyserial --no-boot -a $(printf "%d" $jump_command_address) -u jump.bin
+# hexdump -C jump.bin
+# check that's board is recognized by tingprog
+tinyprog --pyserial -l
+#tinyprog -m
diff --git a/boards/ulx3s-v2.0-45f-sp/initialize/jump.bin b/boards/ulx3s-v2.0-45f-sp/initialize/jump.bin
new file mode 100644
index 0000000..d39691f
Binary files /dev/null and b/boards/ulx3s-v2.0-45f-sp/initialize/jump.bin differ
diff --git a/boards/ulx3s-v2.0-45f-sp/initialize/jump.py b/boards/ulx3s-v2.0-45f-sp/initialize/jump.py
new file mode 100755
index 0000000..b1ff948
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/initialize/jump.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+
+# Lattice ECP5 jump command generator
+# TN1216 p.23 describes the jump command syntax which does not work.
+# The syntax has been fixed by looking at dual boot intel hex file
+# generated by diamond, this actually works.
+
+import struct
+import sys
+
+# write output of this funtion at FLASH address:
+# jump_command_address = 0x3FFF00 = 4194048
+
+# write "golden" bitstream at FLASH address:
+golden_image_address = 0x140000
+golden_image_address = int(sys.argv[1])
+
+# normally both 0
+reverse_bytes = 0
+reverse_bits = 0
+
+# to compare with intel HEX file generated by diamond:
+# (not for normal use)
+# reverse_bytes = 1
+# reverse_bits = 1
+# ./jump.py | hexdump -C
+
+def reverse_Bits(n, no_of_bits):
+ result = 0
+ for i in range(no_of_bits):
+ result <<= 1
+ result |= n & 1
+ n >>= 1
+ return result
+
+def uint8(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 8)
+ return struct.pack(">B", n)
+
+def uint16(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 16)
+ if reverse_bytes:
+ return struct.pack("H", n)
+
+def uint24(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 24)
+ if reverse_bytes:
+ return struct.pack("> 8 )
+ else:
+ return struct.pack(">HB", n >> 8, n & 0xFF )
+
+def uint32(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 32)
+ if reverse_bytes:
+ return struct.pack("L", n)
+
+packet = b''
+# Frame (START) 18 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint16(0xFFFF) # 2 dummy bytes (diamond generates this 2 bytes more)
+# Preamble
+packet += uint16(0xBDB3) # Preamble
+# Frame (Control Register 0) commented out, diamond doesn't output this
+# if uncommented, jump won't work:
+#packet += uint8(0xC4) # Write control register 0 command
+#packet += uint24(0) # 24-bit Command Information
+#packet += uint32(0) # Control Register 0 data
+# This is generated by diamond:
+packet += uint32(0xFFFFFFFF) # I don't know what it does but it works
+# Framme (Jump Command)
+#packet += uint8(0xFE) # Jump command Wrong noted in TN1216
+packet += uint8(0x7E) # Jump command generated by diamond
+packet += uint24(0) # 24-bit Command Information
+packet += uint8(0x03) # SPI Flash Read opcode (0x03 = regular read, 0x0B = fast read)
+packet += uint24(golden_image_address) # 24-bit SPI Flash Sector X address
+# Frame (END) 18 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint16(0xFFFF) # 2 dummy bytes (diamond generates this 2 bytes more)
+
+sys.stdout.write(packet)
+# print([elem.encode("hex") for elem in packet])
diff --git a/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k.bit b/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k.bit
new file mode 120000
index 0000000..59e9556
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k.bit
@@ -0,0 +1 @@
+project/project_project.bit
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_multiboot_flash_is25lp032d.svf b/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_multiboot_flash_is25lp032d.svf
new file mode 120000
index 0000000..a01da25
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_multiboot_flash_is25lp032d.svf
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_is25lp032d.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_multiboot_flash_is25lp032d.vme b/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_multiboot_flash_is25lp032d.vme
new file mode 120000
index 0000000..7d99dc6
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_multiboot_flash_is25lp032d.vme
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_is25lp032d.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_multiboot_flash_is25lp128f.svf b/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_multiboot_flash_is25lp128f.svf
new file mode 120000
index 0000000..1b8f717
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_multiboot_flash_is25lp128f.svf
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_is25lp128f.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_multiboot_flash_is25lp128f.vme b/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_multiboot_flash_is25lp128f.vme
new file mode 120000
index 0000000..c736cfa
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_multiboot_flash_is25lp128f.vme
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_is25lp128f.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_multiboot_flash_s25fl164k.svf b/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_multiboot_flash_s25fl164k.svf
new file mode 120000
index 0000000..7232663
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_multiboot_flash_s25fl164k.svf
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_s25fl164k.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_multiboot_flash_s25fl164k.vme b/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_multiboot_flash_s25fl164k.vme
new file mode 120000
index 0000000..cadb80a
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_multiboot_flash_s25fl164k.vme
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_s25fl164k.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_sram.svf b/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_sram.svf
new file mode 120000
index 0000000..bb7617d
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_sram.svf
@@ -0,0 +1 @@
+project/project_project_sram.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_sram.vme b/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_sram.vme
new file mode 120000
index 0000000..d098048
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/tinyfpga_45k_sram.vme
@@ -0,0 +1 @@
+project/project_project_sram.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-45f-sp/top/bootloader_sp_ulx3s.v b/boards/ulx3s-v2.0-45f-sp/top/bootloader_sp_ulx3s.v
new file mode 100644
index 0000000..e106183
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/top/bootloader_sp_ulx3s.v
@@ -0,0 +1,141 @@
+module bootloader_sp_ulx3s (
+ input clk_25mhz,
+
+ inout usb_fpga_dp,
+ inout usb_fpga_dn,
+
+ output usb_fpga_pu_dp,
+ inout user_programn,
+
+ output [7:0] led,
+
+ input flash_miso,
+ output flash_mosi,
+ output flash_csn,
+ output flash_wpn,
+ output flash_holdn,
+
+ input [6:0] btn,
+ output wifi_gpio0
+);
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// generate 48 mhz clock
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ wire clk_200mhz;
+ clk_25M_200M clk_200M_inst (
+ .CLKI(clk_25mhz),
+ .CLKOP(clk_200mhz)
+ );
+
+ wire clk_48mhz;
+ wire clk_ready;
+ clk_200M_48M clk_48M_inst (
+ .CLKI(clk_200mhz),
+ .CLKOP(clk_48mhz),
+ .LOCK(clk_ready)
+ );
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// instantiate tinyfpga bootloader
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ reg [15:0] reset_counter = 0; // counter for debouce and prolong reset
+ wire reset;
+ assign reset = ~reset_counter[15];
+ wire usb_p_tx;
+ wire usb_n_tx;
+ wire usb_p_rx;
+ wire usb_n_rx;
+ wire usb_tx_en;
+ wire pin_led;
+ wire [7:0] debug_led;
+ wire boot;
+ wire S_flash_clk;
+ wire S_flash_csn;
+
+ tinyfpgasp_bootloader tinyfpgasp_bootloader_inst (
+ .clk_48mhz(clk_48mhz),
+ .reset(reset),
+ .usb_p_tx(usb_p_tx),
+ .usb_n_tx(usb_n_tx),
+ .usb_p_rx(usb_p_rx),
+ .usb_n_rx(usb_n_rx),
+ .usb_tx_en(usb_tx_en),
+ .led(pin_led),
+ .debug_led(debug_led),
+ .spi_miso(flash_miso),
+ .spi_mosi(flash_mosi),
+ .spi_sck(S_flash_clk),
+ .spi_cs(S_flash_csn),
+ .boot(boot)
+ );
+
+ assign usb_fpga_dp = reset ? 1'b0 : (usb_tx_en ? usb_p_tx : 1'bz);
+ assign usb_fpga_dn = reset ? 1'b0 : (usb_tx_en ? usb_n_tx : 1'bz);
+ assign usb_p_rx = usb_tx_en ? 1'b1 : usb_fpga_dp;
+ assign usb_n_rx = usb_tx_en ? 1'b0 : usb_fpga_dn;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// Vendor-specific clock output to SPI config flash
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ USRMCLK usrmclk_inst (
+ .USRMCLKI(S_flash_clk),
+ .USRMCLKTS(S_flash_csn)
+ ) /* synthesis syn_noprune=1 */;
+ assign flash_csn = S_flash_csn;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// Debonuce and prolong RESET
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ always @(posedge clk_48mhz)
+ begin
+ if (btn[1] | ~clk_ready)
+ reset_counter <= 0;
+ else
+ if (reset_counter[15] == 0)
+ reset_counter <= reset_counter + 1;
+ end
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// ULX3S board buttons and LEDs
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ assign wifi_gpio0 = btn[0];
+ assign led[0] = pin_led;
+ assign led[1] = ~pin_led;
+ assign led[5] = debug_led;
+ assign led[7] = boot;
+ // assign led[3:0] = {flash_miso, flash_mosi, S_flash_clk, S_flash_csn};
+
+ // PULLUP 1.5k D+
+ assign usb_fpga_pu_dp = 1;
+
+ // set 1 to holdn wpn for use as single bit mode spi
+ assign flash_holdn = 1;
+ assign flash_wpn = 1;
+
+ // EXIT from BOOTLOADER
+ assign user_programn = ~boot;
+
+
+endmodule
diff --git a/boards/ulx3s-v2.0-45f-sp/ulx3s_45f_multiboot_flash_is25lp032d.xcf b/boards/ulx3s-v2.0-45f-sp/ulx3s_45f_multiboot_flash_is25lp032d.xcf
new file mode 100644
index 0000000..f2698c1
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/ulx3s_45f_multiboot_flash_is25lp032d.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-45F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project_multiboot_flash_is25lp032d.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-45F
+ 0x41112043
+ All
+ LFE5U-45F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ Micron
+ SPI Serial Flash
+ SPI-M25P128
+ 0x15
+ 8-pin VDFPN8
+ SPI Flash Erase,Program
+ project/project_project_multiboot_flash_is25lp032d.mcs
+ 0x00000000
+ 0x01000000
+ 128
+ 16777216
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project_multiboot_flash_is25lp032d.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v2.0-45f-sp/ulx3s_45f_multiboot_flash_is25lp128f.xcf b/boards/ulx3s-v2.0-45f-sp/ulx3s_45f_multiboot_flash_is25lp128f.xcf
new file mode 100644
index 0000000..a3e2693
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/ulx3s_45f_multiboot_flash_is25lp128f.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-45F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project_multiboot_flash_is25lp128f.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-45F
+ 0x41112043
+ All
+ LFE5U-45F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ SPANSION
+ SPI Serial Flash
+ SPI-S25FL128S
+ 0x17
+ 8-lead WSON
+ SPI Flash Erase,Program
+ project/project_project_multiboot_flash_is25lp128f.mcs
+ 0x00000000
+ 0x01000000
+ 128
+ 16777216
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project_multiboot_flash_is25lp128f.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v2.0-45f-sp/ulx3s_45f_multiboot_flash_s25fl164k.xcf b/boards/ulx3s-v2.0-45f-sp/ulx3s_45f_multiboot_flash_s25fl164k.xcf
new file mode 100644
index 0000000..d195828
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/ulx3s_45f_multiboot_flash_s25fl164k.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-45F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project_multiboot_flash_s25fl164k.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-45F
+ 0x41112043
+ All
+ LFE5U-45F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-45F.msk
+ Bypass
+
+
+
+
+
+ 1
+ SPANSION
+ SPI Serial Flash
+ SPI-S25FL164K
+ 0x16
+ 8-lead SOIC
+ SPI Flash Erase,Program
+ project/project_project_multiboot_flash_s25fl164k.mcs
+ 0x00000000
+ 0x00800000
+ 64
+ 8388608
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project_multiboot_flash_s25fl164k.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v2.0-45f-sp/ulx3s_45f_sram.xcf b/boards/ulx3s-v2.0-45f-sp/ulx3s_45f_sram.xcf
new file mode 100644
index 0000000..b11ed78
--- /dev/null
+++ b/boards/ulx3s-v2.0-45f-sp/ulx3s_45f_sram.xcf
@@ -0,0 +1,48 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5UM
+ LFE5U-45F
+ 0x41112043
+ All
+ LFE5U-45F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project.bit
+ Fast Program
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ DUAL RS232-HS A Location 0000 Serial Dual RS232-HS A
+
+
diff --git a/boards/ulx3s-v2.0-85f-sp/Makefile b/boards/ulx3s-v2.0-85f-sp/Makefile
new file mode 100644
index 0000000..ac5fe70
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/Makefile
@@ -0,0 +1,140 @@
+
+PROJ_FILE := $(shell ls *.ldf | head -1)
+PROJ_NAME := $(shell fgrep default_implementation ${PROJ_FILE} | cut -d'"' -f 4)
+IMPL_NAME := $(shell fgrep default_implementation ${PROJ_FILE} | cut -d'"' -f 8)
+IMPL_DIR := $(shell fgrep default_strategy ${PROJ_FILE} | cut -d'"' -f 4)
+
+DIAMOND_BASE := /usr/local/diamond
+DIAMOND_BIN := $(shell find ${DIAMOND_BASE}/ -maxdepth 2 -name bin | sort -rn | head -1)
+DIAMONDC := $(shell find ${DIAMOND_BIN}/ -name diamondc)
+DDTCMD := $(shell find ${DIAMOND_BIN}/ -name ddtcmd)
+
+OPENOCD = openocd_ft232r
+# OPENOCD_BASE := ../../programmer/openocd/ulx3s
+OPENOCD_BASE := .
+
+# name of the project as defined in project file
+PROJECT = project
+
+# FPGA flashing device for programming
+FPGA_DEVICE = LFE5U-85F
+
+JUNK = ${IMPL_DIR} .recovery ._Real_._Math_.vhd *.sty reportview.xml
+JUNK += dummy_sym.sort project_tcl.html promote.xml
+JUNK += generate_core.tcl generate_ngd.tcl msg_file.log
+JUNK += project_tcr.dir
+
+all: $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.svf \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.svf \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.vme \
+ $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.svf \
+
+
+$(PROJECT)/$(PROJECT)_$(PROJECT).bit:
+ echo prj_project open ${PROJ_FILE} \; prj_run Export -task Bitgen | ${DIAMONDC}
+
+# same file with different name required for multiboot to work
+$(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ cp $< $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_85f_sram.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_85f_sram.xcf -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT).mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit -oft -int -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -oft -advanced -format int -flashsize 32 -header -quad 4 \
+ -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -golden $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -multi 1 -altfile $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit -address 0x200000 -next prim -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.vme: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_85f_multiboot_flash_is25lp032d.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.svf: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp032d.mcs
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_85f_multiboot_flash_is25lp032d.xcf -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -oft -advanced -format int -flashsize 64 -header -quad 4 \
+ -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -golden $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -multi 1 -altfile $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit -address 0x200000 -next prim -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.vme: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_85f_multiboot_flash_s25fl164k.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.svf: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.mcs
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_85f_multiboot_flash_s25fl164k.xcf -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.mcs: $(PROJECT)/$(PROJECT)_$(PROJECT).bit $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit
+ LANG=C ${DDTCMD} -dev $(FPGA_DEVICE) -oft -advanced -format int -flashsize 128 -header -quad 4 \
+ -if $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -golden $(PROJECT)/$(PROJECT)_$(PROJECT).bit \
+ -multi 1 -altfile $(PROJECT)/$(PROJECT)_$(PROJECT)_altfile.bit -address 0x200000 -next prim -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.vme: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.mcs
+ LANG=C ${DDTCMD} -oft -fullvme -if ulx3s_85f_multiboot_flash_is25lp128f.xcf -nocompress -noheader -of $@
+
+$(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.svf: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.mcs
+ LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if ulx3s_85f_multiboot_flash_is25lp128f.xcf -of $@
+
+program: $(PROJECT)/$(PROJECT)_$(PROJECT).bit
+ echo pgr_project open ulx3s_85f_sram.xcf \; pgr_program run | ${DIAMONDC}
+
+program_wifi: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ $(OPENOCD) --file=$(OPENOCD_BASE)/remote.ocd --file=$(OPENOCD_BASE)/ecp5-85f.ocd
+
+program_web: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ svfupload.py ulx3s.lan $<
+
+program_web_flash: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.svf
+ svfupload.py ulx3s.lan $<
+
+program_ft2232: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ $(OPENOCD) --file=$(OPENOCD_BASE)/ft2232-fpu1.ocd --file=$(OPENOCD_BASE)/ecp5-85f.ocd
+
+program_ft231x: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.svf
+ $(OPENOCD) --file=$(OPENOCD_BASE)/ft231x.ocd --file=$(OPENOCD_BASE)/ecp5-85f.ocd
+
+program_flea: $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme
+ FleaFPGA-JTAG $(PROJECT)/$(PROJECT)_$(PROJECT)_sram.vme
+
+program_flea_flash: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_is25lp128f.vme
+ FleaFPGA-JTAG $<
+
+program_flea_flash_spansion: $(PROJECT)/$(PROJECT)_$(PROJECT)_multiboot_flash_s25fl164k.vme
+ FleaFPGA-JTAG $<
+
+#$(PROJECT)/$(PROJECT)_$(PROJECT).jed:
+# echo prj_project open ${PROJ_FILE} \; prj_run Export -task Jedecgen | ${DIAMONDC}
+
+#$(PROJECT)/$(PROJECT)_$(PROJECT)_flash.vme: $(PROJECT)/$(PROJECT)_$(PROJECT).jed
+# ${DDTCMD} -oft -fullvme -if sparrowhawk_flash_is25lp128f.xcf -nocompress -noheader -of $@
+
+#$(PROJECT)/$(PROJECT)_$(PROJECT)_flash.svf: $(PROJECT)/$(PROJECT)_$(PROJECT).jed
+# ${DDTCMD} -oft -svfsingle -op "FLASH Erase,Program,Verify" -if $< -of $@
+
+flash: $(PROJECT)/$(PROJECT)_$(PROJECT)_flash.vme
+ ${PROGRAMMERC} $<
+ # after this, to gain access to serial port on linux
+ # rmmod ftdi_sio; modprobe ftdi_sio
+
+# example another project
+#%.svf : %.jed
+# ${DDTCMD} -oft -svfsingle -op "FLASH Erase,Program,Verify" -if $< -of $@
+# mv -f $@ $@.flash
+# ${DDTCMD} -oft -svfsingle -revd -op "SRAM Fast Program" -if $< -of $@
+# mv -f $@ $@.sram
+# ./svf_to_urjtag.pl <$@.flash | sed 's/,/./g' > $@
+
+clean:
+ rm -rf $(JUNK) *~
diff --git a/boards/ulx3s-v2.0-85f-sp/bootloader.ldf b/boards/ulx3s-v2.0-85f-sp/bootloader.ldf
new file mode 100644
index 0000000..936630d
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/bootloader.ldf
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-v2.0-85f-sp/clocks/clk_200M_48M.v b/boards/ulx3s-v2.0-85f-sp/clocks/clk_200M_48M.v
new file mode 100644
index 0000000..2e9bb80
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/clocks/clk_200M_48M.v
@@ -0,0 +1,75 @@
+/* Verilog netlist generated by SCUBA Diamond (64-bit) 3.7.0.96.1 */
+/* Module Version: 5.7 */
+/* /mt/lattice/diamond/3.7_x64/ispfpga/bin/lin64/scuba -w -n clk_200M_48M -lang verilog -synth synplify -bus_exp 7 -bb -arch sa5p00 -type pll -fin 200.00 -fclkop 48.00 -fclkop_tol 0.0 -phase_cntl STATIC -fb_mode 1 -fdc /home/guest/src/fpga/usbserial-core/TinyFPGA-Bootloader/boards/ulx3s/clock/clk_200M_48M/clk_200M_48M.fdc */
+/* Wed Jul 11 00:10:22 2018 */
+
+
+`timescale 1 ns / 1 ps
+module clk_200M_48M (CLKI, CLKOP, LOCK)/* synthesis NGD_DRC_MASK=1 */;
+ input wire CLKI;
+ output wire CLKOP;
+ output wire LOCK;
+
+ wire REFCLK;
+ wire CLKOP_t;
+ wire scuba_vhi;
+ wire scuba_vlo;
+
+ VHI scuba_vhi_inst (.Z(scuba_vhi));
+
+ VLO scuba_vlo_inst (.Z(scuba_vlo));
+
+ defparam PLLInst_0.PLLRST_ENA = "DISABLED" ;
+ defparam PLLInst_0.INTFB_WAKE = "DISABLED" ;
+ defparam PLLInst_0.STDBY_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.DPHASE_SOURCE = "DISABLED" ;
+ defparam PLLInst_0.CLKOS3_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS3_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_CPHASE = 11 ;
+ defparam PLLInst_0.PLL_LOCK_MODE = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.CLKOP_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOP_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXD = "DIVD" ;
+ defparam PLLInst_0.CLKOS3_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXC = "DIVC" ;
+ defparam PLLInst_0.CLKOS2_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXB = "DIVB" ;
+ defparam PLLInst_0.CLKOS_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXA = "DIVA" ;
+ defparam PLLInst_0.CLKOP_ENABLE = "ENABLED" ;
+ defparam PLLInst_0.CLKOS3_DIV = 1 ;
+ defparam PLLInst_0.CLKOS2_DIV = 1 ;
+ defparam PLLInst_0.CLKOS_DIV = 1 ;
+ defparam PLLInst_0.CLKOP_DIV = 12 ;
+ defparam PLLInst_0.CLKFB_DIV = 6 ;
+ defparam PLLInst_0.CLKI_DIV = 25 ;
+ defparam PLLInst_0.FEEDBK_PATH = "CLKOP" ;
+ EHXPLLL PLLInst_0 (.CLKI(CLKI), .CLKFB(CLKOP_t), .PHASESEL1(scuba_vlo),
+ .PHASESEL0(scuba_vlo), .PHASEDIR(scuba_vlo), .PHASESTEP(scuba_vlo),
+ .PHASELOADREG(scuba_vlo), .STDBY(scuba_vlo), .PLLWAKESYNC(scuba_vlo),
+ .RST(scuba_vlo), .ENCLKOP(scuba_vlo), .ENCLKOS(scuba_vlo), .ENCLKOS2(scuba_vlo),
+ .ENCLKOS3(scuba_vlo), .CLKOP(CLKOP_t), .CLKOS(), .CLKOS2(), .CLKOS3(),
+ .LOCK(LOCK), .INTLOCK(), .REFCLK(REFCLK), .CLKINTFB())
+ /* synthesis FREQUENCY_PIN_CLKOP="48.000000" */
+ /* synthesis FREQUENCY_PIN_CLKI="200.000000" */
+ /* synthesis ICP_CURRENT="5" */
+ /* synthesis LPF_RESISTOR="16" */;
+
+ assign CLKOP = CLKOP_t;
+
+
+ // exemplar begin
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKOP 48.000000
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKI 200.000000
+ // exemplar attribute PLLInst_0 ICP_CURRENT 5
+ // exemplar attribute PLLInst_0 LPF_RESISTOR 16
+ // exemplar end
+
+endmodule
diff --git a/boards/ulx3s-v2.0-85f-sp/clocks/clk_25M_200M.v b/boards/ulx3s-v2.0-85f-sp/clocks/clk_25M_200M.v
new file mode 100644
index 0000000..0ce5c18
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/clocks/clk_25M_200M.v
@@ -0,0 +1,75 @@
+/* Verilog netlist generated by SCUBA Diamond (64-bit) 3.7.0.96.1 */
+/* Module Version: 5.7 */
+/* /mt/lattice/diamond/3.7_x64/ispfpga/bin/lin64/scuba -w -n clk_25M_200M -lang verilog -synth synplify -bus_exp 7 -bb -arch sa5p00 -type pll -fin 25.00 -fclkop 200.00 -fclkop_tol 0.0 -phase_cntl STATIC -fb_mode 1 -fdc /home/guest/src/fpga/usbserial-core/TinyFPGA-Bootloader/boards/ulx3s/clock/clk_25M_200M/clk_25M_200M.fdc */
+/* Wed Jul 11 00:09:44 2018 */
+
+
+`timescale 1 ns / 1 ps
+module clk_25M_200M (CLKI, CLKOP)/* synthesis NGD_DRC_MASK=1 */;
+ input wire CLKI;
+ output wire CLKOP;
+
+ wire REFCLK;
+ wire LOCK;
+ wire CLKOP_t;
+ wire scuba_vhi;
+ wire scuba_vlo;
+
+ VHI scuba_vhi_inst (.Z(scuba_vhi));
+
+ VLO scuba_vlo_inst (.Z(scuba_vlo));
+
+ defparam PLLInst_0.PLLRST_ENA = "DISABLED" ;
+ defparam PLLInst_0.INTFB_WAKE = "DISABLED" ;
+ defparam PLLInst_0.STDBY_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.DPHASE_SOURCE = "DISABLED" ;
+ defparam PLLInst_0.CLKOS3_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS3_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS2_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOS_CPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_FPHASE = 0 ;
+ defparam PLLInst_0.CLKOP_CPHASE = 2 ;
+ defparam PLLInst_0.PLL_LOCK_MODE = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOS_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.CLKOP_TRIM_DELAY = 0 ;
+ defparam PLLInst_0.CLKOP_TRIM_POL = "FALLING" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXD = "DIVD" ;
+ defparam PLLInst_0.CLKOS3_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXC = "DIVC" ;
+ defparam PLLInst_0.CLKOS2_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXB = "DIVB" ;
+ defparam PLLInst_0.CLKOS_ENABLE = "DISABLED" ;
+ defparam PLLInst_0.OUTDIVIDER_MUXA = "DIVA" ;
+ defparam PLLInst_0.CLKOP_ENABLE = "ENABLED" ;
+ defparam PLLInst_0.CLKOS3_DIV = 1 ;
+ defparam PLLInst_0.CLKOS2_DIV = 1 ;
+ defparam PLLInst_0.CLKOS_DIV = 1 ;
+ defparam PLLInst_0.CLKOP_DIV = 3 ;
+ defparam PLLInst_0.CLKFB_DIV = 8 ;
+ defparam PLLInst_0.CLKI_DIV = 1 ;
+ defparam PLLInst_0.FEEDBK_PATH = "CLKOP" ;
+ EHXPLLL PLLInst_0 (.CLKI(CLKI), .CLKFB(CLKOP_t), .PHASESEL1(scuba_vlo),
+ .PHASESEL0(scuba_vlo), .PHASEDIR(scuba_vlo), .PHASESTEP(scuba_vlo),
+ .PHASELOADREG(scuba_vlo), .STDBY(scuba_vlo), .PLLWAKESYNC(scuba_vlo),
+ .RST(scuba_vlo), .ENCLKOP(scuba_vlo), .ENCLKOS(scuba_vlo), .ENCLKOS2(scuba_vlo),
+ .ENCLKOS3(scuba_vlo), .CLKOP(CLKOP_t), .CLKOS(), .CLKOS2(), .CLKOS3(),
+ .LOCK(LOCK), .INTLOCK(), .REFCLK(REFCLK), .CLKINTFB())
+ /* synthesis FREQUENCY_PIN_CLKOP="200.000000" */
+ /* synthesis FREQUENCY_PIN_CLKI="25.000000" */
+ /* synthesis ICP_CURRENT="5" */
+ /* synthesis LPF_RESISTOR="16" */;
+
+ assign CLKOP = CLKOP_t;
+
+
+ // exemplar begin
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKOP 200.000000
+ // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKI 25.000000
+ // exemplar attribute PLLInst_0 ICP_CURRENT 5
+ // exemplar attribute PLLInst_0 LPF_RESISTOR 16
+ // exemplar end
+
+endmodule
diff --git a/boards/ulx3s-v2.0-85f-sp/constraints/ulx3s_v17patch.lpf b/boards/ulx3s-v2.0-85f-sp/constraints/ulx3s_v17patch.lpf
new file mode 100644
index 0000000..8e0d34c
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/constraints/ulx3s_v17patch.lpf
@@ -0,0 +1,435 @@
+BLOCK RESETPATHS;
+BLOCK ASYNCPATHS;
+## ULX3S v1.7 patched towards v1.8
+
+# The clock "usb" and "gpdi" sheet
+LOCATE COMP "clk_25mhz" SITE "G2";
+IOBUF PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33;
+FREQUENCY PORT "clk_25mhz" 25 MHZ;
+
+# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash
+SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 SLAVE_SPI_PORT=DISABLE MASTER_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE;
+
+## USBSERIAL FTDI-FPGA serial port "usb" sheet
+LOCATE COMP "ftdi_rxd" SITE "L4"; # FPGA transmits to ftdi
+LOCATE COMP "ftdi_txd" SITE "M1"; # FPGA receives from ftdi
+LOCATE COMP "ftdi_nrts" SITE "M3"; # FPGA receives
+LOCATE COMP "ftdi_ndtr" SITE "N1"; # FPGA receives
+LOCATE COMP "ftdi_txden" SITE "L3"; # FPGA receives
+IOBUF PORT "ftdi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "ftdi_txd" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_nrts" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_ndtr" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_txden" PULLMODE=UP IO_TYPE=LVCMOS33;
+
+## LED indicators "blinkey" and "gpio" sheet
+LOCATE COMP "led[7]" SITE "H3";
+LOCATE COMP "led[6]" SITE "E1";
+LOCATE COMP "led[5]" SITE "E2";
+LOCATE COMP "led[4]" SITE "D1";
+LOCATE COMP "led[3]" SITE "D2";
+LOCATE COMP "led[2]" SITE "C1";
+LOCATE COMP "led[1]" SITE "C2";
+LOCATE COMP "led[0]" SITE "B2";
+IOBUF PORT "led[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Pushbuttons "blinkey", "flash", "power", "gpdi" sheet
+LOCATE COMP "btn[0]" SITE "D6"; # BTN_PWRn (inverted logic)
+LOCATE COMP "btn[1]" SITE "R1"; # FIRE1
+LOCATE COMP "btn[2]" SITE "T1"; # FIRE2
+LOCATE COMP "btn[3]" SITE "W1"; # UP
+LOCATE COMP "btn[4]" SITE "V1"; # DOWN
+LOCATE COMP "btn[5]" SITE "U1"; # LEFT
+LOCATE COMP "btn[6]" SITE "Y2"; # RIGHT
+IOBUF PORT "btn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[4]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[5]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[6]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## DIP switch "blinkey", "gpio" sheet
+LOCATE COMP "sw[0]" SITE "E8"; # SW1
+LOCATE COMP "sw[1]" SITE "D8"; # SW2
+LOCATE COMP "sw[2]" SITE "D7"; # SW3
+LOCATE COMP "sw[3]" SITE "E7"; # SW4
+IOBUF PORT "sw[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI OLED DISPLAY SSD1331 (Color) or SSD1306 (B/W) "blinkey", "usb" sheet
+LOCATE COMP "oled_clk" SITE "P4";
+LOCATE COMP "oled_mosi" SITE "P3";
+LOCATE COMP "oled_dc" SITE "P1";
+LOCATE COMP "oled_resn" SITE "P2";
+LOCATE COMP "oled_csn" SITE "N2";
+IOBUF PORT "oled_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_dc" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_resn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI Flash chip "flash" sheet
+LOCATE COMP "flash_csn" SITE "R2";
+LOCATE COMP "flash_clk" SITE "U3";
+LOCATE COMP "flash_mosi" SITE "W2";
+LOCATE COMP "flash_miso" SITE "V2";
+#LOCATE COMP "flash_csspin" SITE "AJ3";
+#LOCATE COMP "flash_initn" SITE "AG4";
+#LOCATE COMP "flash_done" SITE "AJ4";
+#LOCATE COMP "flash_programn" SITE "AH4";
+#LOCATE COMP "flash_cfg_select[0]" SITE "AM4";
+#LOCATE COMP "flash_cfg_select[1]" SITE "AL4";
+#LOCATE COMP "flash_cfg_select[2]" SITE "AK4";
+IOBUF PORT "flash_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_clk" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_csspin" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_initn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SD card "sdcard", "usb" sheet
+LOCATE COMP "sd_clk" SITE "J1"; # sd_clk WiFi_GPIO14
+LOCATE COMP "sd_cmd" SITE "J3"; # sd_cmd_di (MOSI) WiFi GPIO15
+LOCATE COMP "sd_d[0]" SITE "K2"; # sd_dat0_do (MISO) WiFi GPIO2
+LOCATE COMP "sd_d[1]" SITE "K1"; # sd_dat1_irq WiFi GPIO4
+LOCATE COMP "sd_d[2]" SITE "H2"; # sd_dat2 WiFi_GPIO12
+LOCATE COMP "sd_d[3]" SITE "H1"; # sd_dat3_csn WiFi_GPIO13
+LOCATE COMP "sd_wp" SITE "P5"; # not connected
+LOCATE COMP "sd_cdn" SITE "N5"; # not connected
+IOBUF PORT "sd_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cmd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; # WiFi GPIO12 pulldown bootstrapping requirement
+IOBUF PORT "sd_d[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_wp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## ADC SPI (MAX11123) "analog", "ram" sheet
+LOCATE COMP "adc_csn" SITE "R17";
+LOCATE COMP "adc_mosi" SITE "R16";
+LOCATE COMP "adc_miso" SITE "U16";
+LOCATE COMP "adc_sclk" SITE "P17";
+IOBUF PORT "adc_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_sclk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Audio 4-bit DAC "analog", "gpio" sheet
+# 4-bit mode can drive down to 75 ohm load impedance.
+# Lower impedance leads to IO overload,
+# FPGA will stop working and need reboot.
+# For standard 17 ohm earphones:
+# use bits 2,3 as input (High-Z) and drive only bits 0,1.
+LOCATE COMP "audio_l[3]" SITE "B3"; # JACK TIP (left audio)
+LOCATE COMP "audio_l[2]" SITE "C3";
+LOCATE COMP "audio_l[1]" SITE "D3";
+LOCATE COMP "audio_l[0]" SITE "E4";
+LOCATE COMP "audio_r[3]" SITE "C5"; # JACK RING1 (right audio)
+LOCATE COMP "audio_r[2]" SITE "D5";
+LOCATE COMP "audio_r[1]" SITE "B5";
+LOCATE COMP "audio_r[0]" SITE "A3";
+LOCATE COMP "audio_v[3]" SITE "E5"; # JACK RING2 (video or digital audio)
+LOCATE COMP "audio_v[2]" SITE "F5";
+LOCATE COMP "audio_v[1]" SITE "F2";
+LOCATE COMP "audio_v[0]" SITE "H5";
+IOBUF PORT "audio_l[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## WiFi ESP-32 "wifi", "usb", "flash" sheet
+# other pins are shared with GP/GN, SD card and JTAG
+LOCATE COMP "wifi_en" SITE "F1"; # enable/reset WiFi
+LOCATE COMP "wifi_rxd" SITE "K3"; # FPGA transmits to WiFi
+LOCATE COMP "wifi_txd" SITE "K4"; # FPGA receives from WiFi
+LOCATE COMP "wifi_gpio0" SITE "L2";
+LOCATE COMP "wifi_gpio5" SITE "N4"; # WIFI LED
+LOCATE COMP "wifi_gpio16" SITE "L1";
+LOCATE COMP "wifi_gpio17" SITE "N3";
+# LOCATE COMP "prog_done" SITE "Y3"; # not GPIO, always active
+IOBUF PORT "wifi_en" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_txd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio16" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio17" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+# IOBUF PORT "prog_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## PCB antenna 433 MHz (may be also used for FM) "usb" sheet
+LOCATE COMP "ant_433mhz" SITE "G1";
+IOBUF PORT "ant_433mhz" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Second USB port going directly into FPGA "usb", "ram" sheet
+LOCATE COMP "usb_fpga_dp" SITE "E16";
+LOCATE COMP "usb_fpga_dn" SITE "F16";
+IOBUF PORT "usb_fpga_dp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## JTAG ESP-32 "usb" sheet
+# connected to FT231X and ESP-32
+# commented out because those are dedicated pins, not directly useable as GPIO
+# but could be used by some vendor-specific JTAG bridging (boundary scan) module
+#LOCATE COMP "jtag_tdi" SITE "R5"; # FTDI_nRI FPGA receives
+#LOCATE COMP "jtag_tdo" SITE "V4"; # FTDI_nCTS FPGA transmits
+#LOCATE COMP "jtag_tck" SITE "T5"; # FTDI_nDSR FPGA receives
+#LOCATE COMP "jtag_tms" SITE "U5"; # FTDI_nDCD FPGA receives
+#IOBUF PORT "jtag_tdi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tdo" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tck" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tms" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SDRAM "ram" sheet
+LOCATE COMP "sdram_clk" SITE "F19";
+LOCATE COMP "sdram_cke" SITE "F20";
+LOCATE COMP "sdram_csn" SITE "P20";
+LOCATE COMP "sdram_wen" SITE "T20";
+LOCATE COMP "sdram_rasn" SITE "R20";
+LOCATE COMP "sdram_casn" SITE "T19";
+LOCATE COMP "sdram_a[0]" SITE "M20";
+LOCATE COMP "sdram_a[1]" SITE "M19";
+LOCATE COMP "sdram_a[2]" SITE "L20";
+LOCATE COMP "sdram_a[3]" SITE "L19";
+LOCATE COMP "sdram_a[4]" SITE "K20";
+LOCATE COMP "sdram_a[5]" SITE "K19";
+LOCATE COMP "sdram_a[6]" SITE "K18";
+LOCATE COMP "sdram_a[7]" SITE "J20";
+LOCATE COMP "sdram_a[8]" SITE "J19";
+LOCATE COMP "sdram_a[9]" SITE "H20";
+LOCATE COMP "sdram_a[10]" SITE "N19";
+LOCATE COMP "sdram_a[11]" SITE "G20";
+LOCATE COMP "sdram_a[12]" SITE "G19";
+LOCATE COMP "sdram_ba[0]" SITE "P19";
+LOCATE COMP "sdram_ba[1]" SITE "N20";
+LOCATE COMP "sdram_dqm[0]" SITE "U19";
+LOCATE COMP "sdram_dqm[1]" SITE "E20";
+LOCATE COMP "sdram_d[0]" SITE "J16";
+LOCATE COMP "sdram_d[1]" SITE "L18";
+LOCATE COMP "sdram_d[2]" SITE "M18";
+LOCATE COMP "sdram_d[3]" SITE "N18";
+LOCATE COMP "sdram_d[4]" SITE "P18";
+LOCATE COMP "sdram_d[5]" SITE "T18";
+LOCATE COMP "sdram_d[6]" SITE "T17";
+LOCATE COMP "sdram_d[7]" SITE "U20";
+LOCATE COMP "sdram_d[8]" SITE "E19";
+LOCATE COMP "sdram_d[9]" SITE "D20";
+LOCATE COMP "sdram_d[10]" SITE "D19";
+LOCATE COMP "sdram_d[11]" SITE "C20";
+LOCATE COMP "sdram_d[12]" SITE "E18";
+LOCATE COMP "sdram_d[13]" SITE "F18";
+LOCATE COMP "sdram_d[14]" SITE "J18";
+LOCATE COMP "sdram_d[15]" SITE "J17";
+IOBUF PORT "sdram_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_cke" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_wen" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_rasn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_casn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[13]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[14]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[15]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPDI differential interface (Video) "gpdi" sheet
+LOCATE COMP "gpdi_dp[0]" SITE "A16"; # Blue +
+LOCATE COMP "gpdi_dn[0]" SITE "B16"; # Blue -
+LOCATE COMP "gpdi_dp[1]" SITE "A14"; # Green +
+LOCATE COMP "gpdi_dn[1]" SITE "C14"; # Green -
+LOCATE COMP "gpdi_dp[2]" SITE "A12"; # Red +
+LOCATE COMP "gpdi_dn[2]" SITE "A13"; # Read +
+LOCATE COMP "gpdi_ethp" SITE "A19"; # Ethernet +
+LOCATE COMP "gpdi_ethn" SITE "B20"; # Ethernet -
+LOCATE COMP "gpdi_clkp" SITE "A17"; # Clock +
+LOCATE COMP "gpdi_clkn" SITE "B18"; # Clock -
+LOCATE COMP "gpdi_cec" SITE "A18";
+LOCATE COMP "gpdi_sda" SITE "B19"; # I2C shared with RTC
+LOCATE COMP "gpdi_scl" SITE "C12"; # I2C shared with RTC
+IOBUF PORT "gpdi_dp[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_clkp" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_clkn" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethp" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethn" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_cec" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_sda" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_scl" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPIO (default single-ended) "gpio", "ram", "gpdi" sheet
+# Pins enumerated gp[0-27], gn[0-27].
+# With differential mode enabled on Lattice,
+# gp[] (+) are used, gn[] (-) are ignored from design
+# as they handle inverted signal by default.
+# To enable differential, rename LVCMOS33->LVCMOS33D
+LOCATE COMP "gp[0]" SITE "B11"; # J1_5+ GP0
+LOCATE COMP "gn[0]" SITE "C11"; # J1_5- GN0
+LOCATE COMP "gp[1]" SITE "A10"; # J1_7+ GP1
+LOCATE COMP "gn[1]" SITE "A11"; # J1_7- GN1
+LOCATE COMP "gp[2]" SITE "A9"; # J1_9+ GP2
+LOCATE COMP "gn[2]" SITE "B10"; # J1_9- GN2
+LOCATE COMP "gp[3]" SITE "B9"; # J1_11+ GP3
+LOCATE COMP "gn[3]" SITE "C10"; # J1_11- GN3
+LOCATE COMP "gp[4]" SITE "A7"; # J1_13+ GP4
+LOCATE COMP "gn[4]" SITE "A8"; # J1_13- GN4
+LOCATE COMP "gp[5]" SITE "C8"; # J1_15+ GP5
+LOCATE COMP "gn[5]" SITE "B8"; # J1_15- GN5
+LOCATE COMP "gp[6]" SITE "C6"; # J1_17+ GP6
+LOCATE COMP "gn[6]" SITE "C7"; # J1_17- GN6
+IOBUF PORT "gp[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[7]" SITE "A6"; # J1_23+ GP7
+LOCATE COMP "gn[7]" SITE "B6"; # J1_23- GN7
+LOCATE COMP "gp[8]" SITE "A4"; # J1_25+ GP8
+LOCATE COMP "gn[8]" SITE "A5"; # J1_25- GN8
+LOCATE COMP "gp[9]" SITE "A2"; # J1_27+ GP9
+LOCATE COMP "gn[9]" SITE "B1"; # J1_27- GN9
+LOCATE COMP "gp[10]" SITE "C4"; # J1_29+ GP10 WIFI_GPIO27
+LOCATE COMP "gn[10]" SITE "B4"; # J1_29- GN10
+LOCATE COMP "gp[11]" SITE "F4"; # J1_31+ GP11 WIFI_GPIO25
+LOCATE COMP "gn[11]" SITE "E3"; # J1_31- GN11 WIFI_GPIO26
+LOCATE COMP "gp[12]" SITE "G3"; # J1_33+ GP12 WIFI_GPIO32
+LOCATE COMP "gn[12]" SITE "F3"; # J1_33- GN12 WIFI_GPIO33
+LOCATE COMP "gp[13]" SITE "H4"; # J1_35+ GP13 WIFI_GPIO34
+LOCATE COMP "gn[13]" SITE "G5"; # J1_35- GN13 WIFI_GPIO35
+IOBUF PORT "gp[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[14]" SITE "U18"; # J2_5+ GP14
+LOCATE COMP "gn[14]" SITE "U17"; # J2_5- GN14
+LOCATE COMP "gp[15]" SITE "N17"; # J2_7+ GP15
+LOCATE COMP "gn[15]" SITE "P16"; # J2_7- GN15
+LOCATE COMP "gp[16]" SITE "N16"; # J2_9+ GP16
+LOCATE COMP "gn[16]" SITE "M17"; # J2_9- GN16
+LOCATE COMP "gp[17]" SITE "L16"; # J2_11+ GP17
+LOCATE COMP "gn[17]" SITE "L17"; # J2_11- GN17
+LOCATE COMP "gp[18]" SITE "H18"; # J2_13+ GP18
+LOCATE COMP "gn[18]" SITE "H17"; # J2_13- GN18
+LOCATE COMP "gp[19]" SITE "F17"; # J2_15+ GP19
+LOCATE COMP "gn[19]" SITE "G18"; # J2_15- GN19
+LOCATE COMP "gp[20]" SITE "D18"; # J2_17+ GP20
+LOCATE COMP "gn[20]" SITE "E17"; # J2_17- GN20
+IOBUF PORT "gp[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[21]" SITE "C18"; # J2_23+ GP21
+LOCATE COMP "gn[21]" SITE "D17"; # J2_23- GN21
+LOCATE COMP "gp[22]" SITE "D15"; # J2_25+ GP22
+LOCATE COMP "gn[22]" SITE "E15"; # J2_25- GN22
+LOCATE COMP "gp[23]" SITE "B17"; # J2_27+ GP23
+LOCATE COMP "gn[23]" SITE "C17"; # J2_27- GN23
+LOCATE COMP "gp[24]" SITE "C16"; # J2_29+ GP24
+LOCATE COMP "gn[24]" SITE "D16"; # J2_29- GN24
+LOCATE COMP "gp[25]" SITE "B15"; # J2_31+ GP25
+LOCATE COMP "gn[25]" SITE "C15"; # J2_31- GN25
+LOCATE COMP "gp[26]" SITE "B13"; # J2_33+ GP26
+LOCATE COMP "gn[26]" SITE "C13"; # J2_33- GN26
+LOCATE COMP "gp[27]" SITE "D13"; # J2_35+ GP27
+LOCATE COMP "gn[27]" SITE "E13"; # J2_35- GN27
+IOBUF PORT "gp[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SHUTDOWN "power", "ram" sheet (connected from PCB v1.7.5)
+# on PCB v1.7 shutdown is not connected to FPGA
+LOCATE COMP "shutdown" SITE "G16"; # FPGA receives
+IOBUF PORT "shutdown" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
diff --git a/boards/ulx3s-v2.0-85f-sp/constraints/ulx3s_v20.lpf b/boards/ulx3s-v2.0-85f-sp/constraints/ulx3s_v20.lpf
new file mode 100644
index 0000000..e04bc4f
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/constraints/ulx3s_v20.lpf
@@ -0,0 +1,452 @@
+BLOCK RESETPATHS;
+BLOCK ASYNCPATHS;
+## ULX3S v2.0 and v2.1
+
+# The clock "usb" and "gpdi" sheet
+LOCATE COMP "clk_25mhz" SITE "G2";
+IOBUF PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33;
+FREQUENCY PORT "clk_25mhz" 25 MHZ;
+
+# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash
+SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 MASTER_SPI_PORT=DISABLE SLAVE_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE;
+
+## USBSERIAL FTDI-FPGA serial port "usb" sheet
+LOCATE COMP "ftdi_rxd" SITE "L4"; # FPGA transmits to ftdi
+LOCATE COMP "ftdi_txd" SITE "M1"; # FPGA receives from ftdi
+LOCATE COMP "ftdi_nrts" SITE "M3"; # FPGA receives
+LOCATE COMP "ftdi_ndtr" SITE "N1"; # FPGA receives
+LOCATE COMP "ftdi_txden" SITE "L3"; # FPGA receives
+IOBUF PORT "ftdi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "ftdi_txd" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_nrts" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_ndtr" PULLMODE=UP IO_TYPE=LVCMOS33;
+IOBUF PORT "ftdi_txden" PULLMODE=UP IO_TYPE=LVCMOS33;
+
+## LED indicators "blinkey" and "gpio" sheet
+LOCATE COMP "led[7]" SITE "H3";
+LOCATE COMP "led[6]" SITE "E1";
+LOCATE COMP "led[5]" SITE "E2";
+LOCATE COMP "led[4]" SITE "D1";
+LOCATE COMP "led[3]" SITE "D2";
+LOCATE COMP "led[2]" SITE "C1";
+LOCATE COMP "led[1]" SITE "C2";
+LOCATE COMP "led[0]" SITE "B2";
+IOBUF PORT "led[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "led[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Pushbuttons "blinkey", "flash", "power", "gpdi" sheet
+LOCATE COMP "btn[0]" SITE "D6"; # BTN_PWRn (inverted logic)
+LOCATE COMP "btn[1]" SITE "R1"; # FIRE1
+LOCATE COMP "btn[2]" SITE "T1"; # FIRE2
+LOCATE COMP "btn[3]" SITE "R18"; # UP W1->R18
+LOCATE COMP "btn[4]" SITE "V1"; # DOWN
+LOCATE COMP "btn[5]" SITE "U1"; # LEFT
+LOCATE COMP "btn[6]" SITE "H16"; # RIGHT Y2->H16
+IOBUF PORT "btn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[4]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[5]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "btn[6]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## DIP switch "blinkey", "gpio" sheet
+LOCATE COMP "sw[0]" SITE "E8"; # SW1
+LOCATE COMP "sw[1]" SITE "D8"; # SW2
+LOCATE COMP "sw[2]" SITE "D7"; # SW3
+LOCATE COMP "sw[3]" SITE "E7"; # SW4
+IOBUF PORT "sw[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sw[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI OLED DISPLAY SSD1331 (Color) or SSD1306 (B/W) "blinkey", "usb" sheet
+LOCATE COMP "oled_clk" SITE "P4";
+LOCATE COMP "oled_mosi" SITE "P3";
+LOCATE COMP "oled_dc" SITE "P1";
+LOCATE COMP "oled_resn" SITE "P2";
+LOCATE COMP "oled_csn" SITE "N2";
+IOBUF PORT "oled_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_dc" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_resn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "oled_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SPI Flash chip "flash" sheet
+LOCATE COMP "flash_csn" SITE "R2";
+LOCATE COMP "flash_mosi" SITE "W2";
+LOCATE COMP "flash_miso" SITE "V2";
+LOCATE COMP "flash_holdn" SITE "W1";
+LOCATE COMP "flash_wpn" SITE "Y2";
+#LOCATE COMP "flash_clk" SITE "U3";
+#LOCATE COMP "flash_csspin" SITE "AJ3";
+#LOCATE COMP "flash_initn" SITE "AG4";
+#LOCATE COMP "flash_done" SITE "AJ4";
+#LOCATE COMP "flash_programn" SITE "AH4";
+#LOCATE COMP "flash_cfg_select[0]" SITE "AM4";
+#LOCATE COMP "flash_cfg_select[1]" SITE "AL4";
+#LOCATE COMP "flash_cfg_select[2]" SITE "AK4";
+IOBUF PORT "flash_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_holdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "flash_wpn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_clk" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_csspin" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_initn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "flash_cfg_select[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SD card "sdcard", "usb" sheet
+LOCATE COMP "sd_clk" SITE "H2"; # sd_clk WiFi_GPIO14
+LOCATE COMP "sd_cmd" SITE "J1"; # sd_cmd_di (MOSI) WiFi GPIO15
+LOCATE COMP "sd_d[0]" SITE "J3"; # sd_dat0_do (MISO) WiFi GPIO2
+LOCATE COMP "sd_d[1]" SITE "H1"; # sd_dat1_irq WiFi GPIO4
+LOCATE COMP "sd_d[2]" SITE "K1"; # sd_dat2 WiFi_GPIO12
+LOCATE COMP "sd_d[3]" SITE "K2"; # sd_dat3_csn WiFi_GPIO13
+LOCATE COMP "sd_wp" SITE "P5"; # not connected
+LOCATE COMP "sd_cdn" SITE "N5"; # not connected
+IOBUF PORT "sd_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cmd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; # WiFi GPIO12 pulldown bootstrapping requirement
+IOBUF PORT "sd_d[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_wp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sd_cdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## ADC SPI (MAX11123) "analog", "ram" sheet
+LOCATE COMP "adc_csn" SITE "R17";
+LOCATE COMP "adc_mosi" SITE "R16";
+LOCATE COMP "adc_miso" SITE "U16";
+LOCATE COMP "adc_sclk" SITE "P17";
+IOBUF PORT "adc_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "adc_sclk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Audio 4-bit DAC "analog", "gpio" sheet
+# 4-bit mode can drive down to 75 ohm load impedance.
+# Lower impedance leads to IO overload,
+# FPGA will stop working and need reboot.
+# For standard 17 ohm earphones:
+# use bits 2,3 as input (High-Z) and drive only bits 0,1.
+LOCATE COMP "audio_l[3]" SITE "B3"; # JACK TIP (left audio)
+LOCATE COMP "audio_l[2]" SITE "C3";
+LOCATE COMP "audio_l[1]" SITE "D3";
+LOCATE COMP "audio_l[0]" SITE "E4";
+LOCATE COMP "audio_r[3]" SITE "C5"; # JACK RING1 (right audio)
+LOCATE COMP "audio_r[2]" SITE "D5";
+LOCATE COMP "audio_r[1]" SITE "B5";
+LOCATE COMP "audio_r[0]" SITE "A3";
+LOCATE COMP "audio_v[3]" SITE "E5"; # JACK RING2 (video or digital audio)
+LOCATE COMP "audio_v[2]" SITE "F5";
+LOCATE COMP "audio_v[1]" SITE "F2";
+LOCATE COMP "audio_v[0]" SITE "H5";
+IOBUF PORT "audio_l[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_l[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_r[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "audio_v[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## WiFi ESP-32 "wifi", "usb", "flash" sheet
+# other pins are shared with GP/GN, SD card and JTAG
+LOCATE COMP "wifi_en" SITE "F1"; # enable/reset WiFi
+LOCATE COMP "wifi_rxd" SITE "K3"; # FPGA transmits to WiFi
+LOCATE COMP "wifi_txd" SITE "K4"; # FPGA receives from WiFi
+LOCATE COMP "wifi_gpio0" SITE "L2";
+LOCATE COMP "wifi_gpio5" SITE "N4"; # WIFI LED
+LOCATE COMP "wifi_gpio16" SITE "L1"; # Serial1 RX
+LOCATE COMP "wifi_gpio17" SITE "N3"; # Serial1 TX
+# LOCATE COMP "prog_done" SITE "Y3"; # not GPIO, always active
+IOBUF PORT "wifi_en" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_txd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio16" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "wifi_gpio17" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+# IOBUF PORT "prog_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## PCB antenna 433 MHz (may be also used for FM) "usb" sheet
+LOCATE COMP "ant_433mhz" SITE "G1";
+IOBUF PORT "ant_433mhz" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+## Second USB port "US2" going directly into FPGA "usb", "ram" sheet
+LOCATE COMP "usb_fpga_dp" SITE "E16"; # single ended or differential input only
+LOCATE COMP "usb_fpga_dn" SITE "F16";
+IOBUF PORT "usb_fpga_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+LOCATE COMP "usb_fpga_bd_dp" SITE "D15"; # differential bidirectional
+LOCATE COMP "usb_fpga_bd_dn" SITE "E15";
+IOBUF PORT "usb_fpga_bd_dp" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "usb_fpga_bd_dn" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=4;
+LOCATE COMP "usb_fpga_pu_dp" SITE "B12"; # pull up/down control
+LOCATE COMP "usb_fpga_pu_dn" SITE "C12";
+IOBUF PORT "usb_fpga_pu_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+IOBUF PORT "usb_fpga_pu_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
+
+## JTAG ESP-32 "usb" sheet
+# connected to FT231X and ESP-32
+# commented out because those are dedicated pins, not directly useable as GPIO
+# but could be used by some vendor-specific JTAG bridging (boundary scan) module
+#LOCATE COMP "jtag_tdi" SITE "R5"; # FTDI_nRI FPGA receives
+#LOCATE COMP "jtag_tdo" SITE "V4"; # FTDI_nCTS FPGA transmits
+#LOCATE COMP "jtag_tck" SITE "T5"; # FTDI_nDSR FPGA receives
+#LOCATE COMP "jtag_tms" SITE "U5"; # FTDI_nDCD FPGA receives
+#IOBUF PORT "jtag_tdi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tdo" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tck" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+#IOBUF PORT "jtag_tms" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SDRAM "ram" sheet
+LOCATE COMP "sdram_clk" SITE "F19";
+LOCATE COMP "sdram_cke" SITE "F20";
+LOCATE COMP "sdram_csn" SITE "P20";
+LOCATE COMP "sdram_wen" SITE "T20";
+LOCATE COMP "sdram_rasn" SITE "R20";
+LOCATE COMP "sdram_casn" SITE "T19";
+LOCATE COMP "sdram_a[0]" SITE "M20";
+LOCATE COMP "sdram_a[1]" SITE "M19";
+LOCATE COMP "sdram_a[2]" SITE "L20";
+LOCATE COMP "sdram_a[3]" SITE "L19";
+LOCATE COMP "sdram_a[4]" SITE "K20";
+LOCATE COMP "sdram_a[5]" SITE "K19";
+LOCATE COMP "sdram_a[6]" SITE "K18";
+LOCATE COMP "sdram_a[7]" SITE "J20";
+LOCATE COMP "sdram_a[8]" SITE "J19";
+LOCATE COMP "sdram_a[9]" SITE "H20";
+LOCATE COMP "sdram_a[10]" SITE "N19";
+LOCATE COMP "sdram_a[11]" SITE "G20";
+LOCATE COMP "sdram_a[12]" SITE "G19";
+LOCATE COMP "sdram_ba[0]" SITE "P19";
+LOCATE COMP "sdram_ba[1]" SITE "N20";
+LOCATE COMP "sdram_dqm[0]" SITE "U19";
+LOCATE COMP "sdram_dqm[1]" SITE "E20";
+LOCATE COMP "sdram_d[0]" SITE "J16";
+LOCATE COMP "sdram_d[1]" SITE "L18";
+LOCATE COMP "sdram_d[2]" SITE "M18";
+LOCATE COMP "sdram_d[3]" SITE "N18";
+LOCATE COMP "sdram_d[4]" SITE "P18";
+LOCATE COMP "sdram_d[5]" SITE "T18";
+LOCATE COMP "sdram_d[6]" SITE "T17";
+LOCATE COMP "sdram_d[7]" SITE "U20";
+LOCATE COMP "sdram_d[8]" SITE "E19";
+LOCATE COMP "sdram_d[9]" SITE "D20";
+LOCATE COMP "sdram_d[10]" SITE "D19";
+LOCATE COMP "sdram_d[11]" SITE "C20";
+LOCATE COMP "sdram_d[12]" SITE "E18";
+LOCATE COMP "sdram_d[13]" SITE "F18";
+LOCATE COMP "sdram_d[14]" SITE "J18";
+LOCATE COMP "sdram_d[15]" SITE "J17";
+IOBUF PORT "sdram_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_cke" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_wen" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_rasn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_casn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_a[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_ba[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[13]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[14]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "sdram_d[15]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPDI differential interface (Video) "gpdi" sheet
+LOCATE COMP "gpdi_dp[0]" SITE "A16"; # Blue +
+LOCATE COMP "gpdi_dn[0]" SITE "B16"; # Blue -
+LOCATE COMP "gpdi_dp[1]" SITE "A14"; # Green +
+LOCATE COMP "gpdi_dn[1]" SITE "C14"; # Green -
+LOCATE COMP "gpdi_dp[2]" SITE "A12"; # Red +
+LOCATE COMP "gpdi_dn[2]" SITE "A13"; # Red -
+LOCATE COMP "gpdi_dp[3]" SITE "A17"; # Clock +
+LOCATE COMP "gpdi_dn[3]" SITE "B18"; # Clock -
+LOCATE COMP "gpdi_ethp" SITE "A19"; # Ethernet +
+LOCATE COMP "gpdi_ethn" SITE "B20"; # Ethernet -
+LOCATE COMP "gpdi_cec" SITE "A18";
+LOCATE COMP "gpdi_sda" SITE "B19"; # I2C shared with RTC
+LOCATE COMP "gpdi_scl" SITE "E12"; # I2C shared with RTC C12->E12
+IOBUF PORT "gpdi_dp[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[0]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[1]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[2]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dp[3]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_dn[3]" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethp" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_ethn" IO_TYPE=LVCMOS33D DRIVE=4;
+IOBUF PORT "gpdi_cec" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_sda" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gpdi_scl" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+# GPIO (default single-ended) "gpio", "ram", "gpdi" sheet
+# Pins enumerated gp[0-27], gn[0-27].
+# With differential mode enabled on Lattice,
+# gp[] (+) are used, gn[] (-) are ignored from design
+# as they handle inverted signal by default.
+# To enable differential, rename LVCMOS33->LVCMOS33D
+LOCATE COMP "gp[0]" SITE "B11"; # J1_5+ GP0
+LOCATE COMP "gn[0]" SITE "C11"; # J1_5- GN0
+LOCATE COMP "gp[1]" SITE "A10"; # J1_7+ GP1
+LOCATE COMP "gn[1]" SITE "A11"; # J1_7- GN1
+LOCATE COMP "gp[2]" SITE "A9"; # J1_9+ GP2
+LOCATE COMP "gn[2]" SITE "B10"; # J1_9- GN2
+LOCATE COMP "gp[3]" SITE "B9"; # J1_11+ GP3
+LOCATE COMP "gn[3]" SITE "C10"; # J1_11- GN3
+LOCATE COMP "gp[4]" SITE "A7"; # J1_13+ GP4
+LOCATE COMP "gn[4]" SITE "A8"; # J1_13- GN4
+LOCATE COMP "gp[5]" SITE "C8"; # J1_15+ GP5
+LOCATE COMP "gn[5]" SITE "B8"; # J1_15- GN5
+LOCATE COMP "gp[6]" SITE "C6"; # J1_17+ GP6
+LOCATE COMP "gn[6]" SITE "C7"; # J1_17- GN6
+IOBUF PORT "gp[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[7]" SITE "A6"; # J1_23+ GP7
+LOCATE COMP "gn[7]" SITE "B6"; # J1_23- GN7
+LOCATE COMP "gp[8]" SITE "A4"; # J1_25+ GP8
+LOCATE COMP "gn[8]" SITE "A5"; # J1_25- GN8
+LOCATE COMP "gp[9]" SITE "A2"; # J1_27+ GP9
+LOCATE COMP "gn[9]" SITE "B1"; # J1_27- GN9
+LOCATE COMP "gp[10]" SITE "C4"; # J1_29+ GP10 WIFI_GPIO27
+LOCATE COMP "gn[10]" SITE "B4"; # J1_29- GN10
+LOCATE COMP "gp[11]" SITE "F4"; # J1_31+ GP11 WIFI_GPIO25
+LOCATE COMP "gn[11]" SITE "E3"; # J1_31- GN11 WIFI_GPIO26
+LOCATE COMP "gp[12]" SITE "G3"; # J1_33+ GP12 WIFI_GPIO32
+LOCATE COMP "gn[12]" SITE "F3"; # J1_33- GN12 WIFI_GPIO33
+LOCATE COMP "gp[13]" SITE "H4"; # J1_35+ GP13 WIFI_GPIO34
+LOCATE COMP "gn[13]" SITE "G5"; # J1_35- GN13 WIFI_GPIO35
+IOBUF PORT "gp[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[14]" SITE "U18"; # J2_5+ GP14
+LOCATE COMP "gn[14]" SITE "U17"; # J2_5- GN14
+LOCATE COMP "gp[15]" SITE "N17"; # J2_7+ GP15
+LOCATE COMP "gn[15]" SITE "P16"; # J2_7- GN15
+LOCATE COMP "gp[16]" SITE "N16"; # J2_9+ GP16
+LOCATE COMP "gn[16]" SITE "M17"; # J2_9- GN16
+LOCATE COMP "gp[17]" SITE "L16"; # J2_11+ GP17
+LOCATE COMP "gn[17]" SITE "L17"; # J2_11- GN17
+LOCATE COMP "gp[18]" SITE "H18"; # J2_13+ GP18
+LOCATE COMP "gn[18]" SITE "H17"; # J2_13- GN18
+LOCATE COMP "gp[19]" SITE "F17"; # J2_15+ GP19
+LOCATE COMP "gn[19]" SITE "G18"; # J2_15- GN19
+LOCATE COMP "gp[20]" SITE "D18"; # J2_17+ GP20
+LOCATE COMP "gn[20]" SITE "E17"; # J2_17- GN20
+IOBUF PORT "gp[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "gp[21]" SITE "C18"; # J2_23+ GP21
+LOCATE COMP "gn[21]" SITE "D17"; # J2_23- GN21
+LOCATE COMP "gp[22]" SITE "B15"; # J2_25+ GP22 D15->B15
+LOCATE COMP "gn[22]" SITE "C15"; # J2_25- GN22 E15->C15
+LOCATE COMP "gp[23]" SITE "B17"; # J2_27+ GP23
+LOCATE COMP "gn[23]" SITE "C17"; # J2_27- GN23
+LOCATE COMP "gp[24]" SITE "C16"; # J2_29+ GP24
+LOCATE COMP "gn[24]" SITE "D16"; # J2_29- GN24
+LOCATE COMP "gp[25]" SITE "D14"; # J2_31+ GP25 B15->D14
+LOCATE COMP "gn[25]" SITE "E14"; # J2_31- GN25 C15->E14
+LOCATE COMP "gp[26]" SITE "B13"; # J2_33+ GP26
+LOCATE COMP "gn[26]" SITE "C13"; # J2_33- GN26
+LOCATE COMP "gp[27]" SITE "D13"; # J2_35+ GP27
+LOCATE COMP "gn[27]" SITE "E13"; # J2_35- GN27
+IOBUF PORT "gp[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gp[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+IOBUF PORT "gn[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## PROGRAMN (reload bitstream from FLASH, exit from bootloader)
+# PCB v2.0.5 and higher
+LOCATE COMP "user_programn" SITE "M4";
+IOBUF PORT "user_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
+
+## SHUTDOWN "power", "ram" sheet (connected from PCB v1.7.5)
+# on PCB v1.7 shutdown is not connected to FPGA
+LOCATE COMP "shutdown" SITE "G16"; # FPGA receives
+IOBUF PORT "shutdown" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
diff --git a/boards/ulx3s-v2.0-85f-sp/ecp5-85f.ocd b/boards/ulx3s-v2.0-85f-sp/ecp5-85f.ocd
new file mode 100644
index 0000000..370b066
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/ecp5-85f.ocd
@@ -0,0 +1,16 @@
+# ecp5-XXf.cfg
+# OpenOCD commands
+
+telnet_port 4444
+gdb_port 3333
+
+# JTAG TAPs
+#jtag newtap lfe5u12 tap -expected-id 0x21111043 -irlen 8 -irmask 0xFF -ircapture 0x5
+#jtag newtap lfe5u25 tap -expected-id 0x41111043 -irlen 8 -irmask 0xFF -ircapture 0x5
+#jtag newtap lfe5u45 tap -expected-id 0x41112043 -irlen 8 -irmask 0xFF -ircapture 0x5
+jtag newtap lfe5u85 tap -expected-id 0x41113043 -irlen 8 -irmask 0xFF -ircapture 0x5
+
+init
+scan_chain
+svf -tap lfe5u85.tap -quiet -progress project/project_project_sram.svf
+shutdown
diff --git a/boards/ulx3s-v2.0-85f-sp/ft2232-fpu1.ocd b/boards/ulx3s-v2.0-85f-sp/ft2232-fpu1.ocd
new file mode 100644
index 0000000..6c41311
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/ft2232-fpu1.ocd
@@ -0,0 +1,9 @@
+#
+# PLDkit FPU1 JTAG Programmer
+#
+
+interface ftdi
+ftdi_device_desc "FPU1 JTAG Programmer"
+ftdi_vid_pid 0x0403 0x6010
+ftdi_layout_init 0x3088 0x1f8b
+adapter_khz 25000
diff --git a/boards/ulx3s-v2.0-85f-sp/ft231x.ocd b/boards/ulx3s-v2.0-85f-sp/ft231x.ocd
new file mode 100644
index 0000000..f2dee26
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/ft231x.ocd
@@ -0,0 +1,15 @@
+#
+# openocd_ft232r patched for custom jtag nums and buffer_size
+#
+
+interface ft232r
+ft232r_vid_pid 0x0403 0x6015
+# ft232r_serial_desc 12345678
+ft232r_tck_num 5
+ft232r_tms_num 6
+ft232r_tdi_num 7
+ft232r_tdo_num 3
+ft232r_trst_num 2
+ft232r_srst_num 4
+ft232r_buffer_size 16384
+adapter_khz 300
diff --git a/boards/ulx3s-v2.0-85f-sp/initialize/boardmeta4MB.bin b/boards/ulx3s-v2.0-85f-sp/initialize/boardmeta4MB.bin
new file mode 100644
index 0000000..7a525c7
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/initialize/boardmeta4MB.bin
@@ -0,0 +1,119 @@
+{
+ "boardmeta":
+ {
+ "name": "ULX3S",
+ "fpga": "LFE5U-45F-6BG381C",
+ "hver": "1.7",
+ "uuid": "00000000-0000-0000-0000-000000000000",
+ "serial": 12345
+ },
+ "bootmeta":
+ {
+ "bootloader": "TinyFPGA USB Bootloader",
+ "bver": "2.0.0",
+ "update": "https://github.com/emard/TinyFPGA-Bootloader",
+ "addrmap":
+ {
+ "bootloader": "0x000000-0x0FFFFF",
+ "golden": "0x100000-0x1FFFFF",
+ "userimage": "0x200000-0x2FFFFF",
+ "userdata": "0x300000-0x3FBFFF"
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-v2.0-85f-sp/initialize/boardmeta8MB.bin b/boards/ulx3s-v2.0-85f-sp/initialize/boardmeta8MB.bin
new file mode 100644
index 0000000..89be03c
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/initialize/boardmeta8MB.bin
@@ -0,0 +1,58 @@
+{
+ "boardmeta":
+ {
+ "name": "ULX3S",
+ "fpga": "LFE5U-45F-6BG381C",
+ "hver": "1.7",
+ "uuid": "00000000-0000-0000-0000-000000000000",
+ "serial": 12345
+ },
+ "bootmeta":
+ {
+ "bootloader": "TinyFPGA USB Bootloader",
+ "bver": "2.0.0",
+ "update": "https://github.com/emard/TinyFPGA-Bootloader",
+ "addrmap":
+ {
+ "bootloader": "0x000000-0x0FFFFF",
+ "golden": "0x100000-0x1FFFFF",
+ "userimage": "0x200000-0x3FFFFF",
+ "userdata": "0x500000-0x7FBFFF"
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/boards/ulx3s-v2.0-85f-sp/initialize/initialize4MB.sh b/boards/ulx3s-v2.0-85f-sp/initialize/initialize4MB.sh
new file mode 100755
index 0000000..3d67d93
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/initialize/initialize4MB.sh
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+
+# Initializer for ECP5 dual boot.
+
+# first half of the FLASH is for user bitstram
+# bootloader bitstream starts at second half of the FLASH
+# board metadata at last 0x1000 bytes
+# Jump command at last 0x100 bytes
+
+# flash size: 16 Mbit = 2 MB = 0x200000
+# flash size: 32 Mbit = 4 MB = 0x400000
+# flash size: 64 Mbit = 8 MB = 0x800000
+# flash size: 128 Mbit = 16 MB = 0x1000000
+
+bootloader_image_address=$(printf "%d" 0x000000) # 0
+golden_image_address=$(printf "%d" 0x100000) # 0x100000 (1MB) (backup of bootloader)
+board_meta_address=$(printf "%d" 0x3FF000) # flash size - 0x1000
+jump_command_address=$(printf "%d" 0x3FFF00) # flash size - 0x100
+
+# primary image must be generated by diamond deployment tool (ddtcmd)
+# simply overwriting bootloader image will not have multiboot capability
+#tinyprog --pyserial --no-boot -a $bootloader_image_address -u ../../boards/ulx3s-v1.7-45f/tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $golden_image_address -u ../tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $(printf "%d" $board_meta_address) -u boardmeta4MB.bin
+./jump.py $golden_image_address > jump.bin
+tinyprog --pyserial --no-boot -a $(printf "%d" $jump_command_address) -u jump.bin
+# hexdump -C jump.bin
+# check that's board is recognized by tingprog
+tinyprog --pyserial -l
+#tinyprog -m
diff --git a/boards/ulx3s-v2.0-85f-sp/initialize/initialize8MB.sh b/boards/ulx3s-v2.0-85f-sp/initialize/initialize8MB.sh
new file mode 100755
index 0000000..b127f53
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/initialize/initialize8MB.sh
@@ -0,0 +1,31 @@
+#!/bin/sh -e
+
+# Initializer for ECP5 dual boot.
+
+# first half of the FLASH is for user bitstram
+# bootloader bitstream starts at second half of the FLASH
+# board metadata at last 0x1000 bytes
+# Jump command at last 0x100 bytes
+
+# flash size: 8 Mbit = 1 MB = 0x100000
+# flash size: 16 Mbit = 2 MB = 0x200000
+# flash size: 32 Mbit = 4 MB = 0x400000
+# flash size: 64 Mbit = 8 MB = 0x800000
+# flash size: 128 Mbit = 16 MB = 0x1000000
+
+bootloader_image_address=$(printf "%d" 0x000000) # 0
+golden_image_address=$(printf "%d" 0x100000) # 0x100000 (1MB) (backup of bootloader)
+board_meta_address=$(printf "%d" 0x7FF000) # flash size - 0x1000 (-4KB)
+jump_command_address=$(printf "%d" 0x7FFF00) # flash size - 0x100 (-256)
+
+# primary image must be generated by diamond deployment tool (ddtcmd)
+# simply overwriting bootloader image will not have multiboot capability
+#tinyprog --pyserial --no-boot -a $bootloader_image_address -u ../../boards/ulx3s-v1.7-45f/tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $golden_image_address -u ../tinyfpga_45k.bit
+tinyprog --pyserial --no-boot -a $(printf "%d" $board_meta_address) -u boardmeta8MB.bin
+./jump.py $golden_image_address > jump.bin
+tinyprog --pyserial --no-boot -a $(printf "%d" $jump_command_address) -u jump.bin
+# hexdump -C jump.bin
+# check that's board is recognized by tingprog
+tinyprog --pyserial -l
+#tinyprog -m
diff --git a/boards/ulx3s-v2.0-85f-sp/initialize/jump.bin b/boards/ulx3s-v2.0-85f-sp/initialize/jump.bin
new file mode 100644
index 0000000..d39691f
Binary files /dev/null and b/boards/ulx3s-v2.0-85f-sp/initialize/jump.bin differ
diff --git a/boards/ulx3s-v2.0-85f-sp/initialize/jump.py b/boards/ulx3s-v2.0-85f-sp/initialize/jump.py
new file mode 100755
index 0000000..b1ff948
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/initialize/jump.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+
+# Lattice ECP5 jump command generator
+# TN1216 p.23 describes the jump command syntax which does not work.
+# The syntax has been fixed by looking at dual boot intel hex file
+# generated by diamond, this actually works.
+
+import struct
+import sys
+
+# write output of this funtion at FLASH address:
+# jump_command_address = 0x3FFF00 = 4194048
+
+# write "golden" bitstream at FLASH address:
+golden_image_address = 0x140000
+golden_image_address = int(sys.argv[1])
+
+# normally both 0
+reverse_bytes = 0
+reverse_bits = 0
+
+# to compare with intel HEX file generated by diamond:
+# (not for normal use)
+# reverse_bytes = 1
+# reverse_bits = 1
+# ./jump.py | hexdump -C
+
+def reverse_Bits(n, no_of_bits):
+ result = 0
+ for i in range(no_of_bits):
+ result <<= 1
+ result |= n & 1
+ n >>= 1
+ return result
+
+def uint8(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 8)
+ return struct.pack(">B", n)
+
+def uint16(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 16)
+ if reverse_bytes:
+ return struct.pack("H", n)
+
+def uint24(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 24)
+ if reverse_bytes:
+ return struct.pack("> 8 )
+ else:
+ return struct.pack(">HB", n >> 8, n & 0xFF )
+
+def uint32(n):
+ if reverse_bits:
+ n = reverse_Bits(n, 32)
+ if reverse_bytes:
+ return struct.pack("L", n)
+
+packet = b''
+# Frame (START) 18 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint16(0xFFFF) # 2 dummy bytes (diamond generates this 2 bytes more)
+# Preamble
+packet += uint16(0xBDB3) # Preamble
+# Frame (Control Register 0) commented out, diamond doesn't output this
+# if uncommented, jump won't work:
+#packet += uint8(0xC4) # Write control register 0 command
+#packet += uint24(0) # 24-bit Command Information
+#packet += uint32(0) # Control Register 0 data
+# This is generated by diamond:
+packet += uint32(0xFFFFFFFF) # I don't know what it does but it works
+# Framme (Jump Command)
+#packet += uint8(0xFE) # Jump command Wrong noted in TN1216
+packet += uint8(0x7E) # Jump command generated by diamond
+packet += uint24(0) # 24-bit Command Information
+packet += uint8(0x03) # SPI Flash Read opcode (0x03 = regular read, 0x0B = fast read)
+packet += uint24(golden_image_address) # 24-bit SPI Flash Sector X address
+# Frame (END) 18 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint32(0xFFFFFFFF) # 4 dummy bytes
+packet += uint16(0xFFFF) # 2 dummy bytes (diamond generates this 2 bytes more)
+
+sys.stdout.write(packet)
+# print([elem.encode("hex") for elem in packet])
diff --git a/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k.bit b/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k.bit
new file mode 120000
index 0000000..59e9556
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k.bit
@@ -0,0 +1 @@
+project/project_project.bit
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_multiboot_flash_is25lp032d.svf b/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_multiboot_flash_is25lp032d.svf
new file mode 120000
index 0000000..a01da25
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_multiboot_flash_is25lp032d.svf
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_is25lp032d.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_multiboot_flash_is25lp032d.vme b/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_multiboot_flash_is25lp032d.vme
new file mode 120000
index 0000000..7d99dc6
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_multiboot_flash_is25lp032d.vme
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_is25lp032d.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_multiboot_flash_is25lp128f.svf b/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_multiboot_flash_is25lp128f.svf
new file mode 120000
index 0000000..1b8f717
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_multiboot_flash_is25lp128f.svf
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_is25lp128f.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_multiboot_flash_is25lp128f.vme b/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_multiboot_flash_is25lp128f.vme
new file mode 120000
index 0000000..c736cfa
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_multiboot_flash_is25lp128f.vme
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_is25lp128f.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_multiboot_flash_s25fl164k.svf b/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_multiboot_flash_s25fl164k.svf
new file mode 120000
index 0000000..7232663
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_multiboot_flash_s25fl164k.svf
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_s25fl164k.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_multiboot_flash_s25fl164k.vme b/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_multiboot_flash_s25fl164k.vme
new file mode 120000
index 0000000..cadb80a
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_multiboot_flash_s25fl164k.vme
@@ -0,0 +1 @@
+project/project_project_multiboot_flash_s25fl164k.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_sram.svf b/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_sram.svf
new file mode 120000
index 0000000..bb7617d
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_sram.svf
@@ -0,0 +1 @@
+project/project_project_sram.svf
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_sram.vme b/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_sram.vme
new file mode 120000
index 0000000..d098048
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/tinyfpga_85k_sram.vme
@@ -0,0 +1 @@
+project/project_project_sram.vme
\ No newline at end of file
diff --git a/boards/ulx3s-v2.0-85f-sp/top/bootloader_sp_ulx3s.v b/boards/ulx3s-v2.0-85f-sp/top/bootloader_sp_ulx3s.v
new file mode 100644
index 0000000..95e7e0b
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/top/bootloader_sp_ulx3s.v
@@ -0,0 +1,148 @@
+module bootloader_sp_ulx3s (
+ input clk_25mhz,
+
+ inout usb_fpga_dp,
+ inout usb_fpga_dn,
+
+ output usb_fpga_pu_dp,
+ inout user_programn,
+
+ output [7:0] led,
+
+ input flash_miso,
+ output flash_mosi,
+ output flash_csn,
+ output flash_wpn,
+ output flash_holdn,
+
+ input [6:0] btn,
+ output wifi_gpio0
+);
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// generate 48 mhz clock
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ wire clk_200mhz;
+ clk_25M_200M clk_200M_inst (
+ .CLKI(clk_25mhz),
+ .CLKOP(clk_200mhz)
+ );
+
+ wire clk_48mhz;
+ wire clk_ready;
+ clk_200M_48M clk_48M_inst (
+ .CLKI(clk_200mhz),
+ .CLKOP(clk_48mhz),
+ .LOCK(clk_ready)
+ );
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// instantiate tinyfpga bootloader
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ reg [15:0] reset_counter = 0; // counter for debouce and prolong reset
+ wire reset;
+ assign reset = ~reset_counter[15];
+ wire usb_p_tx;
+ wire usb_n_tx;
+ wire usb_p_rx;
+ wire usb_n_rx;
+ wire usb_tx_en;
+ wire pin_led;
+ wire [7:0] debug_led;
+ wire boot;
+ wire S_flash_clk;
+ wire S_flash_csn;
+
+ tinyfpgasp_bootloader tinyfpgasp_bootloader_inst (
+ .clk_48mhz(clk_48mhz),
+ .reset(reset),
+ .usb_p_tx(usb_p_tx),
+ .usb_n_tx(usb_n_tx),
+ .usb_p_rx(usb_p_rx),
+ .usb_n_rx(usb_n_rx),
+ .usb_tx_en(usb_tx_en),
+ .led(pin_led),
+ .debug_led(debug_led),
+ .spi_miso(flash_miso),
+ .spi_mosi(flash_mosi),
+ .spi_sck(S_flash_clk),
+ .spi_cs(S_flash_csn),
+ .boot(boot)
+ );
+
+ assign usb_fpga_dp = reset ? 1'b0 : (usb_tx_en ? usb_p_tx : 1'bz);
+ assign usb_fpga_dn = reset ? 1'b0 : (usb_tx_en ? usb_n_tx : 1'bz);
+ assign usb_p_rx = usb_tx_en ? 1'b1 : usb_fpga_dp;
+ assign usb_n_rx = usb_tx_en ? 1'b0 : usb_fpga_dn;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// Vendor-specific clock output to SPI config flash
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ USRMCLK usrmclk_inst (
+ .USRMCLKI(S_flash_clk),
+ .USRMCLKTS(S_flash_csn)
+ ) /* synthesis syn_noprune=1 */;
+ assign flash_csn = S_flash_csn;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// Debonuce and prolong RESET
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ always @(posedge clk_48mhz)
+ begin
+ if (btn[1] | ~clk_ready)
+ reset_counter <= 0;
+ else
+ if (reset_counter[15] == 0)
+ reset_counter <= reset_counter + 1;
+ end
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// ULX3S board buttons and LEDs
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ assign wifi_gpio0 = btn[0];
+ assign led[0] = pin_led;
+ assign led[1] = ~pin_led;
+ assign led[5] = debug_led;
+ assign led[7] = boot;
+ // assign led[3:0] = {flash_miso, flash_mosi, S_flash_clk, S_flash_csn};
+
+ // PULLUP 1.5k D+
+ assign usb_fpga_pu_dp = 1;
+
+ // set 1 to holdn wpn for use as single bit mode spi
+ assign flash_holdn = 1;
+ assign flash_wpn = 1;
+
+ // delay for BTN0 is required
+ reg [3:0] R_progn = 0;
+ always @(posedge clk_25mhz)
+ if(btn[0])
+ R_progn <= 0;
+ else
+ R_progn <= R_progn + 1;
+
+ // EXIT from BOOTLOADER
+ assign user_programn = ~boot & ~R_progn[3];
+
+endmodule
diff --git a/boards/ulx3s-v2.0-85f-sp/ulx3s_85f_multiboot_flash_is25lp032d.xcf b/boards/ulx3s-v2.0-85f-sp/ulx3s_85f_multiboot_flash_is25lp032d.xcf
new file mode 100644
index 0000000..77fc3a8
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/ulx3s_85f_multiboot_flash_is25lp032d.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-85F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project_multiboot_flash_is25lp032d.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-85F
+ 0x41113043
+ All
+ LFE5U-85F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-85F.msk
+ Bypass
+
+
+
+
+
+ 1
+ Micron
+ SPI Serial Flash
+ SPI-M25P32
+ 0x15
+ 8-pin VDFPN8
+ SPI Flash Erase,Program
+ project/project_project_multiboot_flash_is25lp032d.mcs
+ 0x00000000
+ 0x00400000
+ 32
+ 4194304
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project_multiboot_flash_is25lp032d.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v2.0-85f-sp/ulx3s_85f_multiboot_flash_is25lp128f.xcf b/boards/ulx3s-v2.0-85f-sp/ulx3s_85f_multiboot_flash_is25lp128f.xcf
new file mode 100644
index 0000000..8129a59
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/ulx3s_85f_multiboot_flash_is25lp128f.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Micron
+ ECP5U
+ LFE5U-85F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project_multiboot_flash_is25lp128f.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-85F
+ 0x41113043
+ All
+ LFE5U-85F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-85F.msk
+ Bypass
+
+
+
+
+
+ 1
+ SPANSION
+ SPI Serial Flash
+ SPI-S25FL128S
+ 0x17
+ 8-lead WSON
+ SPI Flash Erase,Program
+ project/project_project_multiboot_flash_is25lp128f.mcs
+ 0x00000000
+ 0x01000000
+ 128
+ 16777216
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project_multiboot_flash_is25lp128f.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v2.0-85f-sp/ulx3s_85f_multiboot_flash_s25fl164k.xcf b/boards/ulx3s-v2.0-85f-sp/ulx3s_85f_multiboot_flash_s25fl164k.xcf
new file mode 100644
index 0000000..cbac0ca
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/ulx3s_85f_multiboot_flash_s25fl164k.xcf
@@ -0,0 +1,104 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-85F
+ All
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project_multiboot_flash_s25fl164k.mcs
+ 12/23/17 00:34:50
+ SPI Flash Erase,Program
+
+
+
+
+ 1
+ Lattice
+ ECP5U
+ LFE5U-85F
+ 0x41113043
+ All
+ LFE5U-85F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ /mt/lattice/diamond/3.7_x64/data/vmdata/database/xpga/ecp5/LFE5U-85F.msk
+ Bypass
+
+
+
+
+
+ 1
+ SPANSION
+ SPI Serial Flash
+ SPI-S25FL164K
+ 0x16
+ 8-lead SOIC
+ SPI Flash Erase,Program
+ project/project_project_multiboot_flash_s25fl164k.mcs
+ 0x00000000
+ 0x00800000
+ 64
+ 8388608
+ 1
+
+
+
+
+
+ 1
+
+ project/project_project_multiboot_flash_s25fl164k.mcs
+
+
+
+
+
+
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ FPU1 JTAG PROGRAMMER A Location 0000 Serial FPU1 JTAG Programmer A
+
+
diff --git a/boards/ulx3s-v2.0-85f-sp/ulx3s_85f_sram.xcf b/boards/ulx3s-v2.0-85f-sp/ulx3s_85f_sram.xcf
new file mode 100644
index 0000000..e002ae2
--- /dev/null
+++ b/boards/ulx3s-v2.0-85f-sp/ulx3s_85f_sram.xcf
@@ -0,0 +1,48 @@
+
+
+
+
+
+ JTAG
+
+
+ 1
+ Lattice
+ ECP5UM
+ LFE5U-85F
+ 0x41113043
+ All
+ LFE5U-85F
+
+ 8
+ 11111111
+ 1
+ 0
+
+ project/project_project.bit
+ Fast Program
+
+
+
+
+ SEQUENTIAL
+ ENTIRED CHAIN
+ No Override
+ TLR
+ TLR
+
+ 1
+
+
+ USB2
+ FTUSB-0
+ DUAL RS232-HS A Location 0000 Serial Dual RS232-HS A
+
+
diff --git a/common/serial.v b/common/serial.v
index 360d204..b776c70 100644
--- a/common/serial.v
+++ b/common/serial.v
@@ -11,7 +11,7 @@ module width_adapter #(
output data_out_put,
input data_out_free,
- output [OUTPUT_WIDTH-1:0] data_out,
+ output [OUTPUT_WIDTH-1:0] data_out
);
generate
diff --git a/common/tinyfpga_bootloader.v b/common/tinyfpga_bootloader.v
index 578ca22..922d5a0 100644
--- a/common/tinyfpga_bootloader.v
+++ b/common/tinyfpga_bootloader.v
@@ -74,7 +74,11 @@ module tinyfpga_bootloader (
end
end
end
- always @(posedge clk_48mhz) pwm_cnt <= pwm_cnt + 1'b1;
+ always @(posedge clk_48mhz)
+ if (reset)
+ pwm_cnt <= 0;
+ else
+ pwm_cnt <= pwm_cnt + 1'b1;
assign led = led_pwm > pwm_cnt;
diff --git a/common/tinyfpgasp_bootloader.v b/common/tinyfpgasp_bootloader.v
new file mode 100644
index 0000000..0c836d9
--- /dev/null
+++ b/common/tinyfpgasp_bootloader.v
@@ -0,0 +1,231 @@
+module tinyfpgasp_bootloader (
+ input clk_48mhz,
+ input reset,
+
+ // USB lines. Split into input vs. output and oe control signal to maintain
+ // highest level of compatibility with synthesis tools.
+ output usb_p_tx,
+ output usb_n_tx,
+
+ input usb_p_rx,
+ input usb_n_rx,
+
+ output usb_tx_en,
+
+ // bootloader indicator light, pulses on and off when bootloader is active
+ output led,
+ output [7:0] debug_led,
+
+ // connection to SPI flash
+ output spi_cs,
+ output spi_sck,
+ output spi_mosi,
+ input spi_miso,
+
+ // when asserted it indicates the bootloader is ready for the FPGA to load
+ // the user config. different FPGAs use different primitives for this
+ // function.
+ output boot
+);
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// bootloader LED
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ reg [7:0] led_pwm = 0;
+ reg [7:0] pwm_cnt = 0;
+
+ reg [5:0] ns_cnt = 0;
+ wire ns_rst = (ns_cnt == 48);
+ always @(posedge clk_48mhz) begin
+ if (ns_rst) begin
+ ns_cnt <= 0;
+ end else begin
+ ns_cnt <= ns_cnt + 1'b1;
+ end
+ end
+
+ reg [9:0] us_cnt = 0;
+ wire us_rst = (us_cnt == 1000);
+ always @(posedge clk_48mhz) begin
+ if (us_rst) begin
+ us_cnt <= 0;
+ end else if (ns_rst) begin
+ us_cnt <= us_cnt + 1'b1;
+ end
+ end
+
+ reg count_down = 0;
+ always @(posedge clk_48mhz) begin
+ if (us_rst) begin
+ if (count_down) begin
+ if (led_pwm == 0) begin
+ count_down <= 0;
+ end else begin
+ led_pwm <= led_pwm - 1'b1;
+ end
+ end else begin
+ if (led_pwm == 255) begin
+ count_down <= 1;
+ end else begin
+ led_pwm <= led_pwm + 1'b1;
+ end
+ end
+ end
+ end
+ always @(posedge clk_48mhz)
+ if (reset)
+ pwm_cnt <= 0;
+ else
+ pwm_cnt <= pwm_cnt + 1'b1;
+ assign led = led_pwm > pwm_cnt;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////
+ //////// usb engine
+ ////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+
+ wire [6:0] dev_addr;
+ wire [7:0] out_ep_data;
+
+ wire ctrl_out_ep_req;
+ wire ctrl_out_ep_grant;
+ wire ctrl_out_ep_data_avail;
+ wire ctrl_out_ep_setup;
+ wire ctrl_out_ep_data_get;
+ wire ctrl_out_ep_stall;
+ wire ctrl_out_ep_acked;
+
+ wire ctrl_in_ep_req;
+ wire ctrl_in_ep_grant;
+ wire ctrl_in_ep_data_free;
+ wire ctrl_in_ep_data_put;
+ wire [7:0] ctrl_in_ep_data;
+ wire ctrl_in_ep_data_done;
+ wire ctrl_in_ep_stall;
+ wire ctrl_in_ep_acked;
+
+
+ wire serial_out_ep_req;
+ wire serial_out_ep_grant;
+ wire serial_out_ep_data_avail;
+ wire serial_out_ep_setup;
+ wire serial_out_ep_data_get;
+ wire serial_out_ep_stall;
+ wire serial_out_ep_acked;
+
+ wire serial_in_ep_req;
+ wire serial_in_ep_grant;
+ wire serial_in_ep_data_free;
+ wire serial_in_ep_data_put;
+ wire [7:0] serial_in_ep_data;
+ wire serial_in_ep_data_done;
+ wire serial_in_ep_stall;
+ wire serial_in_ep_acked;
+
+ wire sof_valid;
+ wire [10:0] frame_index;
+
+ reg [25:0] host_presence_timer = 0;
+ wire host_presence_timeout;
+
+ wire boot_to_user_design;
+
+ assign boot = host_presence_timeout || boot_to_user_design;
+ usb_sp_ctrl_ep ctrl_ep_inst (
+ .clk(clk_48mhz),
+ .reset(reset),
+ .dev_addr(dev_addr),
+
+ // debug led
+ .debug_led(debug_led),
+
+ // SPI chip interface
+ .spi_csn(spi_cs),
+ .spi_clk(spi_sck),
+ .spi_mosi(spi_mosi),
+ .spi_miso(spi_miso),
+
+ // out endpoint interface
+ .out_ep_req(ctrl_out_ep_req),
+ .out_ep_grant(ctrl_out_ep_grant),
+ .out_ep_data_avail(ctrl_out_ep_data_avail),
+ .out_ep_setup(ctrl_out_ep_setup),
+ .out_ep_data_get(ctrl_out_ep_data_get),
+ .out_ep_data(out_ep_data),
+ .out_ep_stall(ctrl_out_ep_stall),
+ .out_ep_acked(ctrl_out_ep_acked),
+
+ // in endpoint interface
+ .in_ep_req(ctrl_in_ep_req),
+ .in_ep_grant(ctrl_in_ep_grant),
+ .in_ep_data_free(ctrl_in_ep_data_free),
+ .in_ep_data_put(ctrl_in_ep_data_put),
+ .in_ep_data(ctrl_in_ep_data),
+ .in_ep_data_done(ctrl_in_ep_data_done),
+ .in_ep_stall(ctrl_in_ep_stall),
+ .in_ep_acked(ctrl_in_ep_acked)
+ );
+
+ usb_fs_pe #(
+ .NUM_OUT_EPS(5'd1),
+ .NUM_IN_EPS(5'd1)
+ ) usb_fs_pe_inst (
+ .clk(clk_48mhz),
+ .reset(reset),
+
+ .usb_p_tx(usb_p_tx),
+ .usb_n_tx(usb_n_tx),
+ .usb_p_rx(usb_p_rx),
+ .usb_n_rx(usb_n_rx),
+ .usb_tx_en(usb_tx_en),
+
+ .dev_addr(dev_addr),
+
+ // out endpoint interfaces
+ .out_ep_req({ctrl_out_ep_req}),
+ .out_ep_grant({ctrl_out_ep_grant}),
+ .out_ep_data_avail({ctrl_out_ep_data_avail}),
+ .out_ep_setup({ctrl_out_ep_setup}),
+ .out_ep_data_get({ctrl_out_ep_data_get}),
+ .out_ep_data(out_ep_data),
+ .out_ep_stall({ctrl_out_ep_stall}),
+ .out_ep_acked({ctrl_out_ep_acked}),
+
+ // in endpoint interfaces
+ .in_ep_req({ctrl_in_ep_req}),
+ .in_ep_grant({ctrl_in_ep_grant}),
+ .in_ep_data_free({ctrl_in_ep_data_free}),
+ .in_ep_data_put({ctrl_in_ep_data_put}),
+ .in_ep_data({ctrl_in_ep_data[7:0]}),
+ .in_ep_data_done({ctrl_in_ep_data_done}),
+ .in_ep_stall({ctrl_in_ep_stall}),
+ .in_ep_acked({ctrl_in_ep_acked}),
+
+ // sof interface
+ .sof_valid(sof_valid),
+ .frame_index(frame_index)
+ );
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // host presence detection
+ ////////////////////////////////////////////////////////////////////////////////
+
+ always @(posedge clk_48mhz) begin
+ if (sof_valid) begin
+ host_presence_timer <= 0;
+ end else begin
+ if (host_presence_timer[25] == 1'b0) begin
+ host_presence_timer <= host_presence_timer + 1;
+ end
+ end
+ end
+ assign host_presence_timeout = host_presence_timer[25];
+
+endmodule
diff --git a/common/usb_sp_ctrl_ep.v b/common/usb_sp_ctrl_ep.v
new file mode 100644
index 0000000..eae1933
--- /dev/null
+++ b/common/usb_sp_ctrl_ep.v
@@ -0,0 +1,504 @@
+module usb_sp_ctrl_ep (
+ input clk,
+ input reset,
+ output [6:0] dev_addr,
+
+ output reg [7:0] debug_led,
+
+ ////////////////////
+ // spi chip
+ ////////////////////
+ input spi_miso,
+ output spi_mosi,
+ output reg spi_clk = 1,
+ output reg spi_csn = 1,
+
+ ////////////////////
+ // out endpoint interface
+ ////////////////////
+ output out_ep_req,
+ input out_ep_grant,
+ input out_ep_data_avail,
+ input out_ep_setup,
+ output out_ep_data_get,
+ input [7:0] out_ep_data,
+ output out_ep_stall,
+ input out_ep_acked,
+
+
+ ////////////////////
+ // in endpoint interface
+ ////////////////////
+ output in_ep_req,
+ input in_ep_grant,
+ input in_ep_data_free,
+ output in_ep_data_put,
+ output [7:0] in_ep_data,
+ output in_ep_data_done,
+ output reg in_ep_stall,
+ input in_ep_acked
+);
+
+
+ localparam IDLE = 0;
+ localparam SETUP = 1;
+ localparam DATA_IN = 2;
+ localparam DATA_OUT = 3;
+ localparam STATUS_IN = 4;
+ localparam STATUS_OUT = 5;
+
+ reg [5:0] ctrl_xfr_state = IDLE;
+ reg [5:0] ctrl_xfr_state_next;
+
+
+
+ reg setup_stage_end = 0;
+ reg data_stage_end = 0;
+ reg status_stage_end = 0;
+ reg send_zero_length_data_pkt = 0;
+
+
+ /////////////////////////
+ /// SPI BUFFERING
+ /////////////////////////
+ reg [7:0] out_buf [0:63]; // PC out transfer should be received here (64 byte max)
+ reg [7:0] in_buf [0:31]; // PC in transfer when PC reads back buffered SPI response (32 byte max)
+ reg [5:0] out_buf_addr_usb = 0; // 0-63 address for the buffer for USB acceptor
+ reg [5:0] out_buf_addr_spi = 0; // 0-63 address for the buffer for SPI sender
+ reg [5:0] spi_length = 0; // 0-32 number of bytes to be sent by OUT
+ reg [5:0] spi_bytes_sent = 0; // 0-32 bit current number of bytes sent by OUT
+ reg [3:0] spi_bit_counter = 10; // 0-15
+ reg send_in_buf = 0;
+ reg spi_continue = 0; // 0:normal packet (reset start, closed end) 1:packet continued (open start, open end)
+
+ reg [25:0] superslow; // so slow that LEDs are visible
+
+ // help with assembling the SPI byte
+ reg [7:0] spi_miso_byte; // host input, device output
+ wire [7:0] spi_miso_byte_next;
+ assign spi_miso_byte_next = {spi_miso_byte[6:0], spi_miso}; // input with shifting, MSB enters shift-register first
+ reg [7:0] spi_mosi_byte; // host output, device input
+ wire [7:0] spi_mosi_byte_next;
+ assign spi_mosi_byte_next = {spi_mosi_byte[6:0], 1'b0}; // input with shifting, MSB enters shift-register first
+ assign spi_mosi = spi_mosi_byte[7]; // output: MSB SPI bit gets shifted out first
+
+ wire more_data_out;
+
+ // the default control endpoint gets assigned the device address
+ reg [6:0] dev_addr_i = 0;
+ assign dev_addr = dev_addr_i;
+
+ assign out_ep_req = out_ep_data_avail;
+ assign out_ep_data_get = out_ep_data_avail;
+ reg out_ep_data_valid = 0;
+ always @(posedge clk) out_ep_data_valid <= out_ep_data_avail && out_ep_grant;
+
+ // need to record the setup data
+ reg [3:0] setup_data_addr = 0;
+ reg [9:0] raw_setup_data [7:0];
+
+ wire [7:0] bmRequestType = raw_setup_data[0];
+ wire [7:0] bRequest = raw_setup_data[1];
+ wire [15:0] wValue = {raw_setup_data[3][7:0], raw_setup_data[2][7:0]};
+ wire [15:0] wIndex = {raw_setup_data[5][7:0], raw_setup_data[4][7:0]};
+ wire [15:0] wLength = {raw_setup_data[7][7:0], raw_setup_data[6][7:0]};
+
+ // keep track of new out data start and end
+ wire pkt_start;
+ wire pkt_end;
+
+ rising_edge_detector detect_pkt_start (
+ .clk(clk),
+ .in(out_ep_data_avail),
+ .out(pkt_start)
+ );
+
+ falling_edge_detector detect_pkt_end (
+ .clk(clk),
+ .in(out_ep_data_avail),
+ .out(pkt_end)
+ );
+
+ assign out_ep_stall = 1'b0;
+
+ wire setup_pkt_start = pkt_start && out_ep_setup;
+
+ wire has_data_stage = wLength != 0;
+
+ wire out_data_stage;
+ assign out_data_stage = has_data_stage && !bmRequestType[7];
+
+ wire in_data_stage;
+ assign in_data_stage = has_data_stage && bmRequestType[7];
+
+ reg [7:0] bytes_sent = 0;
+ reg [6:0] rom_length = 0;
+
+ wire all_data_sent =
+ (bytes_sent >= rom_length) ||
+ (bytes_sent >= wLength);
+
+ wire more_data_to_send =
+ !all_data_sent;
+
+ wire in_data_transfer_done;
+
+ rising_edge_detector detect_in_data_transfer_done (
+ .clk(clk),
+ .in(all_data_sent),
+ .out(in_data_transfer_done)
+ );
+
+ assign in_ep_data_done = (in_data_transfer_done && ctrl_xfr_state == DATA_IN) || send_zero_length_data_pkt;
+
+ assign in_ep_req = ctrl_xfr_state == DATA_IN && more_data_to_send;
+ assign in_ep_data_put = ctrl_xfr_state == DATA_IN && more_data_to_send && in_ep_data_free;
+
+
+ reg [6:0] rom_addr = 0;
+
+ reg save_dev_addr = 0;
+ reg [6:0] new_dev_addr = 0;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // control transfer state machine
+ ////////////////////////////////////////////////////////////////////////////////
+
+
+ always @(negedge clk) begin
+ setup_stage_end <= 0;
+ data_stage_end <= 0;
+ status_stage_end <= 0;
+ send_zero_length_data_pkt <= 0;
+
+ case (ctrl_xfr_state)
+ IDLE : begin
+ if (setup_pkt_start) begin
+ ctrl_xfr_state_next <= SETUP;
+ end else begin
+ ctrl_xfr_state_next <= IDLE;
+ end
+ end
+
+ SETUP : begin
+ if (pkt_end) begin
+ setup_stage_end <= 1;
+
+ if (in_data_stage) begin
+ ctrl_xfr_state_next <= DATA_IN;
+
+ end else if (out_data_stage) begin
+ ctrl_xfr_state_next <= DATA_OUT;
+
+ end else begin
+ ctrl_xfr_state_next <= STATUS_IN;
+ send_zero_length_data_pkt <= 1;
+ end
+
+ end else begin
+ ctrl_xfr_state_next <= SETUP;
+ end
+ end
+
+ DATA_IN : begin
+ if (in_ep_stall) begin
+ ctrl_xfr_state_next <= IDLE;
+ data_stage_end <= 1;
+ status_stage_end <= 1;
+
+ end else if (in_ep_acked && all_data_sent) begin
+ ctrl_xfr_state_next <= STATUS_OUT;
+ data_stage_end <= 1;
+
+ end else begin
+ ctrl_xfr_state_next <= DATA_IN;
+ end
+ end
+
+ DATA_OUT : begin
+ // if (out_ep_acked) begin
+ if (pkt_end) begin
+ ctrl_xfr_state_next <= STATUS_IN;
+ send_zero_length_data_pkt <= 1;
+ data_stage_end <= 1;
+
+ end else begin
+ ctrl_xfr_state_next <= DATA_OUT;
+ end
+ end
+
+ STATUS_IN : begin
+ if (in_ep_acked) begin
+ ctrl_xfr_state_next <= IDLE;
+ status_stage_end <= 1;
+
+ end else begin
+ ctrl_xfr_state_next <= STATUS_IN;
+ end
+ end
+
+ STATUS_OUT: begin
+ if (out_ep_acked) begin
+ ctrl_xfr_state_next <= IDLE;
+ status_stage_end <= 1;
+
+ end else begin
+ ctrl_xfr_state_next <= STATUS_OUT;
+ end
+ end
+
+ default begin
+ ctrl_xfr_state_next <= IDLE;
+ end
+ endcase
+ end
+
+ always @(posedge clk) begin
+ if (reset) begin
+ ctrl_xfr_state <= IDLE;
+ end else begin
+ ctrl_xfr_state <= ctrl_xfr_state_next;
+ end
+ end
+
+ always @(posedge clk) begin
+ in_ep_stall <= 0;
+
+ if (out_ep_setup && out_ep_data_valid) begin
+ raw_setup_data[setup_data_addr] <= out_ep_data;
+ setup_data_addr <= setup_data_addr + 1;
+ end
+
+ if (setup_stage_end) begin
+ case (bmRequestType[6:5]) // 2 bits describing request type
+ 0: begin // 0: standard request
+ send_in_buf <= 0; // not vendor-specific
+ case (bRequest)
+ 'h06 : begin
+ // GET_DESCRIPTOR
+ case (wValue[15:8])
+ 1 : begin
+ // DEVICE
+ rom_addr <= 0;
+ rom_length <= 18;
+ end
+
+ 2 : begin
+ // CONFIGURATION
+ rom_addr <= 18;
+ rom_length <= 18;
+ end
+
+ 6 : begin
+ // DEVICE_QUALIFIER
+ in_ep_stall <= 1;
+ rom_length <= 0;
+ end
+
+ endcase
+ end
+
+ 'h05 : begin
+ // SET_ADDRESS
+ rom_length <= 0;
+
+ // we need to save the address after the status stage ends
+ // this is because the status stage token will still be using
+ // the old device address
+ save_dev_addr <= 1;
+ new_dev_addr <= wValue[6:0];
+ end
+
+ 'h09 : begin
+ // SET_CONFIGURATION
+ rom_length <= 0;
+ end
+
+ default begin
+ rom_length <= 0;
+ end
+ endcase
+ end // end 0: standard request
+
+ 2: begin // 2: vendor specific request
+ case (bRequest)
+ 0: begin // write or read SPI data block
+ spi_continue <= wValue[0];
+ if (in_data_stage)
+ begin
+ send_in_buf <= 1; // this is vendor-specific request, send data from RAM buffer, not descriptor ROM
+ rom_addr <= 0; // misnomer: rom_addr here addresses RAM buffer actually
+ rom_length <= wLength; // misnomer: rom_length is actually RAM bytes to be sent
+ bytes_sent <= 0;
+ end
+ if (out_data_stage)
+ begin
+ if (spi_bytes_sent != spi_length)
+ debug_led <= debug_led + 1; // indicate overrun, new packet arrived before SPI finished
+ else
+ begin
+ send_in_buf <= 0;
+ spi_length <= wLength;
+ spi_bytes_sent <= 0;
+ end
+ end
+ end // end bRequest 0
+
+ 1: begin // read SPI state (0:free 1:busy) IN request
+ // choose ROM location which is not likely to change
+ // because it will send data from ROM, not buffer
+ if (in_data_stage)
+ begin
+ send_in_buf <= 0;
+ if (spi_bytes_sent == spi_length)
+ rom_addr <= 5; // must point to 0 in ROM descriptor
+ else
+ rom_addr <= 1; // must point to 1 in ROM descriptor
+ rom_length <= 1;
+ bytes_sent <= 0;
+ end
+ end
+
+ default begin // catch all other bRequest != 0
+ end
+ endcase
+ end // end 2: vendor specific request
+ default begin // default 1,3: unhandled
+ end // end defaul
+ endcase
+ end
+
+ if ( (ctrl_xfr_state == DATA_IN) && more_data_to_send && in_ep_grant && in_ep_data_free) begin
+ rom_addr <= rom_addr + 1;
+ bytes_sent <= bytes_sent + 1;
+ end
+
+ if ( (ctrl_xfr_state == DATA_OUT) && out_ep_data_valid && ~out_ep_setup) begin
+ out_buf[out_buf_addr_usb] <= out_ep_data;
+ out_buf_addr_usb <= out_buf_addr_usb + 1;
+ end
+
+ //superslow <= superslow + 1;
+ //if (superslow == 0)
+ if (spi_bytes_sent == spi_length)
+ begin // nothing to send
+ if (spi_continue == 0)
+ begin
+ spi_clk <= 1; // clock inactive
+ spi_csn <= 1; // disable chip
+ spi_bit_counter <= 12; // skip first few clock cycles
+ end
+ end
+ else // spi_bytes_sent != spi_length
+ begin
+ spi_csn <= 0; // enable chip
+ if(out_buf_addr_usb != out_buf_addr_spi) // more spi data
+ begin
+ if (spi_bit_counter[3])
+ spi_bit_counter <= spi_bit_counter + 1; // skip some cycles, flash needs small delay from csn=0 to clk
+ else // spi_bit_counter < 8
+ begin
+ if (spi_clk == 1)
+ begin // clock=0: send data to SPI chip
+ if (spi_bit_counter[2:0] == 0)
+ spi_mosi_byte <= out_buf[out_buf_addr_spi]; // new byte from buffer
+ else
+ spi_mosi_byte <= spi_mosi_byte_next; // shift bit output to SPI chip
+ end
+ if (spi_clk == 0)
+ begin // clock=1: read data from SPI chip
+ spi_miso_byte <= spi_miso_byte_next; // shift input from SPI chip
+ if (spi_bit_counter[2:0] == 7) // byte completed
+ begin
+ in_buf[spi_bytes_sent] <= spi_miso_byte_next; // complete byte to IN buffer, later sent
+ spi_bytes_sent <= spi_bytes_sent + 1;
+ out_buf_addr_spi <= out_buf_addr_spi + 1; // catch up
+ end
+ spi_bit_counter[2:0] <= spi_bit_counter[2:0] + 1;
+ end
+ spi_clk <= ~spi_clk;
+ end // spi bit counter < 8
+ end // more_spi_data
+ end // spi_bytes_sent != spi_length
+
+
+ if (status_stage_end) begin
+ setup_data_addr <= 0;
+ bytes_sent <= 0;
+ rom_length <= 0;
+
+ if (save_dev_addr) begin
+ save_dev_addr <= 0;
+ dev_addr_i <= new_dev_addr;
+ end
+ end
+
+ if (reset) begin
+ bytes_sent <= 0;
+ rom_length <= 0;
+ dev_addr_i <= 0;
+ setup_data_addr <= 0;
+ save_dev_addr <= 0;
+ send_in_buf <= 0;
+ spi_length <= 0;
+ spi_bytes_sent <= 0;
+ debug_led <= 0;
+ end
+ end
+
+ assign in_ep_data = (send_in_buf ? in_buf[rom_addr[4:0]] : descriptor_rom[rom_addr]);
+
+ wire [7:0] descriptor_rom [0:35];
+ assign descriptor_rom[0] = 18; // bLength
+ assign descriptor_rom[1] = 1; // bDescriptorType
+ assign descriptor_rom[2] = 'h10; // bcdUSB[0]
+ assign descriptor_rom[3] = 'h01; // bcdUSB[1]
+ assign descriptor_rom[4] = 'hFF; // bDeviceClass
+ assign descriptor_rom[5] = 'h00; // bDeviceSubClass
+ assign descriptor_rom[6] = 'h00; // bDeviceProtocol
+ assign descriptor_rom[7] = 32; // bMaxPacketSize0
+
+ assign descriptor_rom[8] = 'hc0; // idVendor[0] VOTI
+ assign descriptor_rom[9] = 'h16; // idVendor[1]
+ assign descriptor_rom[10] = 'hdc; // idProduct[0]
+ assign descriptor_rom[11] = 'h05; // idProduct[1]
+
+ assign descriptor_rom[12] = 1; // bcdDevice[0] version minor
+ assign descriptor_rom[13] = 0; // bcdDevice[1] version major
+ assign descriptor_rom[14] = 0; // iManufacturer
+ assign descriptor_rom[15] = 0; // iProduct
+ assign descriptor_rom[16] = 0; // iSerialNumber
+ assign descriptor_rom[17] = 1; // bNumConfigurations
+
+ // configuration descriptor
+ assign descriptor_rom[18] = 9; // bLength
+ assign descriptor_rom[19] = 2; // bDescriptorType
+ assign descriptor_rom[20] = 18; // wTotalLength[0]
+ assign descriptor_rom[21] = 0; // wTotalLength[1]
+ assign descriptor_rom[22] = 1; // bNumInterfaces (must have at least 1 interface)
+ assign descriptor_rom[23] = 1; // bConfigurationValue
+ assign descriptor_rom[24] = 0; // iConfiguration
+ assign descriptor_rom[25] = 'hC0; // bmAttributes
+ assign descriptor_rom[26] = 250; // bMaxPower
+
+ // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
+ assign descriptor_rom[27] = 9; // bLength
+ assign descriptor_rom[28] = 4; // bDescriptorType
+ assign descriptor_rom[29] = 0; // bInterfaceNumber
+ assign descriptor_rom[30] = 0; // bAlternateSetting
+ assign descriptor_rom[31] = 0; // bNumEndpoints
+ assign descriptor_rom[32] = 0; // bInterfaceClass
+ assign descriptor_rom[33] = 0; // bInterfaceSubClass
+ assign descriptor_rom[34] = 0; // bInterfaceProtocol
+ assign descriptor_rom[35] = 0; // iInterface
+
+endmodule
+
+/* TODO
+[ ] duplicate packets sometimes recived (did SPI finish before new packet came')
+[ ] lsusb -vvv -d shows descriptor and vailts, try to dump traffic with wireshark
+[ ] lsusb -vvv -d will make lisbusb fail
+[ ] overrun signal - problem: SPI often stalls
+[ ] wValue OUT: append dummy bytes after end of SPI data (after last byte, add to addr)
+[ ] wIndex OUT: set index to skip first N bytes for next IN
+*/
diff --git a/programmer/tinyfpgasp/cmdline.ggo b/programmer/tinyfpgasp/cmdline.ggo
new file mode 100644
index 0000000..55a0ad5
--- /dev/null
+++ b/programmer/tinyfpgasp/cmdline.ggo
@@ -0,0 +1,16 @@
+# file cmdline.ggo
+
+# Name of your program
+package "fpgasp" # don't use package if you're using automake
+# Version of your program
+version "0.1.0" # don't use version if you're using automake
+
+purpose "Flasher for tinyfpga bootloader with USB vendor-specific support"
+
+# long short description type default required
+option "address" a "Byte Start Address" int default="0x200000" no
+option "length" l "Bytes Length" int default="0" no
+option "read" r "Filename Flash -> File" string default="read.bit" no
+option "write" w "Filename File -> Flash" string default="write.bit" no
+option "device" d "VID:PID of USB device" string default="16c0:05dc" no
+# option "verbose" v "Print extra info (0-no|1-some|2-much)" int default="0" no
diff --git a/programmer/tinyfpgasp/makefile b/programmer/tinyfpgasp/makefile
new file mode 100644
index 0000000..57a59f0
--- /dev/null
+++ b/programmer/tinyfpgasp/makefile
@@ -0,0 +1,25 @@
+CFLAGS=-Wall -s -Os
+CLIBS=-lusb-1.0
+
+project=tinyfpgasp
+parser=cmdline
+version=$(shell ./version.sh)
+
+OBJECTS=$(project).o $(parser).o
+
+all: $(project)
+
+$(project).o: $(project).c $(parser).h
+ gcc -c $(CFLAGS) $<
+
+$(parser).c: $(parser).ggo makefile
+ gengetopt < $< --file-name=$(parser) # --unamed-opts
+
+$(parser).h: $(parser).ggo makefile
+ gengetopt < $< --file-name=$(parser) # --unamed-opts
+
+$(project): $(OBJECTS) makefile
+ gcc $(CFLAGS) $(CLIBS) $(OBJECTS) -o $@
+
+clean:
+ rm -f $(project) $(OBJECTS) $(parser).o $(parser).c $(parser).h *~
diff --git a/programmer/tinyfpgasp/tinyfpgasp.c b/programmer/tinyfpgasp/tinyfpgasp.c
new file mode 100644
index 0000000..f0b16b3
--- /dev/null
+++ b/programmer/tinyfpgasp/tinyfpgasp.c
@@ -0,0 +1,649 @@
+
+#include
+
+// uint types
+#include
+
+// malloc
+#include
+
+// memcpy
+#include
+
+// file handling
+#include
+#include
+#include
+
+// USB
+#include
+
+// commandline parser cmdline.ggo with gengetpot
+#include "cmdline.h"
+
+struct gengetopt_args_info args_info;
+struct gengetopt_args_info *args = &args_info;
+
+static struct libusb_device_handle *device_handle = NULL;
+uint8_t libusb_initialized = 0, interface_claimed = 0;
+
+void print_progress_bar (uint32_t done, uint32_t total)
+{
+ const char *PBSTR = "#################################################";
+ if(total == 0 || done > total)
+ done = total = 1; // avoid division by zero
+ const uint32_t PBWIDTH = strlen(PBSTR);
+ int percent = (int) (100 * done / total);
+ int lpad = (int) (PBWIDTH * done / total);
+ int rpad = PBWIDTH - lpad;
+ fprintf(stderr, "\r%3d%% [%.*s%*s]", percent, lpad, PBSTR, rpad, "");
+ fflush(stderr);
+}
+
+void print_hex_buf(uint8_t *buf, uint32_t len)
+{
+ for(int i = 0; i < len; i++)
+ {
+ if(i % 32 == 0 && i != 0)
+ printf("\n");
+ printf("%02X ", buf[i]);
+ }
+ printf("\n");
+}
+
+
+void cmd_addr(uint8_t *buf, uint8_t cmd, uint32_t addr)
+{
+ buf[0] = cmd;
+ buf[1] = 0xFF & (addr >> 16);
+ buf[2] = 0xFF & (addr >> 8);
+ buf[3] = 0XFF & addr;
+}
+
+// up to 32 byte single packet in/out exchange
+int txrx(uint8_t *out_data, uint32_t out_len, uint8_t *in_data, uint32_t in_len)
+{
+ uint8_t bRequest = 0; // currently no use
+ uint16_t wIndex = 0; // currently no use
+ uint16_t wValue = 0; // wValue: 0-no continuation, 1-continuation
+ uint16_t timeout_ms = 10; // 10 ms waiting for response
+ int response;
+
+ response = libusb_control_transfer(device_handle, (uint8_t)(LIBUSB_ENDPOINT_OUT|LIBUSB_REQUEST_TYPE_VENDOR),
+ bRequest, wValue, wIndex, out_data, out_len, timeout_ms);
+ if(response < 0)
+ {
+ fprintf(stderr, "txrx OUT: %s\n", libusb_error_name(response));
+ return -1; // something went wrong with USB
+ }
+
+ if(in_data == NULL || in_len == 0)
+ return 0;
+
+ response = libusb_control_transfer(device_handle, (uint8_t)(LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_VENDOR),
+ bRequest, wValue, wIndex, in_data, in_len, timeout_ms);
+ if(response < 0)
+ {
+ fprintf(stderr, "txrx IN: %s\n", libusb_error_name(response));
+ return -1; // something went wrong with USB
+ }
+
+ return 0;
+}
+
+int flash_read_id()
+{
+ uint8_t buf[5];
+ cmd_addr(buf, 0xAB, 0);
+ int rc = txrx(buf, sizeof(buf), buf, sizeof(buf));
+ if(rc < 0)
+ return rc;
+ return buf[4];
+}
+
+int flash_read_status()
+{
+ uint8_t buf[2];
+ buf[0] = 0x05;
+ int rc = txrx(buf, sizeof(buf), buf, sizeof(buf));
+ if(rc < 0)
+ return rc;
+ return buf[1];
+}
+
+int flash_wait_while_busy()
+{
+ while(flash_read_status() & 1);
+ return 0;
+}
+
+int flash_write_enable()
+{
+ uint8_t buf[1];
+ buf[0] = 0x06;
+ int rc = txrx(buf, sizeof(buf), NULL, 0);
+ if(rc < 0)
+ return rc;
+ return 0;
+}
+
+int flash_write_disable()
+{
+ uint8_t buf[1];
+ buf[0] = 0x04;
+ int rc = txrx(buf, sizeof(buf), NULL, 0);
+ if(rc < 0)
+ return rc;
+ return 0;
+}
+
+
+int flash_read(uint8_t *data, uint32_t addr, uint32_t length)
+{
+ uint8_t buf[32]; // USB I/O buffer
+ uint32_t accumulated_read = 0; // accumulate total read
+ uint32_t payload_start = 4; // initial payload starts at byte 4 without continuation
+ uint8_t data1 = 0; // currently no use
+ uint8_t bRequest = 0; // currently no use
+ uint16_t wIndex = 0; // currently no use
+ uint16_t wValue = length <= sizeof(buf)-payload_start ? 0 : 1; // wValue: 0-no continuation, 1-continuation
+ uint16_t timeout_ms = 10; // 10 ms waiting for response
+
+ cmd_addr(buf, 0x03, addr); // FLASH normal (slow) read
+
+ while(accumulated_read < length)
+ {
+ int response;
+
+ #if 0
+ // IN request - wait for SPI to finish its transmission
+ buf[0] = 1;
+ while(buf[0] == 1)
+ {
+ response = libusb_control_transfer(device_handle, (uint8_t)(LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_VENDOR),
+ 1, 0, 0, buf, 1, timeout_ms);
+ if(buf[0])
+ printf("spi busy before out %d\n", buf[0]);
+ }
+ #endif
+
+ // write to USB read command followed with dummy bytes
+ // in order to read, we must first write command and the
+ // contiue writing anything to SPI
+ // every written byte will also result in reading a byte.
+ // up to 32 read bytes are buffered inside of the USB device.
+ // this USB buffer can be retrieved by subsequent IN command later.
+ response = libusb_control_transfer(device_handle, (uint8_t)(LIBUSB_ENDPOINT_OUT|LIBUSB_REQUEST_TYPE_VENDOR|data1),
+ bRequest, wValue, wIndex, buf, sizeof(buf), timeout_ms);
+ if(response < 0)
+ {
+ fprintf(stderr, "OUT: %s\n", libusb_error_name(response));
+ return -1; // something went wrong with USB
+ }
+ // calculate next request length (how much to read from USB)
+ uint32_t request_size;
+ if(accumulated_read + sizeof(buf) - payload_start >= length)
+ {
+ // printf("last packet\n");
+ // end packet, trim request size to how much we really need
+ request_size = length + payload_start - accumulated_read;
+ wValue = 0; // terminate continuation
+ }
+ else
+ request_size = sizeof(buf);
+
+ #if 0
+ // IN request - wait for SPI to finish its transmission
+ buf[0] = 1;
+ while(buf[0] == 1)
+ {
+ response = libusb_control_transfer(device_handle, (uint8_t)(LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_VENDOR),
+ 1, 0, 0, buf, 1, timeout_ms);
+ if(buf[0])
+ printf("spi busy before in %d\n", buf[0]);
+ }
+ #endif
+
+ //usleep(1000000);
+ // usleep(11); // sleep 11us for SPI to tranfer (usually not needed)
+ response = libusb_control_transfer(device_handle, (uint8_t)(LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_VENDOR|data1),
+ bRequest, wValue, wIndex, buf, request_size, timeout_ms);
+ if(response != request_size)
+ {
+ fprintf(stderr, "IN: %s\n", libusb_error_name(response));
+ return -1; // something went wrong with USB
+ }
+ uint32_t response_size = response - payload_start;
+ memcpy(data, buf+payload_start, response_size);
+ data += response_size;
+ accumulated_read += response_size;
+ if(payload_start) // contination will result in full 32-byte payload
+ payload_start = 0;
+ }
+ return 0; // 0 on success
+}
+
+// retry max "retry" times until 'match' of consecutive identical readings appear
+int flash_read_retry(uint8_t *data, uint32_t addr, uint32_t length, int retry, int match)
+{
+}
+
+// only 3 selected sector lengths are possible
+int flash_erase_sector(uint32_t addr, uint32_t len)
+{
+ uint8_t opcode = 0; // null-opcode is NOP
+ if(len == 4*1024) opcode = 0x20;
+ if(len == 32*1024) opcode = 0x52;
+ if(len == 64*1024) opcode = 0xd8;
+ if(opcode == 0)
+ return -1; // unsupported length
+ flash_write_enable();
+ uint8_t buf[4];
+ cmd_addr(buf, opcode, addr);
+ int rc = txrx(buf, sizeof(buf), NULL, 0);
+ if(rc < 0)
+ return -1; // error in txrx
+ flash_wait_while_busy();
+ return 0;
+}
+
+int flash_write(uint8_t *data, uint32_t addr, uint32_t length)
+{
+ uint8_t buf[32]; // USB I/O buffer
+ uint32_t accumulated_write = 0; // accumulate total read
+ uint32_t payload_start = 4; // initial payload starts at byte 4 without continuation
+ uint8_t data1 = 0; // currently no use
+ uint8_t bRequest = 0; // currently no use
+ uint16_t wIndex = 0; // currently no use
+ uint16_t wValue = length <= sizeof(buf)-payload_start ? 0 : 1; // wValue: 0-no continuation, 1-continuation
+ uint16_t timeout_ms = 10; // 10 ms waiting for response
+
+ flash_write_enable();
+
+ cmd_addr(buf, 0x02, addr); // FLASH write (should be previous erased to 0xFF)
+ while(accumulated_write < length)
+ {
+ int response;
+
+ #if 0
+ // IN request - wait for SPI to finish its transmission
+ buf[0] = 1;
+ while(buf[0] == 1)
+ {
+ response = libusb_control_transfer(device_handle, (uint8_t)(LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_VENDOR),
+ 1, 0, 0, buf, 1, timeout_ms);
+ if(buf[0])
+ printf("spi busy before out %d\n", buf[0]);
+ }
+ #endif
+
+ // calculate next request length (how much to read from USB)
+ uint32_t request_size;
+ if(accumulated_write + sizeof(buf) - payload_start >= length)
+ {
+ // printf("last packet\n");
+ // end packet, trim request size to how much we really need
+ request_size = length + payload_start - accumulated_write;
+ wValue = 0; // terminate continuation
+ }
+ else
+ request_size = sizeof(buf);
+ uint32_t payload_size = sizeof(buf) - payload_start;
+ // printf("paystart %d, payload_size %d\n", payload_start, payload_size);
+ memcpy(buf+payload_start, data, payload_size);
+
+ // write to USB the flash write command followed with data
+ response = libusb_control_transfer(device_handle, (uint8_t)(LIBUSB_ENDPOINT_OUT|LIBUSB_REQUEST_TYPE_VENDOR|data1),
+ bRequest, wValue, wIndex, buf, request_size, timeout_ms);
+ if(response < 0)
+ {
+ fprintf(stderr, "OUT: %s\n", libusb_error_name(response));
+ return -1; // something went wrong with USB
+ }
+
+ #if 0
+ // IN request - wait for SPI to finish its transmission
+ buf[0] = 1;
+ while(buf[0] == 1)
+ {
+ response = libusb_control_transfer(device_handle, (uint8_t)(LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_VENDOR),
+ 1, 0, 0, buf, 1, timeout_ms);
+ if(buf[0])
+ printf("spi busy before in %d\n", buf[0]);
+ }
+ #endif
+
+ data += payload_size;
+ accumulated_write += payload_size;
+ if(payload_start) // contination will result in full 32-byte payload
+ payload_start = 0;
+
+ }
+ flash_wait_while_busy();
+ return 0; // 0 on success
+}
+
+
+// read from addr, length bytes and write to file
+int read_flash_write_file(char *filename, uint32_t addr, uint32_t length)
+{
+ // printf("reading\n");
+ const int bufsize = 28; // not much speed improvement in increasing this
+ uint8_t buf[2][bufsize]; // 2 buffers, both must match
+ uint32_t accumulated_read = 0;
+ int file_descriptor = open(filename, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+ const int retry = 1000;
+ uint32_t next_progress = 0, progress_step = length / 100;
+ while(accumulated_read < length)
+ {
+ int match; // repeat reading until 2 subsequent readings match
+ int ib = 0; // buffer index 0/1 to match
+ uint32_t requested_size = accumulated_read + bufsize >= length ? length - accumulated_read : bufsize;
+ match = 0;
+ const int match_required = 2;
+ // printf("accumulated_read %d\n", accumulated_read);
+ for(int i = 0; i < retry && match < match_required; i++)
+ {
+ buf[ib][0] = ~buf[ib^1][0]; // damage first byte for the match to initially fail unless read correct
+ buf[ib][requested_size-1] = ~buf[ib^1][requested_size-1]; // damage first byte for the match to initially fail unless read correct
+ int rc = flash_read(buf[ib], addr, requested_size);
+ if(rc == 0 && memcmp(buf[ib], buf[ib^1], requested_size) == 0)
+ match++;
+ else
+ {
+ match = 0;
+ if(i > 0)
+ printf("read verify error %d\n", i);
+ }
+ ib ^= 1; // switch buffer
+ }
+ if(match < match_required)
+ {
+ fprintf(stderr, "failure after %d retries\n", retry);
+ return -1;
+ }
+ write(file_descriptor, buf[0], requested_size);
+ accumulated_read += requested_size;
+ addr += requested_size;
+ if(accumulated_read > next_progress)
+ {
+ print_progress_bar(accumulated_read, length);
+ next_progress += progress_step;
+ }
+ }
+ print_progress_bar(accumulated_read, length);
+ fprintf(stderr, "\n");
+ close(file_descriptor);
+ return 0;
+}
+
+
+// write that many bytes found or file or if file is larger, limit by length.
+// read each sector, then determine should we erase it and/or write
+// read it back for verification, if different, retry few times and give up
+// return value
+// 0: ok
+// -1: error
+int read_file_write_flash(char *filename, uint32_t addr, uint32_t length)
+{
+ const uint32_t available_sector_size[] = {4*1024, 32*1024, 64*1024}; // sizes in ascending order
+ const int num_available_sector_size = sizeof(available_sector_size)/sizeof(available_sector_size[0]);
+ uint8_t flash_sector_buf[available_sector_size[num_available_sector_size-1]]; // allocate buf, max sector size
+ uint8_t file_sector_buf[available_sector_size[num_available_sector_size-1]]; // allocate buf, max sector size
+ int file_descriptor = open(filename, O_RDONLY);
+ if(file_descriptor < 0)
+ return -1; // cant't open file
+
+ if(length == 0)
+ {
+ length = lseek(file_descriptor, 0, SEEK_END);
+ lseek(file_descriptor, 0, SEEK_SET);
+ }
+
+ // **** sector logic ****
+ // we need to interated over flash sectors
+ // if writing to partial sector we first read old data from the sector,
+ // erase whole sector, write from file and write old data, then verify and retry
+ const int retry = 10;
+ uint32_t bytes_written = 0;
+ int retries_remaining = retry;
+
+ printf("writing range 0x%06X-0x%06X\n", addr, addr+length-1);
+ // some simple satistics about flash wear
+ uint32_t count_erase = 0, count_write = 0;
+
+ uint32_t last_read_from_file = 1;
+ while(bytes_written < length && last_read_from_file > 0 && retries_remaining > 0)
+ {
+ uint32_t length_remaining = length - bytes_written;
+ // find suitable sector to erase
+ // 1. priority is to minimize easeing part of data we don't have to erase
+ // 2. maximize sector size
+ uint32_t sector_size = available_sector_size[0]; // minimal sector size
+ uint32_t sector_part_before_data = addr % sector_size; // start as minimal sector
+
+ // find do we have any larger sector
+ if(0) // disabled, the smalles 4K sector is most suitable for retry procedure
+ for(int i = 1; i < num_available_sector_size; i++)
+ {
+ if( addr % available_sector_size[i] == sector_part_before_data // if part before is the same
+ && (length_remaining >= available_sector_size[i]-available_sector_size[0])) // and we have enough data
+ sector_size = available_sector_size[i]; // accept new sector size
+ }
+ uint32_t data_bytes_to_write = sector_size - sector_part_before_data;
+ if(bytes_written + data_bytes_to_write >= length)
+ data_bytes_to_write = length - bytes_written; // last sector, clamp size
+ uint32_t erase_sector_addr = addr-sector_part_before_data;
+
+ uint32_t actual_bytes_from_file = 0;
+ if(retries_remaining == retry)
+ { // first retry, it's new sector we need to read flash and file
+ // read sector before erase and before the file
+ flash_read(flash_sector_buf, erase_sector_addr, sector_size);
+ // copy to file sector (as file may be read in less than sector size)
+ memcpy(file_sector_buf, flash_sector_buf, sector_size);
+ // data_bytes_to_write is what we want to write, but file may contain less
+ // try to read from file "data_bytes_to_write" or get eof:
+ uint32_t remaining_to_read = data_bytes_to_write;
+ uint8_t *file_data_pointer = file_sector_buf + addr - erase_sector_addr;
+ last_read_from_file = 1;
+ while(remaining_to_read > 0 && last_read_from_file > 0)
+ {
+ last_read_from_file = read(file_descriptor, file_data_pointer, remaining_to_read);
+ if(last_read_from_file > 0)
+ {
+ remaining_to_read -= last_read_from_file;
+ file_data_pointer += last_read_from_file;
+ }
+ }
+ actual_bytes_from_file = data_bytes_to_write - remaining_to_read;
+ }
+ //printf("actual_bytes_from_file %d\n", actual_bytes_from_file);
+ //if(last_read_from_file <= 0)
+ // printf("****** EOF *******\n");
+ // update number of bytes to write
+ data_bytes_to_write = actual_bytes_from_file;
+
+ // printf("retry %d\n", retries_remaining);
+ retries_remaining--;
+ // this while loop may be early relooped after this point
+ // with "continue" -> retries will be left decremented
+
+ // determine do we have to 2:erase, 1:write or 0:leave the sector unmodified
+ // compare byte-by-byte flash_sector_buf and file_sector_buf
+ uint8_t must_erase = 0;
+ uint8_t must_write = 0;
+ for(uint32_t i = 0; i < sector_size; i++)
+ {
+ if( (flash_sector_buf[i] & file_sector_buf[i]) != file_sector_buf[i])
+ must_erase = 1;
+ if( flash_sector_buf[i] != file_sector_buf[i] && file_sector_buf[i] != 0xFF)
+ must_write = 1;
+ }
+ if(0)
+ printf("sector 0x%06X-0x%06X (size %d, erase %d, write %d)\n",
+ erase_sector_addr,
+ erase_sector_addr+sector_size-1,
+ sector_size,
+ must_erase, must_write);
+ if(must_erase)
+ {
+ flash_erase_sector(erase_sector_addr, sector_size);
+ count_erase++;
+ }
+ const uint32_t page_program_size = 256; // up to this bytes max in one page write operation
+ if(must_write)
+ {
+ for(int i = 0; i < sector_size; i += page_program_size)
+ flash_write(file_sector_buf + i, erase_sector_addr + i, page_program_size);
+ count_write++;
+ }
+ // verify
+ flash_read(flash_sector_buf, erase_sector_addr, sector_size);
+ int verify_fail = memcmp(flash_sector_buf, file_sector_buf, sector_size);
+ if(verify_fail)
+ continue; // jumps to new while iteration without update of addr and bytes written
+ bytes_written += data_bytes_to_write; // not correct but OK for now
+ addr += data_bytes_to_write;
+ print_progress_bar(bytes_written, length);
+ retries_remaining = retry; // if we get this far, we are successful and set retry counter
+ }
+ printf("\n"); // after progress bar to new line
+ if(retries_remaining == 0)
+ {
+ fprintf(stderr, "FAIL\n");
+ return -1;
+ }
+ printf("4K sectors erased:%d written:%d\n", count_erase, count_write);
+ return 0;
+}
+
+
+void close_usb_device(void)
+{
+ printf("aaaa\n");
+ if(interface_claimed)
+ {
+ libusb_release_interface(device_handle, 0);
+ interface_claimed = 0;
+ }
+ if(libusb_initialized)
+ {
+ libusb_exit(NULL);
+ libusb_initialized = 0;
+ }
+}
+
+int open_usb_device(uint16_t vid, uint16_t pid)
+{
+ int r = libusb_init(NULL);
+ if (r < 0)
+ {
+ fprintf(stderr, "Cannot init libusb\n");
+ close_usb_device();
+ return -1;
+ }
+ libusb_initialized = 1;
+
+ device_handle = libusb_open_device_with_vid_pid(NULL, vid, pid);
+ if (!device_handle)
+ {
+ fprintf(stderr, "Error finding USB device %04X:%04X\n", vid, pid);
+ return -1;
+ }
+
+#if 1
+ int rc;
+ rc = libusb_claim_interface(device_handle, 0);
+ if (rc < 0)
+ {
+ fprintf(stderr, "Error claiming interface: %s\n", libusb_error_name(rc));
+ return -1;
+ }
+ interface_claimed = 1;
+#endif
+ return 0;
+}
+
+int send_one_packet()
+{
+ uint8_t buf[32];
+ buf[0] = 0xAB; // 1010 1011
+ buf[1] = 0x00;
+ buf[2] = 0x00;
+ buf[3] = 0x00;
+ for(int i = 4; i < 32; i++)
+ buf[i] = 0x00;
+ uint16_t datalen = 32;
+ uint8_t data1 = 0; // currently no use
+ uint8_t bRequest = 0; // currently no use
+ uint16_t wIndex = 0; // currently no use
+ uint16_t wValue = 0; // wValue: 0-no continuation, 1-continuation
+ uint16_t timeout_ms = 100; // 10 ms waiting for response
+
+ int response = libusb_control_transfer(device_handle, (uint8_t)(LIBUSB_ENDPOINT_OUT|LIBUSB_REQUEST_TYPE_VENDOR|data1),
+ bRequest, wValue, wIndex, buf, datalen, timeout_ms);
+
+#if 1
+ //usleep(1000000);
+
+ response = libusb_control_transfer(device_handle, (uint8_t)(LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_VENDOR|data1),
+ bRequest, wValue, wIndex, buf, datalen, timeout_ms);
+
+ print_hex_buf(buf, datalen);
+#endif
+ return response;
+}
+
+
+int test_read(uint32_t addr, uint32_t len)
+{
+ uint8_t *buf; // buffer 64K
+ buf = (uint8_t *)malloc(len * sizeof(uint8_t));
+ flash_read(buf, addr, len); // read complete buffer from flash address 0
+
+ // print start of the buffer
+ printf("address 0x%06X length %d\n", addr, len);
+ print_hex_buf(buf, len);
+ free(buf);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ cmdline_parser(argc, argv, args);
+ uint32_t usb_vid, usb_pid;
+
+ sscanf(args->device_arg, "%x:%x", &usb_vid, &usb_pid);
+
+ if(open_usb_device(usb_vid, usb_pid) < 0)
+ return -1;
+
+ printf("FLASH ID: 0x%02X\n", flash_read_id());
+
+ #if 0
+
+ uint8_t flash_status = flash_read_status(0x05);
+ printf("FLASH STATUS: 0x%02X\n", flash_status);
+
+ //usleep(1000000);
+ // test_read(0x300000); // alphabet
+ test_read(0x200000+2*1024-64, 128); // alphabet
+
+ //flash_erase_sector(0x200000, 4*1024);
+ uint32_t length = 4096;
+ uint8_t *data = (uint8_t *)malloc(length * sizeof(uint8_t));
+ for(int i = 0; i < length; i++)
+ data[i] = 0xFF & i;
+ // flash_write(data, 0x200000+2*1024, length);
+ free(data);
+ test_read(0x200000+2*1024-64, 256); // alphabet
+ #endif
+
+ if(args->read_given)
+ read_flash_write_file(args->read_arg, args->address_arg, args->length_arg);
+ if(args->write_given)
+ read_file_write_flash(args->write_arg, args->address_arg, 0);
+
+ return 0;
+}
diff --git a/programmer/tinyfpgasp/version.sh b/programmer/tinyfpgasp/version.sh
new file mode 100755
index 0000000..d1dacdb
--- /dev/null
+++ b/programmer/tinyfpgasp/version.sh
@@ -0,0 +1,2 @@
+#/!bin/sh
+grep "version" cmdline.ggo | sed -e 's/.*"\(.*\)".*/\1/'
diff --git a/programmer/tinyprog/__init__.py b/programmer/tinyprog/__init__.py
index 104eed6..f347288 100644
--- a/programmer/tinyprog/__init__.py
+++ b/programmer/tinyprog/__init__.py
@@ -167,7 +167,7 @@ def _read_metadata(self):
import math
meta_roots = (
[self._parse_json(self.prog.read_security_register_page(p).replace(b"\x00", b"").replace(b"\xff", b"")) for p in [1, 2, 3]] +
- [self._parse_json(self.prog.read(int(math.pow(2, p) - (4 * 1024)), (4 * 1024)).replace(b"\x00", b"").replace(b"\xff", b"")) for p in [17, 18, 19, 20, 21, 22, 23, 24]]
+ [self._parse_json(self.prog.read(int(math.pow(2, p) - (4 * 1024)), (4 * 1024) - 256).replace(b"\x00", b"").replace(b"\xff", b"")) for p in [17, 18, 19, 20, 21, 22, 23, 24]]
)
meta_roots = [root for root in meta_roots if root is not None]
if len(meta_roots) > 0:
@@ -273,11 +273,14 @@ def read(self, addr, length, disable_progress=True):
with tqdm(desc=" Reading", unit="B", unit_scale=True, total=length, disable=disable_progress) as pbar:
while length > 0:
read_length = min(255, length)
- data += self.cmd(0x0b, addr, b'\x00', read_len=read_length)
- self.progress(read_length)
- addr += read_length
- length -= read_length
- pbar.update(read_length)
+ read_payload = self.cmd(0x0b, addr, b'\x00', read_len=read_length)
+ payload_length = len(read_payload)
+ if payload_length > 0:
+ data += read_payload
+ self.progress(payload_length)
+ addr += payload_length
+ length -= payload_length
+ pbar.update(payload_length)
return data
def write_enable(self):
@@ -301,12 +304,32 @@ def _erase(self, addr, length):
self.wait_while_busy()
def erase(self, addr, length, disable_progress=True):
+ return self.program_sectors(addr, length, disable_progress)
+
+ # for each sector: erase,program,verify
+ # this programming is much more reliable than previous program()
+ # because each written sector will be verified and in case of
+ # error, retried several times
+ # if integer value is passed to data, this will erase that much bytes
+ def program_sectors(self, addr, data, disable_progress=True, verify_only=False, retry=10):
possible_lengths = (1, 4 * 1024, 32 * 1024, 64 * 1024)
-
- with tqdm(desc=" Erasing", unit="B", unit_scale=True, total=length, disable=disable_progress) as pbar:
- while length > 0:
+ retries_remaining = retry
+ data_enable = False
+ description = " Erasing"
+ try:
+ if len(data) > 0:
+ length = len(data)
+ description = " Writing"
+ data_enable = True
+ except:
+ length = data # probably integer = number of bytes to erase
+ offset = 0
+ write_addr = addr + offset
+ if verify_only == False:
+ with tqdm(desc=description, unit="B", unit_scale=True, total=length, disable=disable_progress) as pbar:
+ while length > 0 and retries_remaining > 0:
erase_length = max(p for p in possible_lengths
- if p <= length and addr % p == 0)
+ if p <= length and write_addr % p == 0)
if erase_length == 1:
# there are no opcode to erase that much
@@ -320,8 +343,8 @@ def erase(self, addr, length, disable_progress=True):
# +------------------+------------------+----------------+
# <- start_length -> <- erase_length -> <- end_length ->
- start_addr = addr & 0xfff000
- start_length = addr & 0xfff
+ start_addr = write_addr & 0xfff000
+ start_length = write_addr & 0xfff
erase_length = min(0x1000 - start_length, length)
end_addr = start_addr + start_length + erase_length
end_length = start_addr + 0x1000 - end_addr
@@ -344,12 +367,38 @@ def erase(self, addr, length, disable_progress=True):
else:
# there is an opcode to erase that much data
self.progress(erase_length)
- self._erase(addr, erase_length)
+ self._erase(write_addr, erase_length)
+
+ if data_enable:
+ # write part of the data into erased place
+ write_data = data[offset : offset + erase_length]
+ self.write(write_addr, write_data)
+ read_back = self.read(write_addr, erase_length)
+ else:
+ # forces retry compare to succeed
+ # todo: compare erased sector against 0xFF
+ write_data = None
+ read_back = None
# update
- length -= erase_length
- addr += erase_length
- pbar.update(erase_length)
+ if read_back == write_data:
+ length -= erase_length
+ write_addr += erase_length
+ offset += erase_length
+ retries_remaining = retry
+ pbar.update(erase_length)
+ else:
+ retries_remaining -= 1
+
+ if data_enable:
+ read_back = self.read(addr, len(data), disable_progress=disable_progress)
+
+ if read_back == data:
+ self.progress("Success!")
+ return True
+ else:
+ self.progress("Failure!")
+ return False
# don't use this directly, use the public "write" function instead
def _write(self, addr, data):
@@ -416,4 +465,4 @@ def program_bitstream(self, addr, bitstream):
self.progress("Waking up SPI flash")
self.wake()
self.progress(str(len(bitstream)) + " bytes to program")
- return self.program(addr, bitstream)
+ return self.program_sectors(addr, bitstream, disable_progress=False)
diff --git a/programmer/tinyprog/__main__.py b/programmer/tinyprog/__main__.py
index 4b6cf57..1f3d7dd 100644
--- a/programmer/tinyprog/__main__.py
+++ b/programmer/tinyprog/__main__.py
@@ -188,6 +188,8 @@ def parse_int(str_value):
parser.add_argument("-b", "--boot", action="store_true",
help="command the FPGA board to exit the "
"bootloader and load the user configuration")
+ parser.add_argument("--no-boot", action="store_true",
+ help="don't boot after programing")
parser.add_argument("-c", "--com", type=str, help="serial port name")
parser.add_argument("-i", "--id", type=str, help="FPGA board ID")
parser.add_argument("-d", "--device", type=str, default="1d50:6130",
@@ -331,7 +333,8 @@ def progress(info):
if not fpga.program_bitstream(addr, bitstream):
sys.exit(1)
- fpga.boot()
+ if not args.no_boot:
+ fpga.boot()
print("")
sys.exit(0)
@@ -340,7 +343,6 @@ def progress(info):
print(" Booting " + str(active_port))
with active_port:
fpga = TinyProg(active_port)
- fpga.boot()
print("")