{"id":49336249,"url":"https://github.com/datanoisetv/colorlight-i9-aes67","last_synced_at":"2026-04-27T01:02:01.209Z","repository":{"id":349523717,"uuid":"1202693211","full_name":"DatanoiseTV/colorlight-i9-aes67","owner":"DatanoiseTV","description":"Colorlight i9 hardware offloaded AES67 with management softcore.","archived":false,"fork":false,"pushed_at":"2026-04-06T10:45:19.000Z","size":119,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-06T12:10:50.062Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Verilog","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DatanoiseTV.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-06T09:47:46.000Z","updated_at":"2026-04-06T10:45:24.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/DatanoiseTV/colorlight-i9-aes67","commit_stats":null,"previous_names":["datanoisetv/colorlight-i9-aes67"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/DatanoiseTV/colorlight-i9-aes67","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DatanoiseTV%2Fcolorlight-i9-aes67","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DatanoiseTV%2Fcolorlight-i9-aes67/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DatanoiseTV%2Fcolorlight-i9-aes67/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DatanoiseTV%2Fcolorlight-i9-aes67/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DatanoiseTV","download_url":"https://codeload.github.com/DatanoiseTV/colorlight-i9-aes67/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DatanoiseTV%2Fcolorlight-i9-aes67/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32318417,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"ssl_error","status_checked_at":"2026-04-26T23:26:25.802Z","response_time":129,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-27T01:02:00.319Z","updated_at":"2026-04-27T01:02:01.188Z","avatar_url":"https://github.com/DatanoiseTV.png","language":"Verilog","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AES67 on Colorlight i9 v7.2 (Lattice ECP5)\n\nA complete hardware AES67/RAVENNA Audio-over-IP implementation targeting the\nColorlight i9 v7.2 FPGA board, with **IEEE 1588 PTP fully implemented in\nVerilog** and a VexRiscv soft CPU running **lwIP** for the management plane\non the same physical Ethernet — without ever touching the RTP data path.\n\n## Features\n\n| | |\n|---|---|\n| Hardware MAC | Custom 1 Gbps RGMII MAC with **byte-precise SFD pulses** for PTP timestamping |\n| PTP (RFC 1588-2008) | Full Verilog: clock NCO, **hardware timestamp capture with PHY/cable asymmetry compensation** (RFC §7.4), packet processor with **correctionField subtraction** (RFC §11.3), **second-rollover-correct offset math**, **twoStepFlag** awareness, low-pass filter, hysteretic PI servo, lock detector |\n| **Master + Slave** | **Full bidirectional PTP**: hardware generates Sync + Follow_Up + Delay_Resp in master mode, processes them in slave mode. **BMC algorithm** (RFC §9.3) runs in firmware, drives the `mode_is_master` CSR based on Announce messages on UDP port 320. Default Sync interval: 125 ms (8/sec). |\n| **Latency** | **125 µs** packet time, **500 µs** jitter buffer, **cut-through** packet router (~336 ns vs 12 µs store-and-forward), **PTP-disciplined** audio NCO |\n| RTP | Hardware TX + RX engines with L24 codec, BRAM jitter buffer |\n| Audio I/O | I2S **and TDM** master (up to 16 channels) clocked by a PTP-disciplined NCO |\n| TX path | IP/UDP/Ethernet wrappers for PTP and RTP, 3-way arbiter (PTP \u003e RTP \u003e CPU) |\n| Soft CPU | LiteX VexRiscv with 8 MB SDRAM, lwIP TCP/IP stack |\n| DHCP | Full lwIP DHCP client (DISCOVER/OFFER/REQUEST/ACK/RENEW) |\n| **SAP** (RFC 2974) | Multicast session announcement on `239.255.255.255:9875` with AES67-compliant SDP including `ts-refclk` and `mediaclk` attributes; remote source discovery cache |\n| mDNS | lwIP mdns_responder advertising `_ravenna._udp` and `_http._tcp` |\n| HTTP | lwIP httpd with `/status.cgi` JSON endpoint |\n| Virtual TDM-16 | CPU-accessible 16-channel audio FIFO that mixes into the RTP TX path or replaces channels |\n| **DSP slot** | Per-channel **gain / mute / peak meter** in hardware (combinational, Q1.15 gain), foundation for biquad EQ |\n| **WebUI** | Single-page dashboard at `http://aes67br-XXXXXX.local/` — live stats, full configuration editor, SAP discovery, BMC view, **per-channel DSP controls with peak meters**, and **live channel preview audio** |\n| **Audio preview** | `audio_capture` HW FIFO + `/audio.wav` HTTP streaming endpoint, playable in any browser via `\u003caudio\u003e` element |\n| **Hostname** | Auto-generated `aes67br-XXXXXX` from the lower 24 bits of the MAC, used for DHCP, mDNS, BMC clock identity, SAP origin |\n| PLL | Real ECP5 `EHXPLLL` (25 → 125 MHz @ 0° + 90°) |\n| Reset | Async-assert / sync-deassert reset synchronizer |\n| Toolchain | Reproducible Docker image with OSS CAD Suite + LiteX + lwIP + RV32 GCC |\n\n## Latency Budget (slave RX → DAC)\n\n| Stage | Time |\n|-------|------|\n| Wire → MAC SFD pulse (RGMII pipeline) | ~16 ns (compensated via `rx_delay_ns` CSR) |\n| Cut-through packet router (decision @ byte 38) | ~336 ns |\n| RTP RX parse + L24 decode + jitter buffer write | ~100 ns + (jitter buffer fill) |\n| Jitter buffer target depth (default) | **500 µs** |\n| BRAM read → I2S/TDM shift register | \u003c 1 µs |\n| **Total slave RX latency** | **~500 µs** |\n\nFor TX: audio frame tick → RTP TX engine → IP/UDP/Eth wrapper → MAC TX SFD ≈ 1.5 µs + frame transmit time.\n\n## RFC Compliance Notes\n\nThe PTP implementation aims to be conformant with **IEEE 1588-2008** (PTPv2):\n\n- **§7.3.4 Timestamping**: timestamps are captured at the cycle the SFD crosses the MII boundary in the MAC clock domain — *not* after a synchronizer chain that would add jitter. The capture register is registered combinationally on the SFD pulse so there is no extra cycle.\n- **§7.4 Asymmetry compensation**: configurable `tx_delay_ns` and `rx_delay_ns` CSRs (signed nanoseconds) are added to/subtracted from the captured timestamps with correct second-rollover handling. Set these per-board to compensate for PHY + magnetics + cable asymmetry.\n- **§11.3 Offset / mean path delay**:\n  ```\n  m2s   = (t2 - t1) - corrField_sync          # corrField is ns \u003c\u003c 16\n  s2m   = (t4 - t3) - corrField_resp\n  delay = (m2s + s2m) / 2\n  offset= m2s - delay\n  ```\n  All math is signed 64-bit and handles offsets that span seconds boundaries.\n- **§11.4.4 correctionField summation**: the receiver adds the Sync correctionField to the Follow_Up correctionField (two-step path), and uses the Sync's own field directly in one-step mode.\n- **`twoStepFlag` (octet 6 bit 1)**: detected per Sync; if cleared, the Sync's `originTimestamp` is used directly as t1, no Follow_Up wait.\n- **PI servo stability**: tuned gains (Kp=0.5, Ki=0.05 in Q16.16), anti-windup integrator clamp (±100 ms), output saturation (±500 ppm), hysteretic 3-state lock detector with separate enter/exit thresholds.\n- **Active discipline of audio clock**: the same `freq_adj_ppb` signal that adjusts the PTP clock NCO is also fed to the audio sample-rate NCO so the audio output remains locked to the grandmaster — not just synchronized at startup.\n\n## Architecture\n\n```\n                              ┌──────────────────────────────────┐\n                              │      Lattice ECP5-45F            │\n                              │                                  │\n                              │  ┌─────────────┐                 │\n              PHY0 (RGMII) ───┼──┤ Custom MAC  │                 │\n                              │  │ + SFD pulses│                 │\n                              │  └──────┬──────┘                 │\n                              │         │                        │\n                              │  ┌──────┴──────┐                 │\n                              │  │   Packet    │   classifier    │\n                              │  │   Router    │                 │\n                              │  └──┬──┬──┬───┘                 │\n                              │     │  │  │                      │\n                              │  ┌──┘  │  └──┐                   │\n                              │  │     │     │                   │\n                              │  ▼     ▼     ▼                   │\n                              │ ┌──┐  ┌──┐  ┌──────┐              │\n                              │ │PTP│ │RTP│ │ CPU  │ ←─ lwIP      │\n                              │ │HW │ │HW │ │netif │  on VexRiscv│\n                              │ └─┬┘  └─┬┘  └──┬───┘              │\n                              │   │     │      │                  │\n                              │   ▼     ▼      ▼                  │\n                              │ ┌──────────────────┐              │\n                              │ │  TX wrappers     │              │\n                              │ │ (IP/UDP/Eth hdr) │              │\n                              │ └────────┬─────────┘              │\n                              │          │                        │\n                              │  ┌───────┴────────┐               │\n                              │  │  TX Arbiter    │               │\n                              │  │  (PTP\u003eRTP\u003eCPU) │               │\n                              │  └───────┬────────┘               │\n                              │          │                        │\n                              │  back to MAC TX                   │\n                              │                                   │\n                              │  ┌─────────────────────────┐      │\n                              │  │  PTP-locked Audio NCO   │      │\n                              │  │      ↓                  │      │\n                              │  │  I2S/TDM Master ←─ Virtual I2S│\n                              │  │      ↓             (CPU mix) │\n                              │  └────────┬────────────────┘      │\n                              │           │                       │\n                              └───────────┼───────────────────────┘\n                                          ↓\n                                    Audio Codec(s)\n```\n\n| Plane | Where it runs | Function |\n|-------|---------------|----------|\n| Data plane (timing-critical) | FPGA fabric | Ethernet MAC, PTP, RTP, audio NCO, I2S/TDM |\n| Management plane | VexRiscv + lwIP | DHCP, ARP, ICMP, IGMP, mDNS, HTTP |\n| User audio plane | Virtual I2S | CPU can mix into / tap from the audio path |\n\n## Sharing the Same Ethernet\n\nThe CPU's lwIP stack and the hardware RTP/PTP engines share **one physical\nPHY**. The packet router classifies inbound frames at line rate:\n\n- **PTP** (UDP 319/320 or EtherType 0x88F7) → hardware PTP engine\n- **RTP** (UDP 5004 to multicast group) → hardware RTP engine\n- **Everything else** (ARP, ICMP, DHCP, mDNS, HTTP, …) → CPU netif\n\nFor TX, three streams are merged by the arbiter without bothering the RTP\nengine: PTP DelayReq packets, RTP audio packets (each wrapped with full\nIP/UDP/Ethernet headers by `tx_udp_wrapper`), and CPU frames coming from\nlwIP via the `cpu_netif` BRAM.\n\nThe result: **DHCP works, mDNS works, HTTP works, and the RTP data path is\nnever touched by software**.\n\n## Virtual I2S\n\nThe `virt_i2s` peripheral exposes a CPU-accessible FIFO pair that hooks\ninto the audio data path. The CPU can:\n\n- **Generate audio** (test tones, software synths) and have it appear on\n  selected RTP channels (mix or replace mode)\n- **Record audio** from incoming RTP or the I2S ADC into RAM/SD/network\n- **Run software DSP** in a feedback loop with the hardware audio path\n\nAll without disturbing the timing-critical RTP TX/RX. The FIFO uses\nclock-domain-safe Sarwate-style sample staging so even slow CPU writes\ndon't drop samples.\n\n## RTL Module Overview\n\n```\nrtl/\n├── aes67_top.v                Top-level integration\n├── pll_25_to_125.v            Real ecppll EHXPLLL (with SIM_PLL fallback)\n├── eth/\n│   ├── rgmii_rx.v             DDR RGMII receive (ECP5 IDDRX1F)\n│   ├── rgmii_tx.v             DDR RGMII transmit (ECP5 ODDRX1F)\n│   ├── eth_mac_rx.v           Frame RX, CRC check, SFD pulse\n│   ├── eth_mac_tx.v           Frame TX, CRC gen, SFD pulse\n│   ├── eth_mac.v              MAC wrapper\n│   ├── ip_checksum.v          Streaming RFC-1071 16-bit checksum\n│   ├── tx_udp_wrapper.v       Ethernet/IP/UDP header prepender\n│   └── tx_arbiter.v           3-way priority TX arbiter (PTP\u003eRTP\u003eCPU)\n├── ptp/                       ★ Full IEEE 1588 in HW\n│   ├── ptp_clock.v            96-bit timestamp + 8.24 NCO + phase step\n│   ├── ptp_timestamp.v        SFD-triggered TX/RX timestamp FIFOs\n│   ├── ptp_pp.v               Sync/FollowUp/DelayResp parser, DelayReq gen\n│   ├── ptp_servo.v            PI controller, anti-windup, lock detector\n│   └── ptp_top.v              Subsystem wrapper\n├── rtp/\n│   ├── rtp_rx.v               UDP→RTP→L24→samples\n│   ├── rtp_tx.v               samples→L24→RTP→UDP\n│   ├── jitter_buffer.v        Per-channel BRAM jitter buffer\n│   └── rtp_engine.v           Wrapper\n├── audio/\n│   ├── audio_clk_gen.v        PTP-locked NCO (BCLK/LRCLK/MCLK)\n│   ├── i2s_tdm_master.v       I2S + TDM master (configurable slots)\n│   └── virt_i2s.v             CPU-accessible audio FIFO + mixer\n├── soc/\n│   ├── packet_router.v        RX classifier (PTP / RTP / CPU)\n│   └── cpu_netif.v            CPU Ethernet interface (BRAM-buffered)\n└── util/                      crc32, fifo_sync, fifo_async (CDC)\n```\n\n## Firmware (lwIP)\n\n```\nfirmware/\n├── main.c                  lwIP init, dhcp_start, mdns_resp, httpd_init\n├── litex_netif.c/.h        lwIP netif bridging cpu_netif BRAMs to pbufs\n├── sys_now.c               sys_now() and lwip_rand() backed by PTP clock\n├── aes67_status.c          /status.cgi JSON handler\n├── lwipopts.h              lwIP NO_SYS configuration (~32 KB heap)\n├── arch/cc.h, sys_arch.h   lwIP arch port for RV32/GCC\n└── Makefile                builds with $(LWIP_DIR)=/opt/lwip\n```\n\nThe firmware uses lwIP's built-in:\n- `dhcp.c` — full DHCP client\n- `etharp.c` — ARP cache + responder\n- `icmp.c` — ICMP echo replies\n- `igmp.c` — multicast group management\n- `apps/httpd/` — HTTP server with CGI\n- `apps/mdns/` — mDNS service responder\n\n`sys_now()` is backed by the hardware PTP clock — when the SoC is locked to\na grandmaster, all lwIP timers (DHCP renew, mDNS scheduling, TCP RTT) are\nPTP-disciplined.\n\n## Quick Start\n\n### 1. Build the toolchain image (one-time, ~3.5 GB)\n\n```bash\n./docker/build.sh\n```\n\nInstalls:\n- OSS CAD Suite (Yosys, nextpnr-ecp5, prjtrellis, Icarus, Verilator,\n  GTKWave, openFPGAloader)\n- LiteX ecosystem (migen, litex, litedram, liteeth)\n- **lwIP STABLE-2_2_0_RELEASE** at `/opt/lwip`\n- RISC-V GCC for VexRiscv firmware\n\n### 2. Build everything\n\n```bash\n./docker/run.sh make litex      # full SoC + gateware + lwIP firmware\n```\n\nThis produces `litex/build/colorlight_i9_v7_2/gateware/colorlight_i9_v7_2.bit`\nand `firmware/firmware.bin`.\n\n### 3. Program the board\n\nLinux (with the i9 ext-board's DAPLink connected over USB):\n\n```bash\n./docker/run.sh make program       # SRAM (volatile)\n./docker/run.sh make flash         # SPI flash (persistent)\n```\n\nmacOS / Windows: programming requires native USB. Either install\n`openFPGAloader` natively (Homebrew/MSYS2) and only use Docker for the build,\nor forward the USB device into a Linux VM running Docker.\n\n### 4. Watch DHCP work\n\n```bash\n./docker/run.sh openFPGAloader -b colorlight-i9 build/colorlight_i9_v7_2.bit\n# (or use the Makefile target)\n# then connect a USB-UART to the board's debug header to see:\n#\n#   === AES67 SoC firmware (lwIP) starting ===\n#   DHCP: started\n#   netif: link UP, ip=192.168.1.137\n#   mDNS: announced aes67.local\n#   httpd: listening\n#   Services up. Entering main loop.\n#   [192.168.1.137] PTP=LOCKED sec=... offset=12 delay=87 sync=42 ...\n```\n\nYou can then visit `http://aes67.local/` (or the DHCP-assigned IP) to see\nthe live status, and `discovery-tool` will see the `_ravenna._udp` service.\n\n## Cross-Platform Toolchain\n\n| Host | Build | Simulate | Program |\n|------|-------|----------|---------|\n| Linux x64    | ✓ | ✓ | ✓ native USB passthrough |\n| Linux ARM    | ✓ | ✓ | ✓ native USB passthrough |\n| macOS Intel  | ✓ | ✓ | use native openFPGAloader |\n| macOS Apple Silicon | ✓ | ✓ | use native openFPGAloader |\n| Windows (WSL2) | ✓ | ✓ | ✓ via usbipd-win |\n\n## Configuration\n\nAll AES67 parameters are CSR-mapped in the LiteX SoC. The firmware writes\nsensible defaults at startup; runtime changes can be made via the `/status`\nJSON endpoint (read) or by direct CSR access from the firmware.\n\n| CSR | Default | Notes |\n|-----|---------|-------|\n| `local_mac` | 02:AE:67:00:00:01 | unit MAC (locally administered) |\n| `local_ip` | 0.0.0.0 | written by DHCP after lease |\n| `rtp_mcast_ip` | 239.69.0.1 | AES67 default multicast group |\n| `rtp_dst_mac` | 01:00:5E:45:00:01 | derived from `rtp_mcast_ip` |\n| `rtp_port` | 5004 | RTP destination port |\n| `payload_type` | 98 | RTP PT for L24 |\n| `num_channels` | 2 | active channels per stream |\n| `samples_per_packet` | 48 | 1 ms @ 48 kHz |\n| `kp` / `ki` | 1.0 / ~0.004 | PTP servo gains (Q16.16) |\n| `step_threshold_ns` | 1000 | phase step trigger |\n| `nco_increment` | 422_212_466 | BCLK NCO base value |\n| `virtaud_mix_enable` | 0 | 1 = mix CPU into RTP TX |\n| `virtaud_chan_mask` | 0 | bit per channel that CPU drives |\n\n## Resource Estimate (LFE5U-45F)\n\n| Block | LUTs (est.) | BRAM |\n|-------|------------|------|\n| Custom Ethernet MAC | ~2,500 | 0 |\n| PTP subsystem | ~3,000 | 1 EBR |\n| TX wrappers + arbiter | ~1,200 | 0 |\n| Packet router | ~1,500 | 1 EBR |\n| RTP engine (1 stream) | ~3,500 | 8 EBR |\n| Audio NCO + I2S/TDM | ~1,500 | 0 |\n| Virtual I2S | ~800 | 1 EBR |\n| CPU netif | ~600 | 4 EBR |\n| LiteX VexRiscv (lite) | ~3,000 | 16 EBR |\n| LiteDRAM (SDRAM ctrl) | ~2,000 | 2 EBR |\n| **Total** | **~19 K / 44 K LUT** | **~33 / 108 EBR** |\n\nComfortable headroom for additional streams or PHY 1 bring-up\n(redundant Ethernet for ST 2022-7).\n\n## Status / Limitations\n\nImplemented and wired together:\n- Real ECP5 PLL (`EHXPLLL`)\n- Custom 1 Gbps RGMII MAC with PTP SFD pulses\n- Full IEEE 1588 in HW (slave mode)\n- PI servo with lock detector\n- RTP TX/RX with L24, jitter buffer\n- PTP-locked audio NCO + I2S/TDM master\n- Virtual I2S with mix/replace\n- 3-way TX arbiter\n- CPU netif (BRAM-mapped)\n- lwIP + DHCP + ARP + ICMP + IGMP + mDNS + HTTP\n- Docker toolchain (Linux/macOS/Windows)\n\nImplemented and integrated in the latest build:\n- **PTP grandmaster** + slave (`ptp_pp.v` handles Sync, Follow_Up, Delay_Req,\n  Delay_Resp generation; mode flips via `mode_is_master` CSR; BMC algorithm\n  in firmware drives the role decision)\n- **MDIO master** (`mdio_master.v` Clause 22 state machine, CSR-driven)\n  — the CPU can read PHY link status, configure autonegotiation, etc.\n- **Multi-stream RTP** (`rtp_multistream.v` wraps NUM_STREAMS = 2 engines;\n  each stream owns CHANNELS_PER_STREAM = 4 of the 8 TDM slots; per-stream\n  TX wrappers + a 2-way arbiter merge into the top-level RTP TX path)\n\nStill on the to-do list:\n- PHY 1 currently tied off — bring up for redundancy / second network\n- Re-enable SDRAM in the LiteX build (the pin map is now correct, but the\n  board's CKE/CS#/DQM tie-offs require a small custom PHY — see the\n  \"i9 v7.2 SDRAM quirks\" section below)\n\n## i9 v7.2 board quirks\n\nPin assignments in this repo are now verified against the official\n[Colorlight i9 v7.2 reference](https://github.com/wuxx/Colorlight-FPGA-Projects/blob/master/colorlight_i9_v7.2.md).\nA few things on this board are unusual and worth knowing about:\n\n### SDRAM (M12L64322A) – three signals are not on FPGA balls\n\nThe SDRAM is wired so that:\n\n| Signal | Where it goes |\n|--------|---------------|\n| CKE    | Tied to **VCC** on the PCB (always enabled) |\n| CS#    | Tied to **GND** (chip is always selected) |\n| DQM[0..3] | All tied to **GND** (no per-byte write masking) |\n\nThe FPGA cannot drive any of these — they aren't even routed to a ball.\nConsequently the standard LiteX `GENSDRPHY` (which assumes CKE/CS#/DQM\nexist) will not work on this board out of the box. A small board-specific\nPHY that omits those signals is needed; the `_io` Subsignal list in\n`litex/soc.py` deliberately reflects this wire-accurate truth.\n\nThe 27-signal pin map (CLK + RAS#/CAS#/WE# + BA[1:0] + A[10:0] + DQ[31:0])\nin both `constraints/colorlight_i9_v7.2.lpf` and `litex/soc.py` is correct.\n\n### Two Ethernet PHYs share one MDIO bus\n\nPHY 0 (U29) and PHY 1 (U30) both use the same MDC pin (P5), MDIO pin (N5),\nand reset pin (P4). Software must select the target PHY by address (typically\n0x00 for PHY 0 and 0x01 for PHY 1) when issuing reads/writes through the\n`mdio_master` peripheral.\n\n### LED D2 collides with SODIMM pin 41\n\nBoth the on-board LED D2 and SODIMM pin 41 are connected to FPGA ball **L2**.\nIf you use the SODIMM header for I/O, do not assign anything to L2 — that\nball is reserved for the LED. The pinout in this repo respects this.\n\n### SODIMM pins 13-39 are PHY magnetics, not GPIOs\n\nThe first ~13 GPIO-looking SODIMM pins (13-39) are actually the differential\npairs going from the on-board PHYs to the RJ45 jacks on the ext-board. They\nare post-PHY signals and are not visible to the FPGA. Only SODIMM pins 41-156\nare real GPIOs.\n\n## License\n\nMIT.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatanoisetv%2Fcolorlight-i9-aes67","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdatanoisetv%2Fcolorlight-i9-aes67","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatanoisetv%2Fcolorlight-i9-aes67/lists"}