2 from nmigen
.hdl
.rec
import *
3 from nmigen
.lib
import fifo
6 __all__
= ["Endpoint", "SyncFIFO", "AsyncFIFO", "Buffer"]
9 def _make_fanout(layout
):
12 if isinstance(f
[1], (int, tuple)):
13 r
.append((f
[0], f
[1], DIR_FANOUT
))
15 r
.append((f
[0], _make_fanout(f
[1])))
19 class EndpointDescription
:
20 def __init__(self
, payload_layout
):
21 self
.payload_layout
= payload_layout
23 def get_full_layout(self
):
24 reserved
= {"valid", "ready", "first", "last", "payload"}
26 for f
in self
.payload_layout
:
27 if f
[0] in attributed
:
28 raise ValueError(f
[0] + " already attributed in payload layout")
30 raise ValueError(f
[0] + " cannot be used in endpoint layout")
34 ("valid", 1, DIR_FANOUT
),
35 ("ready", 1, DIR_FANIN
),
36 ("first", 1, DIR_FANOUT
),
37 ("last", 1, DIR_FANOUT
),
38 ("payload", _make_fanout(self
.payload_layout
))
43 class Endpoint(Record
):
44 def __init__(self
, layout_or_description
, **kwargs
):
45 if isinstance(layout_or_description
, EndpointDescription
):
46 self
.description
= layout_or_description
48 self
.description
= EndpointDescription(layout_or_description
)
49 super().__init
__(self
.description
.get_full_layout(), src_loc_at
=1, **kwargs
)
51 def __getattr__(self
, name
):
53 return super().__getattr
__(name
)
54 except AttributeError:
55 return self
.fields
["payload"][name
]
59 def __init__(self
, payload_layout
):
60 self
.sink
= Endpoint(payload_layout
)
61 self
.source
= Endpoint(payload_layout
)
63 self
.layout
= Layout([
64 ("payload", self
.sink
.description
.payload_layout
),
65 ("first", 1, DIR_FANOUT
),
66 ("last", 1, DIR_FANOUT
)
69 def elaborate(self
, platform
):
72 fifo
= m
.submodules
.fifo
= self
.fifo
73 fifo_din
= Record(self
.layout
)
74 fifo_dout
= Record(self
.layout
)
76 fifo
.w_data
.eq(fifo_din
),
77 fifo_dout
.eq(fifo
.r_data
),
79 self
.sink
.ready
.eq(fifo
.w_rdy
),
80 fifo
.w_en
.eq(self
.sink
.valid
),
81 fifo_din
.first
.eq(self
.sink
.first
),
82 fifo_din
.last
.eq(self
.sink
.last
),
83 fifo_din
.payload
.eq(self
.sink
.payload
),
85 self
.source
.valid
.eq(fifo
.r_rdy
),
86 self
.source
.first
.eq(fifo_dout
.first
),
87 self
.source
.last
.eq(fifo_dout
.last
),
88 self
.source
.payload
.eq(fifo_dout
.payload
),
89 fifo
.r_en
.eq(self
.source
.ready
)
95 class SyncFIFO(Elaboratable
, _FIFOWrapper
):
96 def __init__(self
, layout
, depth
, fwft
=True, buffered
=False):
97 super().__init
__(layout
)
99 self
.fifo
= fifo
.SyncFIFOBuffered(width
=len(Record(self
.layout
)), depth
=depth
, fwft
=fwft
)
101 self
.fifo
= fifo
.SyncFIFO(width
=len(Record(self
.layout
)), depth
=depth
, fwft
=fwft
)
102 self
.depth
= self
.fifo
.depth
103 self
.level
= self
.fifo
.level
106 class AsyncFIFO(Elaboratable
, _FIFOWrapper
):
107 def __init__(self
, layout
, depth
, r_domain
="read", w_domain
="write"):
108 super().__init
__(layout
)
109 self
.fifo
= fifo
.AsyncFIFO(width
=len(Record(self
.layout
)), depth
=depth
,
110 r_domain
=r_domain
, w_domain
=w_domain
)
111 self
.depth
= self
.fifo
.depth
113 class PipeValid(Elaboratable
):
114 """Pipe valid/payload to cut timing path"""
115 def __init__(self
, layout
):
116 self
.sink
= Endpoint(layout
)
117 self
.source
= Endpoint(layout
)
119 def elaborate(self
, platform
):
122 # Pipe when source is not valid or is ready.
123 with m
.If(~self
.source
.valid | self
.source
.ready
):
125 self
.source
.valid
.eq(self
.sink
.valid
),
126 self
.source
.first
.eq(self
.sink
.first
),
127 self
.source
.last
.eq(self
.sink
.last
),
128 self
.source
.payload
.eq(self
.sink
.payload
),
129 self
.source
.param
.eq(self
.sink
.param
),
131 m
.d
.comb
+= self
.sink
.ready
.eq(~self
.source
.valid | self
.source
.ready
)
135 class Buffer(PipeValid
): pass # FIXME: Replace Buffer with PipeValid in codebase?