diff --git a/.gitignore b/.gitignore index f1af15c..7614d15 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,9 @@ synlog.tcl gerbers/ build/ *.pyc +*.bit +*.json +.*.d +.*.sw* +gmon.out +*.bin diff --git a/boards/TinyFPGA_BX/Makefile b/boards/TinyFPGA_BX/Makefile index 6ea0de9..eb006a1 100644 --- a/boards/TinyFPGA_BX/Makefile +++ b/boards/TinyFPGA_BX/Makefile @@ -22,12 +22,22 @@ PKG = cm81 all: $(PROJ).rpt fw.bin +%.json: %.v ../../common/*.v + yosys -q -p 'synth_ice40 -top $(PROJ) -json $@' $^ %.blif: %.v ../../common/*.v - yosys -p 'synth_ice40 -top $(PROJ) -blif $@' $^ + yosys -q -p 'synth_ice40 -top $(PROJ) -blif $@' $^ -%.asc: $(PIN_DEF) %.blif +NO-%.asc: $(PIN_DEF) %.blif arachne-pnr -d 8k -P $(PKG) -o $@ -p $^ +%.asc: $(PIN_DEF) %.json + nextpnr-ice40 \ + --$(DEVICE) \ + --package $(PKG) \ + --asc $@ \ + --pcf $(PIN_DEF) \ + --json $(basename $@).json \ + %.bin: %.asc icepack $< $@ diff --git a/boards/TinyFPGA_BX/bootloader.v b/boards/TinyFPGA_BX/bootloader.v index bf7a601..d7d188f 100644 --- a/boards/TinyFPGA_BX/bootloader.v +++ b/boards/TinyFPGA_BX/bootloader.v @@ -20,6 +20,8 @@ module bootloader ( //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// wire clk_48mhz; + wire lock; + wire reset = !lock; SB_PLL40_CORE #( .DIVR(4'b0000), @@ -43,13 +45,18 @@ module bootloader ( .RESETB(1'b1), .BYPASS(1'b0), .LATCHINPUTVALUE(), - .LOCK(), + .LOCK(lock), .SDI(), .SDO(), .SCLK() ); + reg clk_24mhz; + reg clk_12mhz; + always @(posedge clk_48mhz) clk_24mhz = !clk_24mhz; + always @(posedge clk_24mhz) clk_12mhz = !clk_12mhz; + wire clk = clk_12mhz; // quarter speed clock //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -74,7 +81,6 @@ module bootloader ( //////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// - wire reset; wire usb_p_tx; wire usb_n_tx; wire usb_p_rx; @@ -85,6 +91,7 @@ module bootloader ( tinyfpga_bootloader tinyfpga_bootloader_inst ( .clk_48mhz(clk_48mhz), + .clk(clk), .reset(reset), .usb_p_tx(usb_p_tx), .usb_n_tx(usb_n_tx), @@ -100,44 +107,38 @@ module bootloader ( ); assign pin_pu = 1'b1; + wire usb_p_rx_io; + wire usb_n_rx_io; assign usb_p_rx = usb_tx_en ? 1'b1 : usb_p_rx_io; assign usb_n_rx = usb_tx_en ? 1'b0 : usb_n_rx_io; - SB_IO #( - .PIN_TYPE(6'b101001), - .PULLUP(1'b0), - .NEG_TRIGGER(1'b0), - .IO_STANDARD("SB_LVCMOS") - ) io_dp_I ( - .PACKAGE_PIN(pin_usbp), - .LATCH_INPUT_VALUE(1'b0), - .CLOCK_ENABLE(1'b1), - .INPUT_CLK(1'b0), - .OUTPUT_CLK(1'b0), - .OUTPUT_ENABLE(usb_tx_en), - .D_OUT_0(usb_p_tx), - .D_OUT_1(1'b0), - .D_IN_0(usb_p_rx_io), - .D_IN_1() + tristate usbn_buffer( + .pin(pin_usbn), + .enable(usb_tx_en), + .data_in(usb_n_rx_io), + .data_out(usb_n_tx) ); - SB_IO #( - .PIN_TYPE(6'b101001), - .PULLUP(1'b0), - .NEG_TRIGGER(1'b0), - .IO_STANDARD("SB_LVCMOS") - ) io_dn_I ( - .PACKAGE_PIN(pin_usbn), - .LATCH_INPUT_VALUE(1'b0), - .CLOCK_ENABLE(1'b1), - .INPUT_CLK(1'b0), - .OUTPUT_CLK(1'b0), - .OUTPUT_ENABLE(usb_tx_en), - .D_OUT_0(usb_n_tx), - .D_OUT_1(1'b0), - .D_IN_0(usb_n_rx_io), - .D_IN_1() + tristate usbp_buffer( + .pin(pin_usbp), + .enable(usb_tx_en), + .data_in(usb_p_rx_io), + .data_out(usb_p_tx) ); +endmodule - assign reset = 1'b0; +module tristate( + inout pin, + input enable, + input data_out, + output data_in +); + SB_IO #( + .PIN_TYPE(6'b1010_01) // tristatable output + ) buffer( + .PACKAGE_PIN(pin), + .OUTPUT_ENABLE(enable), + .D_IN_0(data_in), + .D_OUT_0(data_out) + ); endmodule diff --git a/boards/TinyFPGA_BX/pins.pcf b/boards/TinyFPGA_BX/pins.pcf index 2a024b7..6fa7e18 100644 --- a/boards/TinyFPGA_BX/pins.pcf +++ b/boards/TinyFPGA_BX/pins.pcf @@ -3,46 +3,46 @@ # Package: CM81 ############################################################################### -#set_io pin_1 A2 -#set_io pin_2 A1 -#set_io pin_3 B1 -#set_io pin_4 C2 -#set_io pin_5 C1 -#set_io pin_6 D2 -#set_io pin_7 D1 -#set_io pin_8 E2 -#set_io pin_9 E1 -#set_io pin_10 G2 -#set_io pin_11 H1 -#set_io pin_12 J1 -#set_io pin_13 H2 -#set_io pin_14 H9 -#set_io pin_15 D9 -#set_io pin_16 D8 -#set_io pin_17 C9 -#set_io pin_18 A9 -#set_io pin_19 B8 -#set_io pin_20 A8 -#set_io pin_21 B7 -#set_io pin_22 A7 -#set_io pin_23 B6 -#set_io pin_24 A6 -#set_io pin_25 G1 -#set_io pin_26 J3 -#set_io pin_27 J4 -#set_io pin_28 H4 -set_io pin_29_miso H7 -set_io pin_30_cs F7 -set_io pin_31_mosi G6 -set_io pin_32_sck G7 -#set_io pin_33 J8 -#set_io pin_34 G9 -#set_io pin_35 J9 -#set_io pin_36 E8 -#set_io pin_37 J2 -set_io pin_led B3 -set_io pin_usbp B4 -set_io pin_usbn A4 -set_io pin_pu A3 -set_io pin_clk B2 +set_io -nowarn pin_1 A2 +set_io -nowarn pin_2 A1 +set_io -nowarn pin_3 B1 +set_io -nowarn pin_4 C2 +set_io -nowarn pin_5 C1 +set_io -nowarn pin_6 D2 +set_io -nowarn pin_7 D1 +set_io -nowarn pin_8 E2 +set_io -nowarn pin_9 E1 +set_io -nowarn pin_10 G2 +set_io -nowarn pin_11 H1 +set_io -nowarn pin_12 J1 +set_io -nowarn pin_13 H2 +set_io -nowarn pin_14 H9 +set_io -nowarn pin_15 D9 +set_io -nowarn pin_16 D8 +set_io -nowarn pin_17 C9 +set_io -nowarn pin_18 A9 +set_io -nowarn pin_19 B8 +set_io -nowarn pin_20 A8 +set_io -nowarn pin_21 B7 +set_io -nowarn pin_22 A7 +set_io -nowarn pin_23 B6 +set_io -nowarn pin_24 A6 +set_io -nowarn pin_25 G1 +set_io -nowarn pin_26 J3 +set_io -nowarn pin_27 J4 +set_io -nowarn pin_28 H4 +set_io -nowarn pin_29_miso H7 +set_io -nowarn pin_30_cs F7 +set_io -nowarn pin_31_mosi G6 +set_io -nowarn pin_32_sck G7 +set_io -nowarn pin_33 J8 +set_io -nowarn pin_34 G9 +set_io -nowarn pin_35 J9 +set_io -nowarn pin_36 E8 +set_io -nowarn pin_37 J2 +set_io -nowarn pin_led B3 +set_io -nowarn pin_usbp B4 +set_io -nowarn pin_usbn A4 +set_io -nowarn pin_pu A3 +set_io -nowarn pin_clk B2 diff --git a/boards/ULX3S/Makefile b/boards/ULX3S/Makefile new file mode 100644 index 0000000..9cdde35 --- /dev/null +++ b/boards/ULX3S/Makefile @@ -0,0 +1,59 @@ +# +# Bootloader for the ulx3s ECP5 board +# Builds with nextpnr-ecp5 and prjtrellis from git as of 2019-07-05 +# +IDCODE ?= 0x21111043 # 12f + +all: fw.bin + +flash: fw.bin bootloader.bit + @echo "-- Plug in both USB ports on the ecp5 --" + ujprog bootloader.bit + sleep 2 + tinyprog -a 1 --security boardmeta.json + tinyprog -a 2 --security bootmeta.json + tinyprog -a 0 --program-image fw.bin + sleep 5 + tinyprog -m + +fw.bin: bootloader.bit + ecpmulti \ + --input-idcode 0x41111043 \ + --output-idcode $(IDCODE) \ + -v \ + --output $@ \ + --flashsize 128 \ + --input $< \ + --address 0x100000 \ + --input $< + + +%.json: %.v + yosys \ + -p "read_verilog -I../../common $<" \ + -p "synth_ecp5 -json $@" \ + -E .$(basename $@).d \ + -q \ + +%.config: %.json + nextpnr-ecp5 \ + --json $< \ + --textcfg $@ \ + --lpf ulx3s_v20.lpf \ + --timing-allow-fail \ + --25k + +%.bit: %.config + ecppack --idcode $(IDCODE) $< $@ + +%.svf: %.config + ecppack --idcode $(IDCODE) --input $< --svf $@ + +%.flash: %.bit + ujprog $< +%.terminal: %.bit + ujprog -t -b 3000000 $< + +clean: + $(RM) *.config *.bit .*.d *.svf +-include .*.d diff --git a/boards/ULX3S/README.md b/boards/ULX3S/README.md new file mode 100644 index 0000000..c377e32 --- /dev/null +++ b/boards/ULX3S/README.md @@ -0,0 +1,23 @@ +ULX3S ECP5 FPGA +--- + +To bootstrap the bootloader: + +* `make` should build `bootloader.bit` +* Connect both USB ports `US1` and `US2` to the computer +* `sudo ujprog bootloader.bit` will load it into the FPGA SRAM via US1 +* The TinyFPGA bootloader should enumerate as `/dev/ttyACM0` via US2 +* Load the security pages into the SPI flash SFDP pages: +``` +sudo tinyprog -a 1 --security boardmeta.json +sudo tinyprog -a 2 --security bootmeta.json +``` +* `tinyprog -m` should now show the meta data +* `tinyprog -a 0 --program-image fw.bin` should write the multiboot image into the flash +* Disconnect both the USB ports and reconnect just US2. +* The bootloader should be running and flashing LED0, and show up again as `/dev/ttyACM0` +* Load your own user image with `tinyprog -p userimage.bit` + +---- + +Maybe that no longer works? Had to write the diff --git a/boards/ULX3S/boardmeta.json b/boards/ULX3S/boardmeta.json new file mode 100644 index 0000000..f7d7d42 --- /dev/null +++ b/boards/ULX3S/boardmeta.json @@ -0,0 +1,6 @@ +{"boardmeta":{ + "name": "ULX3S", + "fpga": "ecp5-12f", + "hver": "1.0.0", + "serial": 31415 +}} diff --git a/boards/ULX3S/bootloader.v b/boards/ULX3S/bootloader.v new file mode 100644 index 0000000..24d3482 --- /dev/null +++ b/boards/ULX3S/bootloader.v @@ -0,0 +1,123 @@ +`default_nettype none +`include "tinyfpga_bootloader.v" +`include "edge_detect.v" +`include "strobe.v" +`include "usb_fs_pe.v" +`include "usb_fs_in_arb.v" +`include "usb_fs_in_pe.v" +`include "usb_fs_out_arb.v" +`include "usb_fs_out_pe.v" +`include "usb_fs_rx.v" +`include "usb_fs_tx.v" +`include "usb_fs_tx_mux.v" +`include "usb_reset_det.v" +`include "usb_serial_ctrl_ep.v" +`include "usb_spi_bridge_ep.v" +`include "pll_132.v" +`include "pll_48.v" + + +module top( + input clk_25mhz, + output [7:0] led, + output wifi_gpio0, + + //input ftdi_txd, // from the ftdi chip + //output ftdi_rxd, // to the ftdi chip + + // USB port directly wired to serial port + inout usb_fpga_bd_dn, + inout usb_fpga_bd_dp, + output usb_fpga_pu_dp, + output usb_fpga_pu_dn, + + // onboard SPI flash + output flash_csn, + //output flash_clk, // special - see USRMCLK below + output flash_mosi, + input flash_miso, + output flash_holdn, + output flash_wpn, + + // select a reboot from the user space on the flash + output user_programn +); + // avoid reboot? + assign wifi_gpio0 = 1; + + // 25 MHz input clock, 132 MHz output + wire clk_132mhz, clk_48mhz; + wire locked; + wire reset = !locked; + pll_132 pll_132_i(.clkin(clk_25mhz), .clkout0(clk_132mhz), .locked(locked)); + pll_48 pll_48_i(clk_132mhz, clk_48mhz); + + // configure as a full speed device (pull up on dp) + assign usb_fpga_pu_dp = 1; // full speed 1.1 device + assign usb_fpga_pu_dn = 0; // full speed 1.1 device + wire usb_tx_en; + wire usb_n_in, usb_n_out; + wire usb_p_in, usb_p_out; + + TRELLIS_IO #(.DIR("BIDIR")) usb_p_buf( + .T(!usb_tx_en), + .B(usb_fpga_bd_dp), + .I(usb_p_out), + .O(usb_p_in), + ); + TRELLIS_IO #(.DIR("BIDIR")) usb_n_buf( + .T(!usb_tx_en), + .B(usb_fpga_bd_dn), + .I(usb_n_out), + .O(usb_n_in), + ); + + // ensure that the flash aux pins are in a stable state + // and allow flash updates + assign flash_holdn = 1; + assign flash_wpn = 1; + + // the U3 pin on the package is special and requires magic to drive it + wire flash_clk; + wire flash_csn_i; // needs to be a wire? + assign flash_csn = flash_csn_i; + USRMCLK usrmclk_inst ( + .USRMCLKI(flash_clk), + .USRMCLKTS(flash_csn_i) + ) /* synthesis syn_noprune=1 */; + + + wire boot; + + tinyfpga_bootloader tinyfgpa_bootloader_inst( + .clk_48mhz(clk_48mhz), + .clk(clk_132mhz), + .reset(reset), + .usb_p_tx(usb_p_out), + .usb_n_tx(usb_n_out), + .usb_p_rx(usb_tx_en ? 1'b1 : usb_p_in), + .usb_n_rx(usb_tx_en ? 1'b0 : usb_n_in), + .usb_tx_en(usb_tx_en), + .led(led[0]), + .spi_miso(flash_miso), + .spi_cs(flash_csn_i), + .spi_mosi(flash_mosi), + .spi_sck(flash_clk), + .boot(boot) + ); + + reg initiate_boot = 0; + reg [8:0] boot_delay = 0; + + assign user_programn = ~boot_delay[8]; // initiate user program + assign led[7:1] = 0; + + always @(posedge clk_132mhz) begin + if (boot) + initiate_boot <= 1; + + if (initiate_boot) begin + boot_delay <= boot_delay + 1'b1; + end + end +endmodule diff --git a/boards/ULX3S/bootmeta.json b/boards/ULX3S/bootmeta.json new file mode 100644 index 0000000..04d94be --- /dev/null +++ b/boards/ULX3S/bootmeta.json @@ -0,0 +1,10 @@ +{"bootmeta":{ +"bootloader":"TinyFPGA USB Bootloader", +"bver":"2.0.0", +"update":"https://tinyfpga.com/update/ulx3s", +"addrmap":{ +"bootloader":"0x0-0xFFFFF", +"userimage":"0x100000-0x1EFFFF", +"userdata":"0x200000-0xFFFFFF", +"desc.tgz":"0x1F0000-0x1FFFFF" +}}} diff --git a/boards/ULX3S/pll_132.v b/boards/ULX3S/pll_132.v new file mode 100644 index 0000000..8f49422 --- /dev/null +++ b/boards/ULX3S/pll_132.v @@ -0,0 +1,46 @@ +module pll_132 +( + input clkin, // 25 MHz, 0 deg + output clkout0, // 132.143 MHz, 0 deg + output clkout1, // 132.143 MHz, 180 deg + output locked +); +wire clkfb; +wire clkos; +wire clkop; +(* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *) +EHXPLLL #( + .PLLRST_ENA("DISABLED"), + .INTFB_WAKE("DISABLED"), + .STDBY_ENABLE("DISABLED"), + .DPHASE_SOURCE("DISABLED"), + .CLKOP_FPHASE(0), + .CLKOP_CPHASE(2), + .OUTDIVIDER_MUXA("DIVA"), + .CLKOP_ENABLE("ENABLED"), + .CLKOP_DIV(5), + .CLKOS_ENABLE("ENABLED"), + .CLKOS_DIV(5), + .CLKOS_CPHASE(4), + .CLKOS_FPHASE(4), + .CLKFB_DIV(37), + .CLKI_DIV(7), + .FEEDBK_PATH("INT_OP") + ) pll_i ( + .CLKI(clkin), + .CLKFB(clkfb), + .CLKINTFB(clkfb), + .CLKOP(clkop), + .CLKOS(clkout1), + .RST(1'b0), + .STDBY(1'b0), + .PHASESEL0(1'b0), + .PHASESEL1(1'b0), + .PHASEDIR(1'b0), + .PHASESTEP(1'b0), + .PLLWAKESYNC(1'b0), + .ENCLKOP(1'b0), + .LOCK(locked) + ); +assign clkout0 = clkop; +endmodule diff --git a/boards/ULX3S/pll_48.v b/boards/ULX3S/pll_48.v new file mode 100644 index 0000000..8d5df70 --- /dev/null +++ b/boards/ULX3S/pll_48.v @@ -0,0 +1,40 @@ +module pll_48 +( + input clkin, // 132 MHz, 0 deg + output clkout0, // 48 MHz, 0 deg + output locked +); +wire clkfb; +wire clkos; +wire clkop; +(* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *) +EHXPLLL #( + .PLLRST_ENA("DISABLED"), + .INTFB_WAKE("DISABLED"), + .STDBY_ENABLE("DISABLED"), + .DPHASE_SOURCE("DISABLED"), + .CLKOP_FPHASE(0), + .CLKOP_CPHASE(5), + .OUTDIVIDER_MUXA("DIVA"), + .CLKOP_ENABLE("ENABLED"), + .CLKOP_DIV(12), + .CLKFB_DIV(4), + .CLKI_DIV(11), + .FEEDBK_PATH("INT_OP") + ) pll_i ( + .CLKI(clkin), + .CLKFB(clkfb), + .CLKINTFB(clkfb), + .CLKOP(clkop), + .RST(1'b0), + .STDBY(1'b0), + .PHASESEL0(1'b0), + .PHASESEL1(1'b0), + .PHASEDIR(1'b0), + .PHASESTEP(1'b0), + .PLLWAKESYNC(1'b0), + .ENCLKOP(1'b0), + .LOCK(locked) + ); +assign clkout0 = clkop; +endmodule diff --git a/boards/ULX3S/ulx3s_v20.lpf b/boards/ULX3S/ulx3s_v20.lpf new file mode 100644 index 0000000..310e231 --- /dev/null +++ b/boards/ULX3S/ulx3s_v20.lpf @@ -0,0 +1,462 @@ +BLOCK RESETPATHS; +BLOCK ASYNCPATHS; +## ULX3S v2.x.x and v3.0.x + +# 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 +# write to FLASH possible any time from JTAG: +#SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 MASTER_SPI_PORT=ENABLE SLAVE_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE; +# write to FLASH possible from user bitstream: +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 +LOCATE COMP "btn[4]" SITE "V1"; # DOWN +LOCATE COMP "btn[5]" SITE "U1"; # LEFT +LOCATE COMP "btn[6]" SITE "H16"; # RIGHT +IOBUF PORT "btn[0]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "btn[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33; +IOBUF PORT "btn[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33; +IOBUF PORT "btn[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33; +IOBUF PORT "btn[4]" PULLMODE=DOWN IO_TYPE=LVCMOS33; +IOBUF PORT "btn[5]" PULLMODE=DOWN IO_TYPE=LVCMOS33; +IOBUF PORT "btn[6]" PULLMODE=DOWN IO_TYPE=LVCMOS33; + +## 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; +IOBUF PORT "sw[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33; +IOBUF PORT "sw[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33; +IOBUF PORT "sw[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33; + +## 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_holdn" SITE "W1"; +LOCATE COMP "flash_wpn" SITE "Y2"; +#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=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_mosi" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_miso" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_holdn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_wpn" PULLMODE=NONE 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=UP 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 +# Output impedance 75 ohm. +# Strong enough to drive 16 ohm earphones. +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=16; +IOBUF PORT "audio_l[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_l[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_l[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_r[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_r[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_r[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_r[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_v[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_v[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_v[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_v[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; + +## 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_gpio5" PULLMODE=NONE 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=LVCMOS33D DRIVE=16; +IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=16; +LOCATE COMP "usb_fpga_bd_dp" SITE "D15"; # single-ended bidirectional +LOCATE COMP "usb_fpga_bd_dn" SITE "E15"; +IOBUF PORT "usb_fpga_bd_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "usb_fpga_bd_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 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 +# Physical connector pins: +# *** when FEMALE ANGLED (90 deg PMOD) soldered *** +# Jm_n- = Jm_n, Jm_n+ = Jm_n+1 +# example: J1_5- is J1_5 phsyical, J1_5+ is J1_6 physical +# *** when MALE VERTICAL soldered *** +# Jm_n+ = Jm_n, Jm_n- = Jm_n+1 +# example: J1_5+ is J1_5 physical, J1_5- is J1_6 physical +# 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 +# To enable clock i/o, add this (example): +#FREQUENCY PORT "gp[12]" 25.00 MHZ; +LOCATE COMP "gp[0]" SITE "B11"; # J1_5+ GP0 PCLK +LOCATE COMP "gn[0]" SITE "C11"; # J1_5- GN0 PCLK +LOCATE COMP "gp[1]" SITE "A10"; # J1_7+ GP1 PCLK +LOCATE COMP "gn[1]" SITE "A11"; # J1_7- GN1 PCLK +LOCATE COMP "gp[2]" SITE "A9"; # J1_9+ GP2 GR_PCLK +LOCATE COMP "gn[2]" SITE "B10"; # J1_9- GN2 GR_PCLK +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 DIFF +LOCATE COMP "gp[9]" SITE "A2"; # J1_27+ GP9 DIFF +LOCATE COMP "gn[9]" SITE "B1"; # J1_27- GN9 DIFF +LOCATE COMP "gp[10]" SITE "C4"; # J1_29+ GP10 DIFF +LOCATE COMP "gn[10]" SITE "B4"; # J1_29- GN10 DIFF +LOCATE COMP "gp[11]" SITE "F4"; # J1_31+ GP11 DIFF WIFI_GPIO26 +LOCATE COMP "gn[11]" SITE "E3"; # J1_31- GN11 DIFF WIFI_GPIO25 +LOCATE COMP "gp[12]" SITE "G3"; # J1_33+ GP12 DIFF WIFI_GPIO33 PCLK +LOCATE COMP "gn[12]" SITE "F3"; # J1_33- GN12 DIFF WIFI_GPIO32 PCLK +LOCATE COMP "gp[13]" SITE "H4"; # J1_35+ GP13 DIFF WIFI_GPIO35 +LOCATE COMP "gn[13]" SITE "G5"; # J1_35- GN13 DIFF WIFI_GPIO34 +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 DIFF ADC1 +LOCATE COMP "gn[14]" SITE "U17"; # J2_5- GN14 DIFF ADC0 +LOCATE COMP "gp[15]" SITE "N17"; # J2_7+ GP15 DIFF ADC3 +LOCATE COMP "gn[15]" SITE "P16"; # J2_7- GN15 DIFF ADC2 +LOCATE COMP "gp[16]" SITE "N16"; # J2_9+ GP16 DIFF ADC5 +LOCATE COMP "gn[16]" SITE "M17"; # J2_9- GN16 DIFF ADC4 +LOCATE COMP "gp[17]" SITE "L16"; # J2_11+ GP17 DIFF ADC7 GR_PCLK +LOCATE COMP "gn[17]" SITE "L17"; # J2_11- GN17 DIFF ADC6 +LOCATE COMP "gp[18]" SITE "H18"; # J2_13+ GP18 DIFF +LOCATE COMP "gn[18]" SITE "H17"; # J2_13- GN18 DIFF +LOCATE COMP "gp[19]" SITE "F17"; # J2_15+ GP19 DIFF +LOCATE COMP "gn[19]" SITE "G18"; # J2_15- GN19 DIFF +LOCATE COMP "gp[20]" SITE "D18"; # J2_17+ GP20 DIFF +LOCATE COMP "gn[20]" SITE "E17"; # J2_17- GN20 DIFF +IOBUF PORT "gp[14]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[14]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[15]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[15]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[16]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[16]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[17]" IO_TYPE=LVCMOS33 SLEWRATE=FAST ; // MISO +IOBUF PORT "gn[17]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[18]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[18]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[19]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[19]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[20]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[20]" PULLMODE=UP IO_TYPE=LVCMOS33; +LOCATE COMP "gp[21]" SITE "C18"; # J2_23+ GP21 DIFF +LOCATE COMP "gn[21]" SITE "D17"; # J2_23- GN21 DIFF +LOCATE COMP "gp[22]" SITE "B15"; # J2_25+ GP22 +LOCATE COMP "gn[22]" SITE "C15"; # 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 "D14"; # J2_31+ GP25 +LOCATE COMP "gn[25]" SITE "E14"; # 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; +IOBUF PORT "gn[21]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[22]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[22]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[23]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[23]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[24]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[24]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[25]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[25]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[26]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[26]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[27]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[27]" PULLMODE=UP IO_TYPE=LVCMOS33; + +## 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/common/strobe.v b/common/strobe.v new file mode 100644 index 0000000..2791ad9 --- /dev/null +++ b/common/strobe.v @@ -0,0 +1,53 @@ +module strobe( + input clk_in, + input clk_out, + input strobe_in, + output strobe_out, + input [WIDTH-1:0] data_in, + output [WIDTH-1:0] data_out +); + parameter WIDTH = 1; + parameter DELAY = 2; // 2 for metastability, larger for testing + +`define CLOCK_CROSS +`ifdef CLOCK_CROSS + reg flag; + reg prev_strobe; + reg [DELAY:0] sync; + reg [WIDTH-1:0] data; + + // flip the flag and clock in the data when strobe is high + always @(posedge clk_in) begin + //if ((strobe_in && !prev_strobe) + //|| (!strobe_in && prev_strobe)) + flag <= flag ^ strobe_in; + + if (strobe_in) + data <= data_in; + + prev_strobe <= strobe_in; + end + + // shift through a chain of flipflop to ensure stability + always @(posedge clk_out) + sync <= { sync[DELAY-1:0], flag }; + + assign strobe_out = sync[DELAY] ^ sync[DELAY-1]; + assign data_out = data; +`else + assign strobe_out = strobe_in; + assign data_out = data_in; +`endif +endmodule + + +module dflip( + input clk, + input in, + output out +); + reg [2:0] d; + always @(posedge clk) + d <= { d[1:0], in }; + assign out = d[2]; +endmodule diff --git a/common/tinyfpga_bootloader.v b/common/tinyfpga_bootloader.v index 578ca22..7b43ee3 100644 --- a/common/tinyfpga_bootloader.v +++ b/common/tinyfpga_bootloader.v @@ -1,5 +1,6 @@ module tinyfpga_bootloader ( input clk_48mhz, + input clk, input reset, // USB lines. Split into input vs. output and oe control signal to maintain @@ -26,6 +27,7 @@ module tinyfpga_bootloader ( // function. output boot ); + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////// @@ -38,7 +40,7 @@ module tinyfpga_bootloader ( reg [5:0] ns_cnt = 0; wire ns_rst = (ns_cnt == 48); - always @(posedge clk_48mhz) begin + always @(posedge clk) begin if (ns_rst) begin ns_cnt <= 0; end else begin @@ -48,7 +50,7 @@ module tinyfpga_bootloader ( reg [9:0] us_cnt = 0; wire us_rst = (us_cnt == 1000); - always @(posedge clk_48mhz) begin + always @(posedge clk) begin if (us_rst) begin us_cnt <= 0; end else if (ns_rst) begin @@ -57,7 +59,7 @@ module tinyfpga_bootloader ( end reg count_down = 0; - always @(posedge clk_48mhz) begin + always @(posedge clk) begin if (us_rst) begin if (count_down) begin if (led_pwm == 0) begin @@ -74,11 +76,10 @@ module tinyfpga_bootloader ( end end end - always @(posedge clk_48mhz) pwm_cnt <= pwm_cnt + 1'b1; + always @(posedge clk) pwm_cnt <= pwm_cnt + 1'b1; assign led = led_pwm > pwm_cnt; - //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////// @@ -136,7 +137,7 @@ module tinyfpga_bootloader ( assign boot = host_presence_timeout || boot_to_user_design; usb_serial_ctrl_ep ctrl_ep_inst ( - .clk(clk_48mhz), + .clk(clk), .reset(reset), .dev_addr(dev_addr), @@ -163,7 +164,7 @@ module tinyfpga_bootloader ( ); usb_spi_bridge_ep usb_spi_bridge_ep_inst ( - .clk(clk_48mhz), + .clk(clk), .reset(reset), // out endpoint interface @@ -204,7 +205,8 @@ module tinyfpga_bootloader ( .NUM_OUT_EPS(5'd2), .NUM_IN_EPS(5'd3) ) usb_fs_pe_inst ( - .clk(clk_48mhz), + .clk_48mhz(clk_48mhz), + .clk(clk), .reset(reset), .usb_p_tx(usb_p_tx), @@ -246,7 +248,7 @@ module tinyfpga_bootloader ( // host presence detection //////////////////////////////////////////////////////////////////////////////// - always @(posedge clk_48mhz) begin + always @(posedge clk) begin if (sof_valid) begin host_presence_timer <= 0; host_presence_timeout <= 0; @@ -258,4 +260,4 @@ module tinyfpga_bootloader ( host_presence_timeout <= 1; end end -endmodule \ No newline at end of file +endmodule diff --git a/common/usb_fs_in_pe.v b/common/usb_fs_in_pe.v index 16b9faf..4ce36a7 100644 --- a/common/usb_fs_in_pe.v +++ b/common/usb_fs_in_pe.v @@ -100,9 +100,9 @@ module usb_fs_in_pe #( integer i = 0; initial begin for (i = 0; i < NUM_IN_EPS; i = i + 1) begin - ep_put_addr[i] = 0; - ep_get_addr[i] = 0; - ep_state[i] = 0; + ep_put_addr[i] <= 0; + ep_get_addr[i] <= 0; + ep_state[i] <= 0; end end @@ -400,4 +400,4 @@ module usb_fs_in_pe #( end end -endmodule \ No newline at end of file +endmodule diff --git a/common/usb_fs_out_pe.v b/common/usb_fs_out_pe.v index 26d0802..dba7112 100644 --- a/common/usb_fs_out_pe.v +++ b/common/usb_fs_out_pe.v @@ -287,7 +287,6 @@ module usb_fs_out_pe #( if (out_token_received || setup_token_received) begin out_xfr_state_next <= RCVD_OUT; out_xfr_start <= 1; - end else begin out_xfr_state_next <= IDLE; end @@ -296,7 +295,6 @@ module usb_fs_out_pe #( RCVD_OUT : begin if (rx_pkt_start) begin out_xfr_state_next <= RCVD_DATA_START; - end else begin out_xfr_state_next <= RCVD_OUT; end @@ -410,4 +408,4 @@ module usb_fs_out_pe #( end end -endmodule \ No newline at end of file +endmodule diff --git a/common/usb_fs_pe.v b/common/usb_fs_pe.v index dadb719..dee04c6 100644 --- a/common/usb_fs_pe.v +++ b/common/usb_fs_pe.v @@ -2,10 +2,10 @@ module usb_fs_pe #( parameter [4:0] NUM_OUT_EPS = 1, parameter [4:0] NUM_IN_EPS = 1 ) ( + input clk_48mhz, input clk, input [6:0] dev_addr, - //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// USB Endpoint Interface @@ -187,7 +187,8 @@ module usb_fs_pe #( ); usb_fs_rx usb_fs_rx_inst ( - .clk_48mhz(clk), + .clk_48mhz(clk_48mhz), + .clk(clk), .reset(reset), .dp(usb_p_rx), .dn(usb_n_rx), @@ -218,7 +219,8 @@ module usb_fs_pe #( ); usb_fs_tx usb_fs_tx_inst ( - .clk_48mhz(clk), + .clk_48mhz(clk_48mhz), + .clk(clk), .reset(reset), .bit_strobe(bit_strobe), .oe(usb_tx_en), @@ -231,4 +233,4 @@ module usb_fs_pe #( .tx_data_get(tx_data_get), .tx_data(tx_data) ); -endmodule \ No newline at end of file +endmodule diff --git a/common/usb_fs_rx.v b/common/usb_fs_rx.v index 8c73f68..ab9c73c 100644 --- a/common/usb_fs_rx.v +++ b/common/usb_fs_rx.v @@ -1,36 +1,39 @@ module usb_fs_rx ( // A 48MHz clock is required to recover the clock from the incoming data. input clk_48mhz, + input clk, input reset, - // USB data+ and data- lines. + // USB data+ and data- lines (clk_48mhz domain) input dp, input dn, - // pulse on every bit transition. + // pulse on every bit transition (clk_48mhz domain) output bit_strobe, - // Pulse on beginning of new packet. + // Pulse on beginning of new packet (clk domain) output pkt_start, - // Pulse on end of current packet. + // Pulse on end of current packet (clk domain) output pkt_end, - // Most recent packet decoded. + // Most recent packet decoded (clk domain) output [3:0] pid, - output reg [6:0] addr = 0, - output reg [3:0] endp = 0, - output reg [10:0] frame_num = 0, + output [6:0] addr, + output [3:0] endp, + output [10:0] frame_num, - // Pulse on valid data on rx_data. + // Pulse on valid data on rx_data (clk domain) output rx_data_put, output [7:0] rx_data, - // Most recent packet passes PID and CRC checks + // Most recent packet passes PID and CRC checks (clk domain) output valid_packet ); - wire clk = clk_48mhz; - + wire [3:0] pid_48; + reg [6:0] addr_48; + reg [3:0] endp_48; + reg [10:0] frame_num_48; //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////// @@ -51,7 +54,7 @@ module usb_fs_rx ( reg [3:0] dpair_q = 0; - always @(posedge clk) begin + always @(posedge clk_48mhz) begin dpair_q[3:0] <= {dpair_q[1:0], dp, dn}; end @@ -78,7 +81,7 @@ module usb_fs_rx ( wire [1:0] dpair = dpair_q[3:2]; - always @(posedge clk) begin + always @(posedge clk_48mhz) begin case (line_state) // if we are in a transition state, then we can sample the pair and // move to the next corresponding line state @@ -122,7 +125,7 @@ module usb_fs_rx ( wire line_state_valid = (bit_phase == 1); assign bit_strobe = (bit_phase == 2); - always @(posedge clk) begin + always @(posedge clk_48mhz) begin // keep track of phase within each bit if (line_state == DT) begin bit_phase <= 0; @@ -165,7 +168,7 @@ module usb_fs_rx ( end end - always @(posedge clk) begin + always @(posedge clk_48mhz) begin if (reset) begin line_history <= 6'b101010; packet_valid <= 0; @@ -214,7 +217,7 @@ module usb_fs_rx ( reg [5:0] bitstuff_history = 0; - always @(posedge clk) begin + always @(posedge clk_48mhz) begin if (reset || packet_end) begin bitstuff_history <= 6'b000000; end else begin @@ -224,7 +227,7 @@ module usb_fs_rx ( end end - assign dvalid = dvalid_raw && !(bitstuff_history == 6'b111111); + wire dvalid = dvalid_raw && !(bitstuff_history == 6'b111111); //////////////////////////////////////////////////////////////////////////////// @@ -237,7 +240,7 @@ module usb_fs_rx ( wire pid_valid = full_pid[4:1] == ~full_pid[8:5]; wire pid_complete = full_pid[0]; - always @(posedge clk) begin + always @(posedge clk_48mhz) begin if (packet_start) begin full_pid <= 9'b100000000; end @@ -253,7 +256,7 @@ module usb_fs_rx ( reg [4:0] crc5 = 0; wire crc5_valid = crc5 == 5'b01100; wire crc5_invert = din ^ crc5[4]; - always @(posedge clk) begin + always @(posedge clk_48mhz) begin if (packet_start) begin crc5 <= 5'b11111; end @@ -274,7 +277,7 @@ module usb_fs_rx ( wire crc16_valid = crc16 == 16'b1000000000001101; wire crc16_invert = din ^ crc16[15]; - always @(posedge clk) begin + always @(posedge clk_48mhz) begin if (packet_start) begin crc16 <= 16'b1111111111111111; end @@ -309,17 +312,19 @@ module usb_fs_rx ( // TODO: need to check for data packet babble // TODO: do i need to check for bitstuff error? - assign valid_packet = pid_valid && ( + wire valid_packet_48 = pid_valid && ( (pkt_is_handshake) || (pkt_is_data && crc16_valid) || (pkt_is_token && crc5_valid) ); + // valid is level, not a strobe + dflip valid_buffer(clk, valid_packet_48, valid_packet); reg [11:0] token_payload = 0; wire token_payload_done = token_payload[0]; - always @(posedge clk) begin + always @(posedge clk_48mhz) begin if (packet_start) begin token_payload <= 12'b100000000000; end @@ -329,17 +334,31 @@ module usb_fs_rx ( end end - always @(posedge clk) begin + always @(posedge clk_48mhz) begin if (token_payload_done && pkt_is_token) begin - addr <= token_payload[7:1]; - endp <= token_payload[11:8]; - frame_num <= token_payload[11:1]; + addr_48 <= token_payload[7:1]; + endp_48 <= token_payload[11:8]; + frame_num_48 <= token_payload[11:1]; end end - assign pkt_start = packet_start; - assign pkt_end = packet_end; - assign pid = full_pid[4:1]; + // cross the packet start signal to the endpoint clk domain + strobe pkt_start_strobe( + .clk_in(clk_48mhz), + .clk_out(clk), + .strobe_in(packet_start), + .strobe_out(pkt_start) + ); + + // at the end of the packet, capture the parameters to the clk domain + strobe #(.WIDTH(26)) pkt_end_strobe( + clk_48mhz, clk, + packet_end, pkt_end, + { pid_48, addr_48, endp_48, frame_num_48 }, + { pid, addr, endp, frame_num } + ); + assign pid_48 = full_pid[4:1]; + //assign addr = token_payload[7:1]; //assign endp = token_payload[11:8]; //assign frame_num = token_payload[11:1]; @@ -350,10 +369,15 @@ module usb_fs_rx ( //assign rx_data_put = dvalid && pid_complete && pkt_is_data; reg [8:0] rx_data_buffer = 0; wire rx_data_buffer_full = rx_data_buffer[0]; - assign rx_data_put = rx_data_buffer_full; - assign rx_data = rx_data_buffer[8:1]; - always @(posedge clk) begin + // convert the rx_data_put to clk domain + strobe #(.WIDTH(8)) rx_data_strobe( + clk_48mhz, clk, + rx_data_buffer_full, rx_data_put, + rx_data_buffer[8:1], rx_data + ); + + always @(posedge clk_48mhz) begin if (packet_start || rx_data_buffer_full) begin rx_data_buffer <= 9'b100000000; end diff --git a/common/usb_fs_tx.v b/common/usb_fs_tx.v index c9ba07a..34d2377 100644 --- a/common/usb_fs_tx.v +++ b/common/usb_fs_tx.v @@ -2,9 +2,10 @@ module usb_fs_tx ( // A 48MHz clock is required to receive USB data at 12MHz // it's simpler to juse use 48MHz everywhere input clk_48mhz, + input clk, input reset, - // bit strobe from rx to align with senders clock + // bit strobe from rx to align with senders clock (in clk_48mhz domain) input bit_strobe, // output enable to take ownership of bus and data out @@ -12,28 +13,43 @@ module usb_fs_tx ( output reg dp = 0, output reg dn = 0, - // pulse to initiate new packet transmission + // pulse to initiate new packet transmission (clk domain) input pkt_start, + + // pulse to indicate end of packet transmission (clk domain) output pkt_end, - // pid to send + // pid to send (clk domain) input [3:0] pid, // tx logic pulls data until there is nothing available input tx_data_avail, - output reg tx_data_get = 0, + output tx_data_get, input [7:0] tx_data ); - wire clk = clk_48mhz; - + // convert pkt_start to clk_48mhz domain // save packet parameters at pkt_start - reg [3:0] pidq = 0; - - always @(posedge clk) begin - if (pkt_start) begin - pidq <= pid; - end - end + wire pkt_start_48; + wire [3:0] pidq; + strobe #(.WIDTH(4)) pkt_start_strobe( + clk, clk_48mhz, + pkt_start, pkt_start_48, + pid, pidq + ); + + wire tx_data_avail_48; + dflip tx_data_avail_buffer(clk_48mhz, tx_data_avail, tx_data_avail_48); + //wire tx_data_avail_48 = tx_data_avail; + + // convert tx_data_get from 48 to clk + //wire tx_data_get_48 = tx_data_get; + reg tx_data_get_48; + strobe tx_data_get_strobe( + .clk_in(clk_48mhz), + .clk_out(clk), + .strobe_in(tx_data_get_48), + .strobe_out(tx_data_get) + ); reg [7:0] data_shift_reg = 0; reg [7:0] oe_shift_reg = 0; @@ -58,14 +74,20 @@ module usb_fs_tx ( reg bitstuff_qqqq = 0; - always @(posedge clk) begin + always @(posedge clk_48mhz) begin bitstuff_q <= bitstuff; bitstuff_qq <= bitstuff_q; bitstuff_qqq <= bitstuff_qq; bitstuff_qqqq <= bitstuff_qqq; end - assign pkt_end = bit_strobe && se0_shift_reg[1:0] == 2'b01; + wire pkt_end_48 = bit_strobe && se0_shift_reg[1:0] == 2'b01; + strobe pkt_end_strobe( + .clk_in(clk_48mhz), + .clk_out(clk), + .strobe_in(pkt_end_48), + .strobe_out(pkt_end) + ); reg data_payload = 0; @@ -79,10 +101,10 @@ module usb_fs_tx ( reg [15:0] crc16 = 0; - always @(posedge clk) begin + always @(posedge clk_48mhz) begin case (pkt_state) IDLE : begin - if (pkt_start) begin + if (pkt_start_48) begin pkt_state <= SYNC; end end @@ -112,23 +134,23 @@ module usb_fs_tx ( DATA_OR_CRC16_0 : begin if (byte_strobe) begin - if (tx_data_avail) begin + if (tx_data_avail_48) begin pkt_state <= DATA_OR_CRC16_0; data_payload <= 1; - tx_data_get <= 1; + tx_data_get_48 <= 1; data_shift_reg <= tx_data; oe_shift_reg <= 8'b11111111; se0_shift_reg <= 8'b00000000; end else begin pkt_state <= CRC16_1; data_payload <= 0; - tx_data_get <= 0; + tx_data_get_48 <= 0; data_shift_reg <= ~{crc16[8], crc16[9], crc16[10], crc16[11], crc16[12], crc16[13], crc16[14], crc16[15]}; oe_shift_reg <= 8'b11111111; se0_shift_reg <= 8'b00000000; end end else begin - tx_data_get <= 0; + tx_data_get_48 <= 0; end end @@ -156,7 +178,7 @@ module usb_fs_tx ( byte_strobe <= 0; end - if (pkt_start) begin + if (pkt_start_48) begin bit_count <= 1; bit_history_q <= 0; @@ -184,12 +206,12 @@ module usb_fs_tx ( // calculate crc16 wire crc16_invert = serial_tx_data ^ crc16[15]; - always @(posedge clk) begin - if (pkt_start) begin + always @(posedge clk_48mhz) begin + if (pkt_start_48) begin crc16 <= 16'b1111111111111111; end - if (bit_strobe && data_payload && !bitstuff_qqqq && !pkt_start) begin + if (bit_strobe && data_payload && !bitstuff_qqqq && !pkt_start_48) begin crc16[15] <= crc16[14] ^ crc16_invert; crc16[14] <= crc16[13]; crc16[13] <= crc16[12]; @@ -213,8 +235,8 @@ module usb_fs_tx ( // nrzi and differential driving - always @(posedge clk) begin - if (pkt_start) begin + always @(posedge clk_48mhz) begin + if (pkt_start_48) begin // J dp <= 1; dn <= 0; diff --git a/programmer/tinyprog/__init__.py b/programmer/tinyprog/__init__.py index ed585a9..e8106a9 100644 --- a/programmer/tinyprog/__init__.py +++ b/programmer/tinyprog/__init__.py @@ -2,6 +2,7 @@ import platform import re import struct +import time from functools import reduce from pkg_resources import get_distribution, DistributionNotFound @@ -353,6 +354,7 @@ def program_security_register_page(self, page, data): self.security_page_write_cmd, page << (8 + self.security_page_bit_offset), data) self.wait_while_busy() + return True def read_security_register_page(self, page): return self.cmd( @@ -493,12 +495,32 @@ def program_sectors(self, addr, data): for offset in range(0, len(data), sector_size): current_addr = addr + offset current_write_data = data[offset:offset + sector_size] + + # Determine if we need to write this sector at all + current_flash_data = self.read( + current_addr, + sector_size, + disable_progress=True, + max_length=sector_size) + + if current_flash_data == current_write_data: + # skip this sector since it matches + pbar.update(sector_size) + continue + self.erase(current_addr, sector_size, disable_progress=True) minor_sector_size = 256 for minor_offset in range(0, 4 * 1024, minor_sector_size): minor_write_data = current_write_data[ minor_offset:minor_offset + minor_sector_size] + + # if the minor data is all 0xFF then it will match + # the erased bits and doesn't need to be re-sent + if minor_write_data == chr(0xFF) * len(minor_write_data): + pbar.update(len(minor_write_data)) + continue + self.write( current_addr + minor_offset, minor_write_data, @@ -566,3 +588,12 @@ def program_bitstream_fast(self, addr, bitstream): self.wake() self.progress(str(len(bitstream)) + " bytes to program") return self.program_fast(addr, bitstream) + + def program_security_page(self, page, data): + self.progress("Waking up SPI flash") + self.wake() + self.progress("Erasing security page " + str(page)) + self.erase_security_register_page(page) + self.progress(str(len(data)) + " bytes to program") + return self.program_security_register_page(page, data) + diff --git a/programmer/tinyprog/__main__.py b/programmer/tinyprog/__main__.py index cf45634..16f4d5c 100644 --- a/programmer/tinyprog/__main__.py +++ b/programmer/tinyprog/__main__.py @@ -266,6 +266,10 @@ def parse_int(str_value): "--meta", action="store_true", help="dump out the metadata for all connected boards in JSON") + parser.add_argument( + "--security", + type=str, + help="update the security page in the flash at address addr") parser.add_argument( "--update-bootloader", action="store_true", @@ -372,6 +376,7 @@ def parse_int(str_value): # program the flash memory if (args.program is not None) or ( args.program_userdata is not None) or ( + args.security is not None) or ( args.program_image is not None): boot_fpga = False @@ -381,6 +386,7 @@ def progress(info): with active_port: fpga = TinyProg(active_port, progress) + force = False if args.program is not None: print(" Programming %s with %s" % ( @@ -390,6 +396,7 @@ def progress(info): if args.addr is not None: addr = parse_int(args.addr) + force = True else: addr = fpga.meta.userimage_addr_range()[0] @@ -400,7 +407,7 @@ def progress(info): print(" Bootloader not active") sys.exit(1) - if check_if_overwrite_bootloader( + if force or check_if_overwrite_bootloader( addr, len(bitstream), fpga.meta.userimage_addr_range()): boot_fpga = True @@ -417,6 +424,7 @@ def progress(info): if args.addr is not None: addr = parse_int(args.addr) + force = True else: addr = fpga.meta.userdata_addr_range()[0] @@ -427,7 +435,7 @@ def progress(info): print(" Bootloader not active") sys.exit(1) - if check_if_overwrite_bootloader( + if force or check_if_overwrite_bootloader( addr, len(bitstream), fpga.meta.userdata_addr_range()): boot_fpga = True @@ -444,6 +452,7 @@ def progress(info): if args.addr is not None: addr = parse_int(args.addr) + force = True else: addr = fpga.meta.userimage_addr_range()[0] @@ -454,7 +463,7 @@ def progress(info): print(" Bootloader not active") sys.exit(1) - if check_if_overwrite_bootloader( + if force or check_if_overwrite_bootloader( addr, len(bitstream), (fpga.meta.userimage_addr_range()[0], fpga.meta.userdata_addr_range()[1])): @@ -463,6 +472,27 @@ def progress(info): if not fpga.program_bitstream(addr, bitstream): sys.exit(1) + if args.security is not None: + print(" Programming %s security page with %s" % ( + active_port, args.security)) + + data = open(args.security, 'r').read() + + if args.addr is not None: + addr = parse_int(args.addr) + else: + addr = 1 + + if addr < 0: + print(" Negative write addr: {}".format(addr)) + sys.exit(1) + if not fpga.is_bootloader_active(): + print(" Bootloader not active") + sys.exit(1) + + if not fpga.program_security_page(addr, data): + sys.exit(1) + if boot_fpga: fpga.boot() print("") diff --git a/tests/file_list.txt b/tests/file_list.txt index 1c65819..076f817 100644 --- a/tests/file_list.txt +++ b/tests/file_list.txt @@ -1,5 +1,6 @@ test.v ../../common/edge_detect.v +../../common/strobe.v ../../common/tinyfpga_bootloader.v ../../common/usb_fs_in_arb.v ../../common/usb_fs_in_pe.v diff --git a/tests/top_tb_header.vh b/tests/top_tb_header.vh index 42b66b0..88422b4 100644 --- a/tests/top_tb_header.vh +++ b/tests/top_tb_header.vh @@ -42,6 +42,7 @@ module top_tb; vlog_tap_generator #("test.tap") vtg(); reg clk_48mhz; + reg clk = 0; reg reset = 0; initial begin @@ -51,6 +52,8 @@ module top_tb; end end + always @(posedge clk_48mhz) clk <= !clk; + // usb interface wire usb_p_tx_raw; wire usb_n_tx_raw; @@ -76,6 +79,7 @@ module top_tb; tinyfpga_bootloader dut ( .clk_48mhz(clk_48mhz), + .clk(clk), .reset(reset), .usb_p_tx(usb_p_tx_raw),