Added Uart.

This commit is contained in:
2026-06-14 09:37:59 +02:00
parent a7c88109a9
commit 85f82c8740
3 changed files with 468 additions and 26 deletions
+52 -21
View File
@@ -12,14 +12,15 @@ See CLAUDE.md "Module Breakdown" and "CDC Signal Inventory" for the full list.
from amaranth import *
from exi_bba.exi_capture import ExiCapture
from exi_bba.bba_register_file import BBARegisterFile
from exi_bba.spram_arbiter import SPRAMArbiter
from exi_bba.rx_frame_assembler import RXFrameAssembler
from exi_bba.tx_frame_drain import TXFrameDrain
from exi_bba.w5500_spi_master import W5500SPIMaster
from exi_bba.exi_capture import ExiCapture
from exi_bba.bba_register_file import BBARegisterFile
from exi_bba.spram_arbiter import SPRAMArbiter
from exi_bba.rx_frame_assembler import RXFrameAssembler
from exi_bba.tx_frame_drain import TXFrameDrain
from exi_bba.w5500_spi_master import W5500SPIMaster
from exi_bba.w5100_parallel_master import W5100ParallelMaster
from exi_bba.status_panel import StatusPanel
from exi_bba.status_panel import StatusPanel
from exi_bba.uart_console import UARTConsole
from amaranth.lib.cdc import FFSynchronizer
@@ -43,7 +44,8 @@ class BBATop(Elaboratable):
w5500_rst_n : W5500 hardware reset (output, active low)
"""
def __init__(self, eth="w5100", reset_cycles=24000, status_panel=False):
def __init__(self, eth="w5100", reset_cycles=24000,
status_panel=False, uart_console=False):
# Ethernet back-end: "w5100" (indirect parallel bus, reaches the EXI
# ceiling) or "w5500" (SPI, ~12 Mbit/s). Both expose the identical
# tx/rx/init/par interface, so only the physical pins differ.
@@ -54,6 +56,9 @@ class BBATop(Elaboratable):
# Optional bring-up status panel (drives onboard LEDs/button on the
# iCEbreaker — see synth.py). panel_led bit order matches StatusPanel.
self._status_panel = status_panel
# Optional UART debug console (8N1 115200, sync domain).
# uart_tx → FT2232H Channel B pin 9; uart_rx ← pin 6.
self._uart_console = uart_console
# EXI (GC side)
self.exi_clk = Signal(init=1)
@@ -89,6 +94,10 @@ class BBATop(Elaboratable):
self.panel_led = Signal(5) # to onboard LEDs (see StatusPanel)
self.panel_btn = Signal(3) # from onboard button(s)
if uart_console:
self.uart_tx = Signal(init=1) # FPGA → PC (FT2232H Channel B)
self.uart_rx = Signal(init=1) # PC → FPGA
def elaborate(self, platform):
m = Module()
@@ -277,25 +286,28 @@ class BBATop(Elaboratable):
# The RX ring-buffer path is active only after the GC sets NCRA[3].
m.d.comb += asm.rx_enabled.eq(reg.ncra_sr)
# ── Optional bring-up status panel (sync domain) ──────────────────
# init_req = NCRA reset (exi→sync PS), OR'd with the panel's manual
# re-init button when the panel is present.
# ── Optional bring-up peripherals (sync domain) ──────────────────
# Build init_req as an OR of all reinit sources (NCRA pulse plus any
# manual re-init from the status panel and/or the UART 'r' command).
# "ready" is latched high by eth.init_done and cleared by any init_req.
# It is computed only when at least one peripheral needs it.
init_req = reg.ncra_rst_o # base: GC-issued NCRA reset
need_ready = self._status_panel or self._uart_console
if need_ready:
ready = Signal()
if self._status_panel:
panel = StatusPanel()
m.submodules.panel = panel
init_req = init_req | panel.reinit
# cs_active lives in the exi domain; bring it to sync for the LED.
cs_a_sync = Signal()
m.submodules.panel_cs = FFSynchronizer(
cap.cs_active, cs_a_sync, o_domain="sync")
# "ready" = ethernet init complete (latched until the next init).
ready = Signal()
with m.If(eth.init_done):
m.d.sync += ready.eq(1)
with m.Elif(reg.ncra_rst_o | panel.reinit):
m.d.sync += ready.eq(0)
m.d.comb += [
panel.cs_active.eq(cs_a_sync),
panel.rx_pulse .eq(asm.rx_irq),
@@ -303,10 +315,29 @@ class BBATop(Elaboratable):
panel.ready .eq(ready),
panel.btn .eq(self.panel_btn),
self.panel_led .eq(panel.led),
eth.init_req .eq(reg.ncra_rst_o | panel.reinit),
]
else:
m.d.comb += eth.init_req.eq(reg.ncra_rst_o)
if self._uart_console:
console = UARTConsole()
m.submodules.console = console
init_req = init_req | console.reinit
m.d.comb += [
console.ncra_rst.eq(reg.ncra_rst_o),
console.rx_pulse.eq(asm.rx_irq),
console.tx_pulse.eq(drain.tx_irq),
console.ready .eq(ready),
self.uart_tx .eq(console.uart_tx),
console.uart_rx .eq(self.uart_rx),
]
if need_ready:
with m.If(eth.init_done):
m.d.sync += ready.eq(1)
with m.Elif(init_req):
m.d.sync += ready.eq(0)
m.d.comb += eth.init_req.eq(init_req)
return m