hdl4fpga (hdl4fpga__hdl4fpga)
| Field | Value |
|---|---|
| Upstream | https://github.com/hdl4fpga/hdl4fpga |
| Reviewed at | 662986b (upstream date 2025-08-17), reviewed 2026-09-28 |
| License | MIT (LICENSE, Miguel Angel Sagreras) for all VHDL/Verilog source checked (headers on every file spot-checked: boards/ULX3S/common/ulx3s.vhd, boards/ULX3S/apps/{graphics,scopeio,ser_debug}.vhd, library/scope/scopeio.vhd, library/mii/mii_ipoe.vhd, library/sdram/sdram_ctlr.vhd, library/usb/usbhost.vhd, library/video/dvi.vhd, library/latticesemi/ecp5/ecp5_sdrphy.vhd, library/apps/ecp5_videodcm.vhd — all carry the same MIT boilerplate as LICENSE, grep -rl "gnu general public license" -i --include=*.vhd --include=*.v . returns nothing). The GPL-3.0-or-later text only appears in the Diamond build Makefiles (boards/ULX3S/diamond/Makefile, boards/ULX4M_LS/diamond/Makefile, boards/ULX4M_LD/diamond/Makefile, library/latticesemi/scripts/Makefile, library/xilinx/scripts/Makefile), not in any HDL source — this corrects the catalogue’s “mixed MIT/GPL” note, see Open questions. |
| HDL / framework | VHDL (this repo is ~all VHDL; the catalogue’s “274” file count and the “Verilog, JS” entries refer to the wider repo — Micron DDR verification models (library/micron/ddr{,2,3}/*.v) and non-ULX3S board tooling — not to anything used by the ULX3S apps) |
| Toolchain | diamond only for ULX3S. boards/ULX3S/diamond/apps.ldf is a Lattice Diamond project (synthesis="synplify", device="LFE5U-12F-8BG381C") built via boards/ULX3S/diamond/Makefile (diamondc batch calls). No yosys/nextpnr-ecp5 flow exists for ULX3S. boards/ULX3S/ghdl/app_graphics.sh and library/ghdl/*.sh run ghdl -a (analysis/type-check only, --std=02) for the graphics app — this is a GHDL front-end syntax check, not a synthesis or simulation run, and there is no nextpnr/yosys call anywhere in the tree (grep -rn "nextpnr\|yosys" boards/ULX3S library → no hits). |
| Programmer | Not stated for ULX3S in this repo (Diamond produces a .bit/.svf; loading is left to the user — openFPGALoader -b ulx3s per CLAUDE.md convention, unverified here) |
| Target FPGA(s) | 12F (apps.ldf device="LFE5U-12F-8BG381C", all three apps share one project/device) |
| Board revision(s) | v2.x / v3.0.x (apps.lpf header: ## ULX3S v2.x.x and v3.0.x; pin names/sites match the ulx3s_v20.lpf convention from CLAUDE.md, e.g. clk_25mhz at G2, gpdi_d[0..3] at A16/A14/A12/A17) |
| Activity | Last commit to the whole monorepo 662986b, 2025-08-17 (git -C original_sources/hdl4fpga__hdl4fpga log -1 --format=%cs). First commit 2013-06-05, 11860 commits total (.claude/memory/history.tsv, recorded before the clone was made shallow — commit count not independently verifiable from this --depth 1 clone) |
Scope of this page
hdl4fpga is a very large portable VHDL library (many boards: ULX3S, ULX4M_LS/LD, arty, orangecrab, ml50x, …). This page covers only what is ULX3S-relevant: the three boards/ULX3S/apps/ designs and the reusable cores they pull in (library/scope, library/mii, library/sdram + library/latticesemi/ecp5, library/usb, library/video). The rest of library/ (Xilinx/Altera back-ends, other boards’ apps, CPU/soft-core work) is out of scope.
What the gateware does
boards/ULX3S/common/ulx3s.vhd declares one entity ulx3s whose port list is the full ULX3S pin set from apps.lpf (clk_25mhz, ftdi_, leds, buttons, sw, oled_, adc_, sdram_, gpdi_, gp/gn, usb_fpga_, wifi_, sd_, audio_*). Each app in boards/ULX3S/apps/ is a separate architecture of that same entity, selected as the Diamond implementation (apps.ldf has one implementation per architecture, default ser_debug; boards/ULX3S/diamond/Makefile has matching ser_debug/graphics/scopeio targets):
ser_debug(boards/ULX3S/apps/ser_debug.vhd, architectureser_debug) — serial/USB debug console. Drives an 800x600@60Hz DVI/GPDI text display (hdl4fpga.ecp5_videodcm, 40 MHz pixel clock from 25 MHz) and a bidirectional link on US2 selectable at build time between USB (usb_deviceconstant,true⇒hdl4fpga.usbdev,false⇒hdl4fpga.usbhostdvr+hdl4fpga.usbphy) or Ethernet (io_link = "io_ipoe", viahdl4fpga.ipoepkg/library/mii).graphics(boards/ULX3S/apps/graphics.vhd, architecturegraphics) — SDRAM-backed framebuffer/graphics demo: instantiates the genericsdram_ctlragainst the ULX3S’s actual SDR SDRAM chip (chip_data => "MT48LC16M16MA2-7E",sdram.dcm25→133 MHz viahdl4fpga.ecp5_profiles.sdram_dcm) and drives 800x600@60Hz over GPDI/DVI, again with a USB or Ethernetio_link.scopeio(boards/ULX3S/apps/scopeio.vhd, architecturescopeio) — the ScopeIO 8-input digital storage oscilloscope. Bit-bangs the onboard MAX1112x SPI ADC directly in this file (adc_sclk/adc_csn/adc_mosi/adc_miso, lines 751-957), stores samples in the SDR SDRAM (sameMT48LC16M16MA2-7Echip data), and renders the waveform/grid/trigger UI at 1280x720@60Hz (64 MHz pixel clock) vialibrary/scope/scopeio.vhd. This is the source for thescope/prebuilt bitstream catalogued inemard__ulx3s-bin.md(mouse GUI, 4-channel storage scope claim there — this repo’sscopeio.vhdtop sets"inputs:" & "8", i.e. 8 channels are wired in the settings string though the ulx3s-bin doc says 4; not reconciled, see Open questions).
Structure
boards/ULX3S/common/ulx3s.vhd— sharedulx3sentity (port list = board pins).boards/ULX3S/apps/{ser_debug,graphics,scopeio}.vhd— one architecture each.boards/ULX3S/diamond/{apps.ldf,apps.lpf,apps_video.lpf,Makefile}— Diamond project, pin constraints (v2.x/v3.0.x), anddiamondcbatch build.boards/ULX3S/ghdl/app_graphics.sh— GHDL analysis-only script forgraphics.boards/ULX3S/testbenches/— 8 files:{ser_debug,graphics,scopeio}.vhdtestbenches with matching.do(ModelSim/Aldec) scripts, pluseth_tb.vhdandgraphics_structure.do.library/scope/— ScopeIO core (scopeio.vhd+ ~20scopeio_*helper units: grid, trigger, storage, capture, downsampler, axis, palette, textbox…).library/mii/— Ethernet/IP stack (see Reuse notes).library/sdram/— portable multi-generation SDRAM/DDR controller.library/latticesemi/ecp5/— ECP5-specific SDRAM PHY + I/O gearbox primitives.library/apps/ecp5_videodcm.vhd,ecp5_sdramdcm.vhd— ECP5EHXPLLL-based clock generators for video and SDRAM.library/video/— DVI/TMDS encoder, VGA/CGA text-mode helpers.library/usb/— USB 1.1 device (usbdev.vhd) and host (usbhost.vhd) cores.library/basic/,library/hdlc/,library/sio/,library/uart/— smaller reusable utility packages (not reviewed in depth here).library/micron/{ddr,ddr2,ddr3}/*.v— Micron’s own bus-functional simulation models for DDR/DDR2/DDR3 chips (verification IP, not an hdl4fpga controller; not ULX3S-relevant since ULX3S has SDR SDRAM).
How to build
Not run (per task constraints: no make/build/simulate). As found in boards/ULX3S/diamond/Makefile:
cd boards/ULX3S/diamond
make graphics # or ser_debug / scopeio
Each target does echo prj_project open apps.ldf \; prj_run Export -impl $@ -task Bitgen | diamondc, i.e. it requires Lattice Diamond (diamondc) on PATH; apps.ldf targets LFE5U-12F-8BG381C with Synplify synthesis. Whether this currently builds clean was not verified (no Diamond available here).
Reuse notes
Reusable blocks
| Block | Path | Top module | Language | Vendor primitives | License |
|---|---|---|---|---|---|
| ScopeIO oscilloscope UI/storage | library/scope/ | scopeio (library/scope/scopeio.vhd) | VHDL | None directly; depends on the SDRAM PHY and video PLL below, which do | MIT |
| Ethernet/IP stack (ARP/IP/UDP/DHCP/ICMP) | library/mii/ | mii_ipoe (library/mii/mii_ipoe.vhd), built from eth_rx/eth_tx, arpd, ipv4, udp, icmpd, dhcpcd | VHDL | None found (portable MII-level logic; RMII pad wiring is board-side) | MIT |
| SDRAM/DDR controller (generation-generic) | library/sdram/ | sdram_ctlr (library/sdram/sdram_ctlr.vhd) | VHDL | None in the controller itself | MIT |
| ECP5 SDRAM PHY (gearbox/serdes) | library/latticesemi/ecp5/ | ecp5_sdrphy → ecp5_sdrbaphy + ecp5_sdrdqphy → ecp5_ogbx/ecp5_igbx | VHDL | oddrx1f, fd1s3ax (ECP5 primitives, via ecp5u.components) | MIT |
| ECP5 PLL/clock gen (video, SDRAM) | library/apps/ | ecp5_videodcm, ecp5_sdramdcm | VHDL | EHXPLLL | MIT |
| USB 1.1 device + host | library/usb/ | usbdev (device), usbhost/usbhostdvr (host), usbphy (PHY-level) | VHDL | None found | MIT |
| DVI/TMDS encoder | library/video/ | dvi (library/video/dvi.vhd), uses tmds_encoder.vhd | VHDL | None in dvi.vhd/tmds_encoder.vhd itself; final GPDI serialization goes through ecp5_ogbx (see above) | MIT |
Per-block detail
- ScopeIO (
library/scope/scopeio.vhd): genericsprofile,settings(a compact JSON-like config string parsed viahdl4fpga.hdo),sdram_freq,fifo_size(default 8*8192),video_gear,red/green/blue_length(default 8/8/8). Ports split into ansi_*/so_*serial I/O link (USB or Ethernet),input_clk/input_data(ADC sample stream), and a fullctlr_*/ctlrphy_*SDRAM controller/PHY interface it drives directly — i.e. ScopeIO expects to own the SDRAM controller, not share it. On ULX3S the ADC SPI bit-banging (MAX1112x,adc_sclk/adc_csn/adc_mosi/adc_miso) lives in the app fileboards/ULX3S/apps/scopeio.vhd, not inlibrary/scope/, so reusing ScopeIO elsewhere means writing your own ADC driver to feedinput_data. - mii/ethernet stack (
library/mii/mii_ipoe.vhd): genericshalf_duplex,default_ipv4a(32-bit),my_mac(48-bit). Ports:mii_clkplus aplrx_*/pltx_*payload link (to the app) andmiirx_*/miitx_*(to the RMII/MII PHY pins). Confirms the catalogue’s “full ARP/IP/UDP/DHCP stack” claim:arpd.vhd/arp_rx.vhd/arp_tx.vhd(ARP),ipv4.vhd/ipv4_rx.vhd/ipv4_tx.vhd(IP),udp.vhd/udp_rx.vhd/udp_tx.vhd(UDP),icmpd.vhd/icmprply_tx.vhd/icmprqst_rx.vhd(ICMP ping),dhcpcd.vhd/dhcp_dscb.vhd/dhcp_offer.vhd(DHCP client). No RMII pad-level PHY driver is in this directory — that’s board-side (e.g. ulx3s-misc’sexamples/eth/rmiiperreusable-cores.md). This is exactly the stack used by theeth/prebuilt bitstream inemard__ulx3s-bin.md(DHCP + ping responder on LAN8720 RMII, GP/GN 9-13). - SDRAM controller (
library/sdram/sdram_ctlr.vhd): genericsdebug,ctlr_tcp(clock period, real),chip_data/phy_data(strings naming entries insdrampkg.vhd’ssdram_db/phy_dbtables). It is generation-generic:sdrampkg.vhdlists chip timing forsdr(e.g.MT48LC16M16MA2-7E— the chip ULX3S actually has),ddr,ddr2andddr3parts (e.g. MicronMT41K128M16-125). ULX3S’s two ULX3S apps (graphics,scopeio) both instantiate it withchip_data => "MT48LC16M16MA2-7E"(SDR, 2 banks/13 row/9 col/16-bit), i.e. only the SDR path is exercised on ULX3S — the DDR2/DDR3 entries in the same table are for other boards/chips and do not apply here (ULX3S has SDR SDRAM only, per CLAUDE.md). The vendor-specific part is the PHY layer (library/latticesemi/ecp5/ecp5_sdrphy.vhdand friends), which uses ECP5oddrx1f/fd1s3axI/O primitives through smallecp5_igbx/ecp5_ogbxgearbox wrappers — this PHY is required to actually connectsdram_ctlrto ECP5 pins and is not portable to other vendors as-is. - USB device/host (
library/usb/usbdev.vhd,usbhost.vhd): used on ULX3S byser_debug.vhdon US2 (usb_fpga_{dp,dn,bd_dp,bd_dn}), switchable device/host via theusb_deviceconstant.library/usb/README.rstnotes 36 MHz oversampling clock (tested 35.9-36.36 MHz). No ECP5-specific primitives found inusbdev.vhd/usbhost.vhd/usbphy*.vhd— this core looks portable. - DVI/TMDS (
library/video/dvi.vhd): genericgear(default 10, ULX3S apps use 2), portsclk,rgb(3×8),hsync/vsync/blank,cclk, and four serializedgear-wide output channelschn0/chn1/chn2/chnc. Portable by itself; on ULX3S the final serialization togpdi_d[0..3]again goes through the ECP5ecp5_ogbxgearbox (oddrx1f), so droppingdvi.vhdinto a non-ECP5 board needs a different output stage.
Clock/reset assumptions and drop-in notes
- All three ULX3S apps assume a single 25 MHz input (
clk_25mhz,apps.lpfsiteG2) and derive everything else (40/64 MHz pixel clocks, 133 MHz SDRAM clock, 36 MHz USB oversampling) viaEHXPLLL-basedecp5_videodcm/ecp5_sdramdcm— this matches the ULX3S board’s actual 25 MHz oscillator (CLAUDE.md). Reset is informal:ser_debug.vhduses therightjoystick button (alias sys_rst is right) as reset;graphics.vhd/scopeio.vhdwere not checked for an explicit reset alias (grep found none) and appear to rely on PLL lock signals instead. - Dependencies: every block above pulls in
library/basic/hdo.vhdandlibrary/basic/base.vhd(thehdo“hierarchical data object” string-based config-parsing package used pervasively for generics likesettingsandchip_data— this is unusual and adds real complexity to reusing any single block standalone; expect to needhdo.vhd/base.vhdplus whichever*pkg.vhdpackage (sdrampkg,videopkg,scopeiopkg,ecp5_profiles) the block references). - To drop a block into a new ULX3S design targeting
ulx3s_v20.lpfconventions: pin names inboards/ULX3S/diamond/apps.lpfalready use the standard ULX3S names (clk_25mhz,gpdi_d[],sdram_*,gp[]/gn[],adc_*), so the LPF constraints themselves are directly reusable; the main porting cost is pulling in thehdo/package dependency chain and (for SDRAM/DVI) the ECP5-specific PHY/gearbox files.
Open questions
- Programmer for ULX3S bitstreams from this repo is unstated (unverified: presumably standard
openFPGALoader -b ulx3sper CLAUDE.md, not confirmed in-repo). - ScopeIO’s
"inputs:" & "8"setting inboards/ULX3S/apps/scopeio.vhd(8 analog inputs configured) vs. the “4-channel storage oscilloscope” description indocs/projects/emard__ulx3s-bin.md(from thescope/prebuilt bitstream) is not reconciled — could be a different commit/config, or the 4 channels described there could be a UI/display subset of the 8 wired. Needs theulx3s-binscope/build’s actual source commit to compare. - Whether
boards/ULX3S/diamond/apps.ldfcurrently builds clean under a present-day Diamond install was not tested (no build performed, per task constraints). library/apps/ecp3_sdramdcm.vhd,xc3s_sdramdcm.vhd,xc5v_sdramdcm.vhd,xc7a_sdramdcm.vhdshow the same SDRAM-DCM pattern exists for other vendors (Xilinx Spartan3/Virtex5/Artix7, Lattice ECP3) — not reviewed, out of scope for ULX3S but useful to know when porting.- Catalogue
reusable_blockscell sayslibrary/sdram, ecp5 phys, video/tmds, usb/ dev+host, mii/ full eth stack, scope/— all verified present and correctly named; cataloguelicensecell (“mixed: MIT (LICENSE) vs GPL-3.0-or-later headers”) should be corrected per the License field above: the mix is MIT-source vs. GPL-headed Makefiles, not mixed HDL.