bayerlink-fpga 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bayerlink_fpga/__init__.py +25 -0
- bayerlink_fpga/ddc.py +107 -0
- bayerlink_fpga/frontends/__init__.py +17 -0
- bayerlink_fpga/frontends/hdmi_rx.json +73 -0
- bayerlink_fpga/hdl/axis_spy.v +46 -0
- bayerlink_fpga/hdl/axis_unpack.v +37 -0
- bayerlink_fpga/hdl/bayerlink_in.v +843 -0
- bayerlink_fpga/hdl/ddc_phy.v +21 -0
- bayerlink_fpga/hdl/link_reset.v +93 -0
- bayerlink_fpga/hdl/rx_axis.v +50 -0
- bayerlink_fpga/hdl/stream_switch.v +58 -0
- bayerlink_fpga/hdl/tmds_align.v +291 -0
- bayerlink_fpga/hdl/tmds_bond.v +163 -0
- bayerlink_fpga/hdl/tmds_rx.v +203 -0
- bayerlink_fpga/hdl/tmds_rx.xdc +22 -0
- bayerlink_fpga/hdl/tmds_rx_lane.v +89 -0
- bayerlink_fpga/modules.json +245 -0
- bayerlink_fpga/receiver.py +257 -0
- bayerlink_fpga-0.3.0.dist-info/METADATA +234 -0
- bayerlink_fpga-0.3.0.dist-info/RECORD +23 -0
- bayerlink_fpga-0.3.0.dist-info/WHEEL +4 -0
- bayerlink_fpga-0.3.0.dist-info/licenses/LICENSE +45 -0
- bayerlink_fpga-0.3.0.dist-info/licenses/LICENSE-APACHE +202 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Copyright 2026 Serge Rabyking
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
|
3
|
+
"""bayerlink on FPGAs: the receiver and what any board needs around it.
|
|
4
|
+
|
|
5
|
+
Two layers, the second reusable by any board:
|
|
6
|
+
|
|
7
|
+
the receiver bayerlink_in (hdl/bayerlink_in.v, sized by
|
|
8
|
+
receiver.py), the DDC slave that is the receiver's
|
|
9
|
+
EDID and control port, and the Verilog around them
|
|
10
|
+
(hdl/): link reset and the capture path's AXIS
|
|
11
|
+
dressing. Nothing here knows a board.
|
|
12
|
+
frontends/ what turns a cable into parallel video -- pixel
|
|
13
|
+
clock, data enable, vsync, 24 bits -- and the facts
|
|
14
|
+
that follow from it, such as which lane carries
|
|
15
|
+
which container byte.
|
|
16
|
+
|
|
17
|
+
Nothing here knows a board. A board's own library says which front end
|
|
18
|
+
its jack uses, how it is configured there, and which pins it lands on.
|
|
19
|
+
Its design names the receiver and the DDC slave as leaves --
|
|
20
|
+
bayerlink_fpga.receiver:bayerlink_in and bayerlink_fpga.ddc:ddc_slave --
|
|
21
|
+
which its build sets from the design's settings.
|
|
22
|
+
"""
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
HDL = Path(__file__).resolve().parent / "hdl"
|
bayerlink_fpga/ddc.py
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Copyright 2026 Serge Rabyking
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
|
3
|
+
"""Generate the DDC slave: this receiver's calling card and control port.
|
|
4
|
+
|
|
5
|
+
The EDID stops being a borrowed monitor identity (a canned 720p file)
|
|
6
|
+
and becomes the receiver's own: the preferred detailed timing IS the
|
|
7
|
+
bayerlink container -- 1920x1081 at 30, one header row above the
|
|
8
|
+
payload -- so a source that honours EDID lands on the right raster
|
|
9
|
+
without being forced, and the monitor name says plainly what answered.
|
|
10
|
+
The same engine serves the register personality at 0x37: the ISP's
|
|
11
|
+
whole register file, readable and writable across the display cable,
|
|
12
|
+
refusal (SLVERR while the file is armed) answered as NACK.
|
|
13
|
+
|
|
14
|
+
The advertised raster is the build's link mode; the board design wires
|
|
15
|
+
the slave's AXI master to whatever register file it wants reachable.
|
|
16
|
+
"""
|
|
17
|
+
def container_timing(mode: str) -> dict:
|
|
18
|
+
"""The advertised raster, DERIVED from bayerlink's rasters.
|
|
19
|
+
|
|
20
|
+
These seven numbers used to be written here as constants, with a
|
|
21
|
+
comment saying they were "the same numbers scanout and the bridge
|
|
22
|
+
use" -- which is a promise a comment cannot keep. They are the
|
|
23
|
+
link_mode's timing with ONE EXTRA ACTIVE LINE: the bayerlink
|
|
24
|
+
container is the payload with its header row above it, and that row
|
|
25
|
+
is why a source honouring this EDID sends 1081 lines and not 1080.
|
|
26
|
+
|
|
27
|
+
The vertical blanking shrinks by that line rather than the total
|
|
28
|
+
growing, because the total is what a source locks to.
|
|
29
|
+
"""
|
|
30
|
+
from bayerlink.rasters import raster
|
|
31
|
+
|
|
32
|
+
t = raster(mode)
|
|
33
|
+
vact = t.v_active + 1 # + the header row
|
|
34
|
+
return {
|
|
35
|
+
"pclk_10khz": round(t.pixel_khz / 10),
|
|
36
|
+
"hact": t.h_active, "hblank": t.h_total - t.h_active,
|
|
37
|
+
"vact": vact, "vblank": t.v_total - vact,
|
|
38
|
+
"hso": t.hs_beg - t.h_active, "hsw": t.hs_end - t.hs_beg,
|
|
39
|
+
"vso": t.vs_beg - vact, "vsw": t.vs_end - t.vs_beg,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def build_edid(link_mode: str) -> bytes:
|
|
44
|
+
"""The receiver's own EDID, preferring the container of `link_mode`."""
|
|
45
|
+
t = container_timing(link_mode)
|
|
46
|
+
PCLK_10KHZ = t["pclk_10khz"]
|
|
47
|
+
HACT, HBLANK = t["hact"], t["hblank"]
|
|
48
|
+
VACT, VBLANK = t["vact"], t["vblank"]
|
|
49
|
+
HSO, HSW = t["hso"], t["hsw"]
|
|
50
|
+
VSO, VSW = t["vso"], t["vsw"]
|
|
51
|
+
e = bytearray(128)
|
|
52
|
+
e[0:8] = bytes([0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00])
|
|
53
|
+
# PnP id "BLK" -- three 5-bit letters, A=1
|
|
54
|
+
pnp = (2 << 10) | (12 << 5) | 11
|
|
55
|
+
e[8], e[9] = pnp >> 8, pnp & 0xFF
|
|
56
|
+
e[10:12] = (1).to_bytes(2, "little") # product: 1 = the rx
|
|
57
|
+
e[12:16] = (0).to_bytes(4, "little") # serial
|
|
58
|
+
e[16], e[17] = 1, 2026 - 1990 # week, year
|
|
59
|
+
e[18], e[19] = 1, 3 # EDID 1.3
|
|
60
|
+
e[20] = 0x80 # digital input
|
|
61
|
+
e[21], e[22] = 0x30, 0x1B # 48x27 cm, honesty optional
|
|
62
|
+
e[23] = 120 # gamma 2.2
|
|
63
|
+
e[24] = 0x0A # RGB, preferred timing
|
|
64
|
+
e[25:35] = bytes([0xEE, 0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26, 0x0F,
|
|
65
|
+
0x50, 0x54]) # sRGB-ish chromaticity
|
|
66
|
+
e[35:38] = bytes(3) # no established timings
|
|
67
|
+
e[38:54] = bytes([0x01, 0x01] * 8) # no standard timings
|
|
68
|
+
# The one detailed timing: the container itself.
|
|
69
|
+
e[54:72] = bytes([
|
|
70
|
+
PCLK_10KHZ & 0xFF, PCLK_10KHZ >> 8,
|
|
71
|
+
HACT & 0xFF, HBLANK & 0xFF,
|
|
72
|
+
((HACT >> 8) << 4) | (HBLANK >> 8),
|
|
73
|
+
VACT & 0xFF, VBLANK & 0xFF,
|
|
74
|
+
((VACT >> 8) << 4) | (VBLANK >> 8),
|
|
75
|
+
HSO & 0xFF, HSW & 0xFF,
|
|
76
|
+
((VSO & 0xF) << 4) | (VSW & 0xF),
|
|
77
|
+
((HSO >> 8) << 6) | ((HSW >> 8) << 4)
|
|
78
|
+
| ((VSO >> 4) << 2) | (VSW >> 4),
|
|
79
|
+
0, 0, 0, 0, 0,
|
|
80
|
+
0x1E, # separate sync, +h +v
|
|
81
|
+
])
|
|
82
|
+
e[72:90] = bytes([0, 0, 0, 0xFC, 0]) + b"BAYERLINK RX\n"
|
|
83
|
+
# the range limits: the container's own rates, a step either side
|
|
84
|
+
hz = round(t["pclk_10khz"] * 1e4 / ((HACT + HBLANK) * (VACT + VBLANK)))
|
|
85
|
+
khz = round(t["pclk_10khz"] * 10 / (HACT + HBLANK))
|
|
86
|
+
mhz10 = -(-t["pclk_10khz"] // 1000) # max clock, in 10 MHz
|
|
87
|
+
e[90:108] = (bytes([0, 0, 0, 0xFD, 0, hz - 1, hz + 1, khz - 5, khz + 5,
|
|
88
|
+
mhz10, 0, 0x0A]) + b"\x20" * 6)
|
|
89
|
+
e[108:126] = bytes([0, 0, 0, 0x10, 0]) + bytes(13)
|
|
90
|
+
e[126] = 0 # no extension blocks
|
|
91
|
+
e[127] = (-sum(e[:127])) % 256
|
|
92
|
+
return bytes(e)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def ddc_slave(link_mode: str) -> dict:
|
|
96
|
+
"""The DDC slave: this receiver's EDID at 0x50, its registers at 0x37.
|
|
97
|
+
|
|
98
|
+
A leaf a design names (`bayerlink_fpga.ddc:ddc_slave`) with the raster
|
|
99
|
+
the EDID advertises. Returns np2hw's result, every port published; the
|
|
100
|
+
EDID is the module's own ROM.
|
|
101
|
+
"""
|
|
102
|
+
from np2hw import ddc_slave as generate_ddc
|
|
103
|
+
return generate_ddc(reg_addr7=0x37, edid=build_edid(link_mode),
|
|
104
|
+
edid_addr7=0x50)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
ddc_slave.leaf = True
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Copyright 2026 Serge Rabyking
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
|
3
|
+
"""Front ends: what turns a cable into the receiver's parallel video.
|
|
4
|
+
|
|
5
|
+
hdmi_rx.json describes the block -- TMDS in; pixel clock, lock, data
|
|
6
|
+
enable, syncs and 24 data bits out -- and its implementations, each from
|
|
7
|
+
a vendor or of our own, each stating what follows from it: which video
|
|
8
|
+
lane carries which container byte, the frame pulse's polarity, the
|
|
9
|
+
reference clock it calibrates with. Every implementation offers the
|
|
10
|
+
block's ports, so the receiver and the designs above it do not change
|
|
11
|
+
when it does.
|
|
12
|
+
|
|
13
|
+
How a front end is configured on a particular board, and which pins it
|
|
14
|
+
lands on, is that board's: a board's jack names the block,
|
|
15
|
+
bayerlink_fpga.frontends.hdmi_rx, chooses its implementation and passes
|
|
16
|
+
its configuration.
|
|
17
|
+
"""
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"blocks": {
|
|
3
|
+
"hdmi_rx": {
|
|
4
|
+
"description": "An HDMI/DVI receiver: a TMDS link in, parallel video out -- pixel clock, lock, data enable, syncs, 24 data bits. Every implementation offers these same ports, so the bayerlink receiver and the designs above it do not change when it does. How it is configured on a board, and which pins it lands on, is that board's.",
|
|
5
|
+
"parameters": {
|
|
6
|
+
"implementation": {
|
|
7
|
+
"default": "'dvi2rgb'",
|
|
8
|
+
"description": "Which implementation fills this block."
|
|
9
|
+
},
|
|
10
|
+
"link_khz": {
|
|
11
|
+
"description": "The link's pixel clock, in kHz: the rate the source sends, which the implementation's clocking is set for."
|
|
12
|
+
},
|
|
13
|
+
"status": {
|
|
14
|
+
"default": 0,
|
|
15
|
+
"description": "1: the implementation's own account of the link, on the ports below marked by it -- for an implementation that keeps one."
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"inputs": [
|
|
19
|
+
{"name": "TMDS", "bus": "tmds", "description": "The link, from the jack's pins."},
|
|
20
|
+
{"name": "refclk", "description": "The reference clock the implementation calibrates its input delays with; its frequency is the implementation's fact refclk_mhz."},
|
|
21
|
+
{"name": "rst", "description": "Asynchronous, active high."}
|
|
22
|
+
],
|
|
23
|
+
"outputs": [
|
|
24
|
+
{"name": "pclk", "description": "The clock recovered from the link: it stops when the cable is pulled."},
|
|
25
|
+
{"name": "locked"},
|
|
26
|
+
{"name": "de"},
|
|
27
|
+
{"name": "hsync"},
|
|
28
|
+
{"name": "vsync"},
|
|
29
|
+
{"name": "data", "width": 24, "description": "Lane 0 is data[23:16], lane 1 [15:8], lane 2 [7:0]."},
|
|
30
|
+
{"name": "bonded", "when": "status", "description": "tmds_rx: the three lanes found in step."},
|
|
31
|
+
{"name": "clock_locked", "when": "status", "description": "tmds_rx: its clock manager locked to the link's clock."},
|
|
32
|
+
{"name": "aligned", "width": 3, "when": "status", "description": "tmds_rx: each lane aligned, lane 0 lowest."},
|
|
33
|
+
{"name": "eye", "width": 15, "when": "status", "description": "tmds_rx: each lane's eye, its taps that misread nothing, 5 bits a lane, lane 0 lowest."},
|
|
34
|
+
{"name": "slip", "width": 12, "when": "status", "description": "tmds_rx: each lane's bit slip, 4 bits a lane, lane 0 lowest."},
|
|
35
|
+
{"name": "survey_count", "width": 8, "when": "status", "description": "tmds_rx's survey, an entry at a time, each entry's fields together (hdl/tmds_rx.v): the misread tokens at this lane, slip and tap, 255 for no blank seen."},
|
|
36
|
+
{"name": "survey_tap", "width": 5, "when": "status", "description": "The survey entry's delay tap."},
|
|
37
|
+
{"name": "survey_slip", "width": 4, "when": "status", "description": "The survey entry's bit slip."},
|
|
38
|
+
{"name": "survey_lane", "width": 2, "when": "status", "description": "The survey entry's lane."},
|
|
39
|
+
{"name": "survey_lane_tap", "width": 5, "when": "status", "description": "The tap that lane samples at."},
|
|
40
|
+
{"name": "survey_lane_slip", "width": 4, "when": "status", "description": "The bit slip that lane samples at."},
|
|
41
|
+
{"name": "survey_lane_aligned", "when": "status", "description": "Whether that lane is aligned."}
|
|
42
|
+
],
|
|
43
|
+
"implementations": {
|
|
44
|
+
"dvi2rgb": {
|
|
45
|
+
"description": "Digilent's dvi2rgb on a 7-series part: TMDS decoded in the fabric (ISERDESE2, IDELAYE2, an MMCM). Needs Digilent's vivado-library in the IP catalogue. Lane map solved 2026-08-12 on a PYNQ-Z2 with the picam2hdmi source, counting and checker patterns: it follows this IP's bus order, not the board, so it holds on any board receiving through dvi2rgb. kClkRange follows the link: its MMCM multiplies the link clock by 5 x kClkRange and divides by kClkRange, so the five-times serial clock is the same whatever the range, and the range only keeps the VCO inside its 600-1200 MHz specification -- range 1 at a 74.25 MHz link would run it at 371 MHz. Range 2 at 74.25 MHz judged 30/30 frames bit-exact on the PYNQ-Z2 (2026-10-09). Below 25 MHz it has no range.",
|
|
46
|
+
"vivado": {"ip": "digilentinc.com:ip:dvi2rgb"},
|
|
47
|
+
"config": {
|
|
48
|
+
"kEmulateDDC": "'false'", "kAddBUFG": "'true'",
|
|
49
|
+
"kClkRange": "1 if link_khz >= 120000 else 2 if link_khz >= 60000 else 3 if link_khz >= 40000 else 4 if link_khz >= 30000 else 5"
|
|
50
|
+
},
|
|
51
|
+
"ports": {
|
|
52
|
+
"refclk": "RefClk", "rst": "aRst", "pclk": "PixelClk",
|
|
53
|
+
"locked": "aPixelClkLckd", "de": "vid_pVDE", "hsync": "vid_pHSync",
|
|
54
|
+
"vsync": "vid_pVSync", "data": "vid_pData"
|
|
55
|
+
},
|
|
56
|
+
"tie": {"pRst": 0},
|
|
57
|
+
"facts": {"lane_map": [1, 2, 0], "vsync_active_high": 1, "refclk_mhz": 200, "min_link_khz": 25000}
|
|
58
|
+
},
|
|
59
|
+
"tmds_rx": {
|
|
60
|
+
"description": "bayerlink-fpga's own TMDS receiver on a 7-series part (hdl/tmds_rx.v): an MMCM at five times the link clock into BUFIO and BUFR, an IDELAYE2 and a pair of ISERDESE2 a lane, and an alignment made for links that blank every line -- each delay tap of every bit slip given tens of lines to show blanks and count misread tokens, not 50 ms, so a mode change costs a fraction of a second rather than seconds, and each lane samples between the walls of its eye at the least delay -- then the lanes bonded by where their blanking ends, and decoded. Its lanes are the TMDS channels in order. RANGE keeps the MMCM's VCO in specification, as dvi2rgb's kClkRange does.",
|
|
61
|
+
"vivado": {"module": "tmds_rx"},
|
|
62
|
+
"sources": ["bayerlink_fpga:hdl/tmds_rx.v", "bayerlink_fpga:hdl/tmds_rx_lane.v", "bayerlink_fpga:hdl/tmds_align.v", "bayerlink_fpga:hdl/tmds_bond.v"],
|
|
63
|
+
"constraints": [{"file": "bayerlink_fpga:hdl/tmds_rx.xdc", "scoped_to": "tmds_rx"}],
|
|
64
|
+
"config": {
|
|
65
|
+
"LINK_KHZ": "link_khz",
|
|
66
|
+
"RANGE": "1 if link_khz >= 120000 else 2 if link_khz >= 60000 else 3 if link_khz >= 40000 else 4 if link_khz >= 30000 else 5"
|
|
67
|
+
},
|
|
68
|
+
"facts": {"lane_map": [0, 1, 2], "vsync_active_high": 1, "refclk_mhz": 200, "min_link_khz": 25000}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Copyright 2026 Serge Rabyking
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
|
3
|
+
// Pass-through AXIS spy: wires straight through, remembers what it saw.
|
|
4
|
+
// The status nibble answers the only bring-up question that matters:
|
|
5
|
+
// who is refusing -- the producer (no valid) or the consumer (no ready).
|
|
6
|
+
module axis_spy #(
|
|
7
|
+
parameter DW = 16
|
|
8
|
+
) (
|
|
9
|
+
input wire clk,
|
|
10
|
+
input wire rst,
|
|
11
|
+
input wire s_axis_tvalid,
|
|
12
|
+
output wire s_axis_tready,
|
|
13
|
+
input wire [DW-1:0] s_axis_tdata,
|
|
14
|
+
input wire [DW/8-1:0] s_axis_tkeep,
|
|
15
|
+
input wire s_axis_tlast,
|
|
16
|
+
output wire m_axis_tvalid,
|
|
17
|
+
input wire m_axis_tready,
|
|
18
|
+
output wire [DW-1:0] m_axis_tdata,
|
|
19
|
+
output wire [DW/8-1:0] m_axis_tkeep,
|
|
20
|
+
output wire m_axis_tlast,
|
|
21
|
+
output wire [15:0] status
|
|
22
|
+
);
|
|
23
|
+
assign m_axis_tvalid = s_axis_tvalid;
|
|
24
|
+
assign s_axis_tready = m_axis_tready;
|
|
25
|
+
assign m_axis_tdata = s_axis_tdata;
|
|
26
|
+
assign m_axis_tkeep = s_axis_tkeep;
|
|
27
|
+
assign m_axis_tlast = s_axis_tlast;
|
|
28
|
+
|
|
29
|
+
reg v_seen, r_seen, beat_seen, last_seen;
|
|
30
|
+
reg [11:0] beats;
|
|
31
|
+
always @(posedge clk) begin
|
|
32
|
+
if (rst) begin
|
|
33
|
+
v_seen <= 0; r_seen <= 0; beat_seen <= 0; last_seen <= 0;
|
|
34
|
+
beats <= 0;
|
|
35
|
+
end else begin
|
|
36
|
+
if (s_axis_tvalid) v_seen <= 1;
|
|
37
|
+
if (m_axis_tready) r_seen <= 1;
|
|
38
|
+
if (s_axis_tvalid && m_axis_tready) begin
|
|
39
|
+
beat_seen <= 1;
|
|
40
|
+
beats <= beats + 1;
|
|
41
|
+
end
|
|
42
|
+
if (s_axis_tvalid && m_axis_tready && s_axis_tlast) last_seen <= 1;
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
assign status = {beats, last_seen, beat_seen, r_seen, v_seen};
|
|
46
|
+
endmodule
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Copyright 2026 Serge Rabyking
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
|
3
|
+
// The inverse of rx_axis: the 32-bit DMA word format back into the
|
|
4
|
+
// elastic stream, on the far side of a clock converter. Sample in
|
|
5
|
+
// [15:0], eol at 16, sof at 17, last as tlast -- one layout, two
|
|
6
|
+
// directions, rx_axis owns the definition.
|
|
7
|
+
module axis_unpack #(
|
|
8
|
+
parameter SAMPLE_BITS = 16
|
|
9
|
+
) (
|
|
10
|
+
(* X_INTERFACE_INFO = "xilinx.com:signal:clock:1.0 clk CLK", X_INTERFACE_PARAMETER = "ASSOCIATED_BUSIF s_axis:out_stream, ASSOCIATED_RESET rst" *)
|
|
11
|
+
input wire clk,
|
|
12
|
+
(* X_INTERFACE_INFO = "xilinx.com:signal:reset:1.0 rst RST", X_INTERFACE_PARAMETER = "POLARITY ACTIVE_HIGH" *)
|
|
13
|
+
input wire rst,
|
|
14
|
+
input wire s_axis_tvalid,
|
|
15
|
+
output wire s_axis_tready,
|
|
16
|
+
input wire [31:0] s_axis_tdata,
|
|
17
|
+
input wire s_axis_tlast,
|
|
18
|
+
(* X_INTERFACE_INFO = "lanserge:interface:np2hw_stream_rtl:1.0 out_stream VALID" *)
|
|
19
|
+
output wire out_valid,
|
|
20
|
+
(* X_INTERFACE_INFO = "lanserge:interface:np2hw_stream_rtl:1.0 out_stream READY" *)
|
|
21
|
+
input wire out_ready,
|
|
22
|
+
(* X_INTERFACE_INFO = "lanserge:interface:np2hw_stream_rtl:1.0 out_stream DATA" *)
|
|
23
|
+
output wire [SAMPLE_BITS-1:0] out_data,
|
|
24
|
+
(* X_INTERFACE_INFO = "lanserge:interface:np2hw_stream_rtl:1.0 out_stream SOF" *)
|
|
25
|
+
output wire out_sof,
|
|
26
|
+
(* X_INTERFACE_INFO = "lanserge:interface:np2hw_stream_rtl:1.0 out_stream EOL" *)
|
|
27
|
+
output wire out_eol,
|
|
28
|
+
(* X_INTERFACE_INFO = "lanserge:interface:np2hw_stream_rtl:1.0 out_stream LAST" *)
|
|
29
|
+
output wire out_last
|
|
30
|
+
);
|
|
31
|
+
assign out_valid = s_axis_tvalid;
|
|
32
|
+
assign s_axis_tready = out_ready;
|
|
33
|
+
assign out_data = s_axis_tdata[SAMPLE_BITS-1:0];
|
|
34
|
+
assign out_eol = s_axis_tdata[16];
|
|
35
|
+
assign out_sof = s_axis_tdata[17];
|
|
36
|
+
assign out_last = s_axis_tlast;
|
|
37
|
+
endmodule
|