Repository navigation
Expand file tree
/
Copy pathplatform.py
More file actions
486 lines (404 loc) · 19.2 KB
/
Copy pathplatform.py
File metadata and controls
486 lines (404 loc) · 19.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
"""Platform / IO definitions and HDL-only build stubs (no synthesis).
The SoC is generated HDL-only: these platforms define just the pin map and a
``build()`` that emits Verilog without invoking the vendor toolchain.
"""
import os
import shutil
from litex.build.generic_platform import Pins, Subsignal, IOStandard
from litex.build.altera import AlteraPlatform
from litex.build.gowin.platform import GowinPlatform
from litex.build.lattice import LatticePlatform
# -- Shared I/O: everything except clock and main RAM (identical across targets) --
_io_common = [
# MAC clock inputs (directly from FPGA Ethernet MAC).
("clk_mac_rx", 0, Pins(1)),
("clk_mac_tx", 0, Pins(1)),
# Serial / UART
("serial", 0,
Subsignal("tx", Pins(1)),
Subsignal("rx", Pins(1)),
),
# I2C: single shared bus (SSD1306 + Si5351A + AD/DA card controller)
("i2c", 0,
Subsignal("scl", Pins(1)),
Subsignal("sda", Pins(1)),
),
# SPI: SD Card
("spi", 0,
Subsignal("clk", Pins(1)),
Subsignal("mosi", Pins(1)),
Subsignal("miso", Pins(1)),
Subsignal("cs_n", Pins(1)),
),
# SPI Flash: W25Q64 (8 MB, memory-mapped)
("spiflash", 0,
Subsignal("clk", Pins(1)),
Subsignal("mosi", Pins(1)),
Subsignal("miso", Pins(1)),
Subsignal("cs_n", Pins(1)),
),
# UART 1: AD/DA Card LEDs (115200 baud)
("serial", 1,
Subsignal("tx", Pins(1)),
Subsignal("rx", Pins(1)),
),
# AES67 CSR I/O (directly active to/from external FPGA logic)
("aes67_ctrl", 0,
# Inputs (from external FPGA logic -> SoC)
Subsignal("pll_ppb_valid", Pins(1)),
Subsignal("pll_ppb_wc_count", Pins(25)),
Subsignal("pll_ppb_pll_count", Pins(25)),
Subsignal("wallclock_locked", Pins(1)),
Subsignal("wallclock_configured", Pins(1)),
Subsignal("eth_link_up", Pins(1)),
Subsignal("eth_speed", Pins(2)),
Subsignal("ptp_path_delay", Pins(32)),
Subsignal("ptp_offset", Pins(32)),
Subsignal("eth_tx_done", Pins(1)),
Subsignal("eth_rx_overflow", Pins(1)),
# RX stream-underrun diagnostics (stream_underrun / mute_channels, LSBs)
Subsignal("rx_underrun", Pins(4)),
Subsignal("rx_mute", Pins(8)),
# PTP BMA results (FPGA -> SoC, read-only status)
Subsignal("ptp_is_leader", Pins(1)),
Subsignal("ptp_is_follower", Pins(1)),
Subsignal("ptp_leader_id", Pins(64)),
# Outputs (SoC -> external FPGA logic)
Subsignal("pll_ppb_start", Pins(1)),
Subsignal("mac_addr", Pins(48)),
Subsignal("ip_addr", Pins(32)),
Subsignal("ptp_time_source", Pins(8)),
Subsignal("ptp_log_msg_interval", Pins(8)),
Subsignal("ptp_announce_msg_interval", Pins(8)),
Subsignal("ptp_gm_priority1", Pins(8)),
Subsignal("ptp_gm_priority2", Pins(8)),
Subsignal("ptp_gm_clock_class", Pins(8)),
Subsignal("ptp_gm_clock_accuracy", Pins(8)),
Subsignal("eth_tx_request", Pins(1)),
Subsignal("adda_nrst", Pins(1)), # AD/DA card nRST (output, active-high release)
# Reset outputs (SoC -> FPGA, active high). Driven by the single "reset"
# CSR bitmask (bit0=ptp, bit1=tx, bit2=rx, bit3=eth).
Subsignal("ptp_reset", Pins(1)), # reset PTP module + wallclock
Subsignal("tx_reset", Pins(1)), # reset audio TX path
Subsignal("rx_reset", Pins(1)), # reset audio RX path
Subsignal("eth_reset", Pins(1)), # reset Ethernet MAC/PHY path
# PTP servo / parser tuning (SoC -> FPGA)
Subsignal("servo_kp_gain", Pins(8)),
Subsignal("servo_ki_gain", Pins(8)),
Subsignal("servo_gain_shift", Pins(5)),
Subsignal("servo_gain_shift_locked", Pins(5)),
Subsignal("servo_ki_extra_shift", Pins(5)),
Subsignal("servo_filter_shift", Pins(5)),
Subsignal("servo_warmup_samples", Pins(8)),
Subsignal("servo_lock_threshold_ns", Pins(32)),
Subsignal("servo_unlock_threshold_ns", Pins(32)),
Subsignal("servo_lock_count_threshold", Pins(8)),
Subsignal("parser_min_filter_enable", Pins(1)),
Subsignal("parser_min_filter_active_depth", Pins(8)),
Subsignal("parser_delay_asymmetry_ns", Pins(32)),
# PTP servo monitoring (FPGA -> SoC)
Subsignal("servo_mon_filtered_offset", Pins(32)),
Subsignal("servo_mon_integral_sum", Pins(32)),
Subsignal("servo_mon_pi_proportional", Pins(32)),
Subsignal("servo_mon_pi_sum_raw", Pins(32)),
Subsignal("servo_mon_effective_gain_shift", Pins(8)),
Subsignal("servo_mon_lock_counter", Pins(16)),
Subsignal("servo_mon_sample_count", Pins(16)),
Subsignal("servo_mon_first_lock_achieved", Pins(1)),
# Audio metering (from external FPGA logic -> SoC)
Subsignal("rx_meter_signal", Pins(16)), # RX signal detect (1 bit per channel)
Subsignal("rx_meter_clip", Pins(16)), # RX clip detect (1 bit per channel)
Subsignal("tx_meter_signal", Pins(16)), # TX signal detect (1 bit per channel)
Subsignal("tx_meter_clip", Pins(16)), # TX clip detect (1 bit per channel)
Subsignal("meter_clear", Pins(1)), # Metering clear toggle (SoC -> FPGA)
# Static FPGA build configuration (FPGA -> SoC, constant per bitstream;
# layout per system_cfg_pkg.vhd's system_cfg_to_vector())
Subsignal("system_cfg", Pins(72)),
# PTP-in-software wallclock interface (FPGA -> SoC)
Subsignal("wallclock_seconds_in", Pins(48)),
Subsignal("wallclock_nanoseconds_in", Pins(30)),
Subsignal("tx_timestamp_sec_in", Pins(4)),
Subsignal("tx_timestamp_nsec_in", Pins(30)),
# PTP-in-software wallclock control (SoC -> FPGA)
Subsignal("wallclock_seconds_out", Pins(48)),
Subsignal("wallclock_nanoseconds_out", Pins(30)),
Subsignal("wallclock_set", Pins(1)),
Subsignal("wallclock_phasejump", Pins(1)),
Subsignal("wallclock_ppb", Pins(20)),
# Software-smoothed NCO (media clock) correction (SoC -> FPGA)
Subsignal("nco_ppb_adj", Pins(48)),
Subsignal("nco_ppb_adj_valid", Pins(1)),
),
# TX stream config RAM (SoC writes, tx_router reads via FPGA-side port)
("tx_stream_cfg", 0,
Subsignal("wr_en", Pins(1)), # output: write enable
Subsignal("wr_addr", Pins(8)), # output: write address (0..255)
Subsignal("wr_data", Pins(8)), # output: write data
),
# RX stream config RAM (SoC writes, rx_ringbuffer reads via FPGA-side port)
("rx_stream_cfg", 0,
Subsignal("wr_en", Pins(1)), # output: write enable
Subsignal("wr_addr", Pins(8)), # output: write address (0..255)
Subsignal("wr_data", Pins(8)), # output: write data
),
# eth_buf RX-ready interrupt line, crossing the SoC<->bridge boundary.
# The bridge (where eth_buf lives) drives this OUT; the SoC takes it IN and
# feeds it to the VexRiscv external interrupt array (so the firmware keeps
# its RX IRQ instead of polling rx_ready over the slow Wishbone bus).
("eth_buf_irq", 0, Pins(1)),
# AES67 external Wishbone window — the bus boundary between the SoC (master)
# and the standalone AES67 bridge (slave). One contiguous 64 KiB window at
# 0x90000000 carries the whole AES67 surface (eth_buf buffer, stream RAMs,
# and the bridge's WB->CSR sub-bridge for aes67_csr). Only requested by the
# SoC built with aes67_external=True and by the aes67_bridge target.
# 30-bit word address (4 GiB / 32-bit words). Signal directions per the
# Wishbone layout: adr/dat_w/sel/cyc/stb/we/cti/bte are M->S, dat_r/ack/err S->M.
("aes67_wb", 0,
Subsignal("adr", Pins(30)),
Subsignal("dat_w", Pins(32)),
Subsignal("dat_r", Pins(32)),
Subsignal("sel", Pins(4)),
Subsignal("cyc", Pins(1)),
Subsignal("stb", Pins(1)),
Subsignal("we", Pins(1)),
Subsignal("cti", Pins(3)),
Subsignal("bte", Pins(2)),
Subsignal("ack", Pins(1)),
Subsignal("err", Pins(1)),
),
# SPIBone: 4-wire SPI -> Wishbone bridge (only requested by the spibone
# target, where an external host replaces the VexRiscv softcore as the
# sole Wishbone master). Declared here so it is available to any target;
# LiteX only emits requested resources as ports, so the 3 CPU targets that
# never request it are unaffected.
("spibone", 0,
Subsignal("clk", Pins(1)),
Subsignal("cs_n", Pins(1)),
Subsignal("mosi", Pins(1)),
Subsignal("miso", Pins(1)),
),
# UARTBone: 2-wire async serial -> Wishbone bridge (only requested by the
# uartbone target, where an external host replaces the VexRiscv softcore as
# the sole Wishbone master). Declared here so it is available to any target;
# LiteX only emits requested resources as ports, so targets that never
# request it are unaffected.
("uartbone", 0,
Subsignal("tx", Pins(1)),
Subsignal("rx", Pins(1)),
),
# Ethernet packet buffer I/O (directly active to/from external FPGA logic)
("eth_buf", 0,
# RX buffer: FPGA writes, SoC reads
Subsignal("rx_data", Pins(8)), # input: data byte from FPGA
Subsignal("rx_addr", Pins(11)), # input: write address from FPGA (0..1499)
Subsignal("rx_we", Pins(1)), # input: write enable from FPGA
Subsignal("rx_len", Pins(11)), # input: received packet length
Subsignal("rx_valid", Pins(1)), # input: packet ready (level)
Subsignal("rx_ack", Pins(1)), # output: SoC done reading
# TX buffer: SoC writes, FPGA reads
Subsignal("tx_data", Pins(8)), # output: data byte to FPGA
Subsignal("tx_addr", Pins(11)), # input: read address from FPGA (0..1499)
Subsignal("tx_len", Pins(11)), # output: packet length
),
]
# Target-specific I/O: clock + main RAM
_io_cyclone10 = [
("clk_sys", 0, Pins(1)),
("hyperram", 0,
Subsignal("clk", Pins(1)),
Subsignal("rst_n", Pins(1)),
Subsignal("dq", Pins(8)),
Subsignal("cs_n", Pins(1)),
Subsignal("rwds", Pins(1)),
),
] + _io_common
_io_cyc1000 = [
("clk_sys", 0, Pins(1)),
("clk_sys_ps", 0, Pins(1)), # 90deg phase-shifted sys clock for SDRAM (from top-level PLL)
("sdram_clock", 0, Pins(1)),
("sdram", 0,
Subsignal("a", Pins(14)),
Subsignal("ba", Pins(2)),
Subsignal("cs_n", Pins(1)),
Subsignal("cke", Pins(1)),
Subsignal("ras_n", Pins(1)),
Subsignal("cas_n", Pins(1)),
Subsignal("we_n", Pins(1)),
Subsignal("dq", Pins(16)),
Subsignal("dm", Pins(2)),
),
] + _io_common
_io_gowin = [
("clk_sys", 0, Pins(1)),
("clk_sys2x", 0, Pins(1)), # 2x sys clock for DDR3 (from top-level PLL)
("ddram", 0,
Subsignal("a", Pins(14)),
Subsignal("ba", Pins(3)),
Subsignal("ras_n", Pins(1)),
Subsignal("cas_n", Pins(1)),
Subsignal("we_n", Pins(1)),
Subsignal("cs_n", Pins(1)),
Subsignal("dm", Pins(2)),
Subsignal("dq", Pins(16)),
Subsignal("dqs_p", Pins(2)),
Subsignal("dqs_n", Pins(2)),
Subsignal("clk_p", Pins(1)),
Subsignal("clk_n", Pins(1)),
Subsignal("cke", Pins(1)),
Subsignal("odt", Pins(1)),
Subsignal("reset_n", Pins(1)),
),
] + _io_common
# spibone target: CPU-less register bridge. No main-RAM pins; clk_sys feeds the
# sys domain. The MAC clocks in _io_common stay unrequested here (spibone has no
# eth_buf). The external host drives the bus over the "spibone" SPI pads.
_io_spibone = [
("clk_sys", 0, Pins(1)),
] + _io_common
# uartbone target: CPU-less register bridge, serial counterpart of spibone. No
# main-RAM pins; clk_sys feeds the sys domain. The MAC clocks in _io_common stay
# unrequested here (uartbone has no eth_buf). The external host drives the bus
# over the "uartbone" serial pads.
_io_uartbone = [
("clk_sys", 0, Pins(1)),
] + _io_common
# aes67_bridge target: the AES67 register surface split off as a standalone
# Wishbone-slave module. Same IO superset as spibone (clk_sys + MAC clocks +
# the AES67 direct signals + the aes67_wb_* bus pads); LiteX only emits the
# resources actually requested by the build, so the unused pads (spiflash, i2c,
# spi, serial, …) never appear as ports.
_io_bridge = [
("clk_sys", 0, Pins(1)),
] + _io_common
# -- Shared build helper (HDL-only, no synthesis) -----------------------------
def _stub_build(platform, fragment, build_dir="build", build_name="litex_soc", run=True, **kwargs):
os.makedirs(build_dir, exist_ok=True)
cwd = os.getcwd()
os.chdir(build_dir)
from migen.fhdl.structure import _Fragment
if not isinstance(fragment, _Fragment):
fragment = fragment.get_fragment()
platform.finalize(fragment)
v_output = platform.get_verilog(fragment, name=build_name)
v_output.write(f"{build_name}.v")
# Copy all registered source files (e.g. VexRiscv CPU) into build dir
for src_path, language, library, *_ in platform.sources:
dst = os.path.join(build_dir, os.path.basename(src_path))
if os.path.abspath(src_path) != os.path.abspath(dst):
shutil.copy2(src_path, dst)
os.chdir(cwd)
return v_output.ns
class Cyclone10StubPlatform(AlteraPlatform):
"""Altera-based platform stub for HDL-only generation (no synthesis)."""
default_clk_name = "clk_sys"
default_clk_period = 1e9 / 75e6
def __init__(self):
AlteraPlatform.__init__(self, "10CL025YU256I7G", _io_cyclone10, toolchain="quartus")
def create_programmer(self):
raise NotImplementedError
def build(self, fragment, **kwargs):
return _stub_build(self, fragment, **kwargs)
class SpiboneStubPlatform(AlteraPlatform):
"""Platform stub for the CPU-less spibone bridge (HDL-only generation).
The FPGA device is irrelevant for HDL-only generation (no synthesis), so we
reuse the Cyclone 10LP part. The generated bridge is device-agnostic.
"""
default_clk_name = "clk_sys"
default_clk_period = 1e9 / 75e6
def __init__(self):
AlteraPlatform.__init__(self, "10CL025YU256I7G", _io_spibone, toolchain="quartus")
def create_programmer(self):
raise NotImplementedError
def build(self, fragment, **kwargs):
return _stub_build(self, fragment, **kwargs)
class UartboneStubPlatform(AlteraPlatform):
"""Platform stub for the CPU-less uartbone bridge (HDL-only generation).
Serial counterpart of :class:`SpiboneStubPlatform`. The FPGA device is
irrelevant for HDL-only generation (no synthesis), so we reuse the Cyclone
10LP part. The generated bridge is device-agnostic.
"""
default_clk_name = "clk_sys"
default_clk_period = 1e9 / 75e6
def __init__(self):
AlteraPlatform.__init__(self, "10CL025YU256I7G", _io_uartbone, toolchain="quartus")
def create_programmer(self):
raise NotImplementedError
def build(self, fragment, **kwargs):
return _stub_build(self, fragment, **kwargs)
class BridgeStubPlatform(AlteraPlatform):
"""Platform stub for the standalone AES67 Wishbone bridge (HDL-only).
Device is irrelevant for HDL-only generation; reuse the Cyclone 10LP part.
"""
default_clk_name = "clk_sys"
default_clk_period = 1e9 / 75e6
def __init__(self):
AlteraPlatform.__init__(self, "10CL025YU256I7G", _io_bridge, toolchain="quartus")
def create_programmer(self):
raise NotImplementedError
def build(self, fragment, **kwargs):
return _stub_build(self, fragment, **kwargs)
# -- Lattice (ECP5 / Diamond) stub platforms ----------------------------------
#
# These mirror the device-agnostic CPU-less Altera stubs above, but use a
# Lattice/Diamond platform so LiteX lowers migen's AsyncResetSynchronizer to the
# ECP5-native FD1S3BX flip-flop instead of the Altera `DFF` primitive (which
# Diamond does not recognise → "Reference to undefined module DFF").
#
# The generated SoC is otherwise identical to the Altera variant: the CRGs for
# these targets only use external clocks + AsyncResetSynchronizer (no vendor PLL
# is baked into the SoC, see crg.py). The ECP5 device string below is
# irrelevant for HDL-only generation (no synthesis / no pin constraints emitted);
# pick the real part in the Diamond project itself.
_LATTICE_STUB_DEVICE = "LFE5U-25F-6BG256C"
class SpiboneLatticeStubPlatform(LatticePlatform):
"""Lattice/Diamond counterpart of :class:`SpiboneStubPlatform`."""
default_clk_name = "clk_sys"
default_clk_period = 1e9 / 75e6
def __init__(self):
LatticePlatform.__init__(self, _LATTICE_STUB_DEVICE, _io_spibone, toolchain="diamond")
def create_programmer(self):
raise NotImplementedError
def build(self, fragment, **kwargs):
return _stub_build(self, fragment, **kwargs)
class UartboneLatticeStubPlatform(LatticePlatform):
"""Lattice/Diamond counterpart of :class:`UartboneStubPlatform`."""
default_clk_name = "clk_sys"
default_clk_period = 1e9 / 75e6
def __init__(self):
LatticePlatform.__init__(self, _LATTICE_STUB_DEVICE, _io_uartbone, toolchain="diamond")
def create_programmer(self):
raise NotImplementedError
def build(self, fragment, **kwargs):
return _stub_build(self, fragment, **kwargs)
class BridgeLatticeStubPlatform(LatticePlatform):
"""Lattice/Diamond counterpart of :class:`BridgeStubPlatform`."""
default_clk_name = "clk_sys"
default_clk_period = 1e9 / 75e6
def __init__(self):
LatticePlatform.__init__(self, _LATTICE_STUB_DEVICE, _io_bridge, toolchain="diamond")
def create_programmer(self):
raise NotImplementedError
def build(self, fragment, **kwargs):
return _stub_build(self, fragment, **kwargs)
class Cyc1000StubPlatform(AlteraPlatform):
"""Altera-based platform stub for Trenz CYC1000 (SDRAM)."""
default_clk_name = "clk_sys"
default_clk_period = 1e9 / 75e6
def __init__(self):
# CYC1000 uses -C8 speed grade (commercial).
AlteraPlatform.__init__(self, "10CL025YU256C8G", _io_cyc1000, toolchain="quartus")
def create_programmer(self):
raise NotImplementedError
def build(self, fragment, **kwargs):
return _stub_build(self, fragment, **kwargs)
class GowinStubPlatform(GowinPlatform):
"""Gowin-based platform stub for HDL-only generation (no synthesis)."""
default_clk_name = "clk_sys"
default_clk_period = 1e9 / 75e6
def __init__(self):
GowinPlatform.__init__(self, "GW2A-LV18PG256C8/I7", _io_gowin,
toolchain="gowin", devicename="GW2A-18C")
def create_programmer(self):
raise NotImplementedError
def build(self, fragment, **kwargs):
return _stub_build(self, fragment, **kwargs)