From cffc6e3fc684358b43202edb3ef02ed4c0b0fc61 Mon Sep 17 00:00:00 2001 From: Joe Devietti Date: Mon, 25 Nov 2024 22:22:13 -0500 Subject: [PATCH] added ULX3S example code, tested on ULX3S-85F board v3.1.8 --- boards/ulx3s/Makefile | 29 ++++++++++++ boards/ulx3s/build.ys | 12 +++++ boards/ulx3s/clock.v | 94 ++++++++++++++++++++++++++++++++++++++ boards/ulx3s/ecppll.py | 1 + boards/ulx3s/top.v | 73 +++++++++++++++++++++++++++++ boards/ulx3s/ulx3s_v20.lpf | 73 +++++++++++++++++++++++++++++ 6 files changed, 282 insertions(+) create mode 100644 boards/ulx3s/Makefile create mode 100644 boards/ulx3s/build.ys create mode 100644 boards/ulx3s/clock.v create mode 120000 boards/ulx3s/ecppll.py create mode 100644 boards/ulx3s/top.v create mode 100644 boards/ulx3s/ulx3s_v20.lpf diff --git a/boards/ulx3s/Makefile b/boards/ulx3s/Makefile new file mode 100644 index 0000000..256a9a1 --- /dev/null +++ b/boards/ulx3s/Makefile @@ -0,0 +1,29 @@ +TARGET=usb_hid_host_demo + +COM=../common +SRC=../../src + +OBJS+=top.v clock.v $(COM)/hid_printer.v $(COM)/uart_tx_V2.v $(SRC)/usb_hid_host.v $(SRC)/usb_hid_host_rom.v + +all: ${TARGET}.bit + +$(TARGET).json: $(OBJS) + yosys build.ys + +$(TARGET)_out.config: $(TARGET).json + nextpnr-ecp5 --85k --package CABGA381 --speed 6 --json $< --textcfg $@ --lpf ulx3s_v20.lpf --freq 65 + +$(TARGET).bit: $(TARGET)_out.config + ecppack --compress --freq 62.0 --input $< --bit $@ + ecppack $< --compress --freq 62.0 --svf-rowsize 800000 --svf ${TARGET}.svf + +${TARGET}.svf: ${TARGET}.bit + +prog: ${TARGET}.svf + icesprog $(TARGET).bit + +clean: + rm -f *.svf *.bit *.config *.json + +.PHONY: prog clean + diff --git a/boards/ulx3s/build.ys b/boards/ulx3s/build.ys new file mode 100644 index 0000000..273d647 --- /dev/null +++ b/boards/ulx3s/build.ys @@ -0,0 +1,12 @@ + +verilog_defaults -add -I../common -I../../src + +read_verilog top.v +read_verilog clock.v +read_verilog ../common/hid_printer.v +read_verilog ../common/uart_tx_V2.v +read_verilog ../../src/usb_hid_host.v +read_verilog ../../src/usb_hid_host_rom.v + +synth_ecp5 -top top -json usb_hid_host_demo.json + diff --git a/boards/ulx3s/clock.v b/boards/ulx3s/clock.v new file mode 100644 index 0000000..7549aaf --- /dev/null +++ b/boards/ulx3s/clock.v @@ -0,0 +1,94 @@ +// f_pfd = f_in / refclk_div +// f_vco = f_pfd * feedback_div * output_div +// f_out = f_vco / output_div +// refclk_div: 1..128 +// feedback_div: 1..80 +// output_div: 1..128 +// f_pfd: 3.125..400 +// f_vco: 400..800 + +module clock +( + input clkin, // 25 MHz + output clk12, // 12 MHz + output clk100, // 100 Mhz + output locked +); + +// pll0 raises 25Mhz to 100Mhz +// pll1 produces 12Mhz from 100Mhz +wire locked0; + +(* FREQUENCY_PIN_CLKI="25" *) +(* FREQUENCY_PIN_CLKOP="100" *) +(* 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"), + .OUTDIVIDER_MUXA("DIVA"), + .OUTDIVIDER_MUXB("DIVB"), + .OUTDIVIDER_MUXC("DIVC"), + .OUTDIVIDER_MUXD("DIVD"), + .CLKI_DIV(1), + .CLKOP_ENABLE("ENABLED"), + .CLKOP_DIV(6), + .CLKOP_CPHASE(2), + .CLKOP_FPHASE(0), + .FEEDBK_PATH("CLKOP"), + .CLKFB_DIV(4) + ) pll0 ( + .RST(1'b0), + .STDBY(1'b0), + .CLKI(clkin), + .CLKOP(clk100), + .CLKFB(clk100), + .CLKINTFB(), + .PHASESEL0(1'b0), + .PHASESEL1(1'b0), + .PHASEDIR(1'b1), + .PHASESTEP(1'b1), + .PHASELOADREG(1'b1), + .PLLWAKESYNC(1'b0), + .ENCLKOP(1'b0), + .LOCK(locked0) + ); + +(* FREQUENCY_PIN_CLKI="100" *) +(* FREQUENCY_PIN_CLKOP="12" *) +(* 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"), + .OUTDIVIDER_MUXA("DIVA"), + .OUTDIVIDER_MUXB("DIVB"), + .OUTDIVIDER_MUXC("DIVC"), + .OUTDIVIDER_MUXD("DIVD"), + .CLKI_DIV(25), + .CLKOP_ENABLE("ENABLED"), + .CLKOP_DIV(50), + .CLKOP_CPHASE(24), + .CLKOP_FPHASE(0), + .FEEDBK_PATH("CLKOP"), + .CLKFB_DIV(3) + ) pll1 ( + .RST(~locked0), + .STDBY(1'b0), + .CLKI(clk100), + .CLKOP(clk12), + .CLKFB(clk12), + .CLKINTFB(), + .PHASESEL0(1'b0), + .PHASESEL1(1'b0), + .PHASEDIR(1'b1), + .PHASESTEP(1'b1), + .PHASELOADREG(1'b1), + .PLLWAKESYNC(1'b0), + .ENCLKOP(1'b0), + .LOCK(locked) + ); + +endmodule diff --git a/boards/ulx3s/ecppll.py b/boards/ulx3s/ecppll.py new file mode 120000 index 0000000..bc7f711 --- /dev/null +++ b/boards/ulx3s/ecppll.py @@ -0,0 +1 @@ +../icesugar-pro/ecppll.py \ No newline at end of file diff --git a/boards/ulx3s/top.v b/boards/ulx3s/top.v new file mode 100644 index 0000000..dc74c62 --- /dev/null +++ b/boards/ulx3s/top.v @@ -0,0 +1,73 @@ +// +// Example using the usb_hid_host core, for the ULX3S board +// devietti, 11/2024 +// + +module top ( + input clk_25mhz, + + // UART output over US1 USB port + output ftdi_rxd, + + // LEDs + output [7:0] led, + + // US2 USB port + inout usb_fpga_bd_dn, + inout usb_fpga_bd_dp +); + +wire sys_resetn; +wire clk_usb; +wire [1:0] usb_type; +wire [7:0] key_modifiers, key1, key2, key3, key4; +wire [7:0] mouse_btn; +wire signed [7:0] mouse_dx, mouse_dy; +wire [63:0] hid_report; +wire usb_report, usb_conerr, game_l, game_r, game_u, game_d, game_a, game_b, game_x, game_y; +wire game_sel, game_sta; +wire [13:0] dbg_pc; +wire [3:0] dbg_inst; + +clock clock( + .clkin(clk_25mhz), + .clk12(clk_usb), // 12Mhz usb clock + .clk100(), + .locked(sys_resetn) +); + +usb_hid_host usb ( + .usbclk(clk_usb), .usbrst_n(sys_resetn), + .usb_dm(usb_fpga_bd_dn), .usb_dp(usb_fpga_bd_dp), + .typ(usb_type), .report(usb_report), + .key_modifiers(key_modifiers), .key1(key1), .key2(key2), .key3(key3), .key4(key4), + .mouse_btn(mouse_btn), .mouse_dx(mouse_dx), .mouse_dy(mouse_dy), + .game_l(game_l), .game_r(game_r), .game_u(game_u), .game_d(game_d), + .game_a(game_a), .game_b(game_b), .game_x(game_x), .game_y(game_y), + .game_sel(game_sel), .game_sta(game_sta), + .conerr(usb_conerr), .dbg_hid_report(hid_report) +); + +hid_printer prt ( + .clk(clk_usb), .resetn(sys_resetn), + .uart_tx(ftdi_rxd), .usb_type(usb_type), .usb_report(usb_report), + .key_modifiers(key_modifiers), .key1(key1), .key2(key2), .key3(key3), .key4(key4), + .mouse_btn(mouse_btn), .mouse_dx(mouse_dx), .mouse_dy(mouse_dy), + .game_l(game_l), .game_r(game_r), .game_u(game_u), .game_d(game_d), + .game_a(game_a), .game_b(game_b), .game_x(game_x), .game_y(game_y), + .game_sel(game_sel), .game_sta(game_sta) +); + +reg report_toggle; // blinks whenever there's a report +always @(posedge clk_usb) if (usb_report) report_toggle <= ~report_toggle; + + assign led[0] = report_toggle; + assign led[1] = usb_type; + assign led[2] = |usb_report; + assign led[3] = mouse_btn; + assign led[4] = |mouse_dx; + assign led[5] = |mouse_dy; + assign led[6] = |key_modifiers; + assign led[7] = |key1; + +endmodule diff --git a/boards/ulx3s/ulx3s_v20.lpf b/boards/ulx3s/ulx3s_v20.lpf new file mode 100644 index 0000000..3110c47 --- /dev/null +++ b/boards/ulx3s/ulx3s_v20.lpf @@ -0,0 +1,73 @@ +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; + +## 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; + +## Second USB port "US2" going directly into FPGA "usb", "ram" sheet +# LOCATE COMP "usb_fpga_dp" SITE "E16"; # single ended i/o or differential input +# LOCATE COMP "usb_fpga_dn" SITE "F16"; +# IOBUF PORT "usb_fpga_dp" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=4; +# IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=4; +LOCATE COMP "usb_fpga_bd_dp" SITE "D15"; # single ended i/o or differential i/o +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=4; +# IOBUF PORT "usb_fpga_pu_dn" PULLMODE=NONE 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;