16def OneItemBuffersToHost(client_type: Type):
17 """Create a simple, non-performant DMA-based channel communication. Protocol:
19 1) Host sends address of buffer address via MMIO write.
20 2) Device writes data on channel with a byte '1' to said buffer address.
21 3) Host polls the last byte in buffer for '1'.
22 4) Data is copied out of buffer, last byte is set to '0', goto 1.
24 Future improvement: support more than one buffer at once."""
26 class OneItemBuffersToHost(esi.EngineModule):
30 return "OneItemBuffersToHost"
35 input_channel = InputChannel(client_type)
40 mmio = Input(esi.MMIO.read_write.type)
41 xfer_data_type = StructType([(
"valid", Bits(8)),
42 (
"client_data", client_type)])
43 hostmem_write = Input(esi.HostMem.write_req_bundle_type(xfer_data_type))
51 mmio_resp_chan = Wire(Channel(Bits(64)))
53 mmio_cmd_chan_raw = mmio_rw.unpack(data=mmio_resp_chan)[
'cmd']
54 mmio_cmd_chan, mmio_cmd_fork_resp = mmio_cmd_chan_raw.fork(clk, rst)
57 mmio_resp_data = NamedWire(Bits(64)(0),
"mmio_resp_data")
58 mmio_resp_chan.assign(
59 mmio_cmd_fork_resp.transform(
lambda _: mmio_resp_data))
63 _, _, mmio_cmd = mmio_cmd_chan.snoop()
65 mmio_offset_words = NamedWire((mmio_cmd.offset.as_bits()[3:]).as_uint(),
67 addr_above = mmio_offset_words >= UInt(32)(num_sinks)
68 addr_is_zero = mmio_offset_words == UInt(32)(0)
69 force_to_null = NamedWire(addr_above | ~addr_is_zero | mmio_cmd.write,
71 cmd_sink_sel = Mux(force_to_null,
72 Bits(clog2(num_sinks))(0),
73 mmio_offset_words.as_bits()[:clog2(num_sinks)])
74 mmio_data_only_chan = mmio_cmd_chan.transform(
lambda m: m.data)
75 mailbox_names = [
"null",
"buffer_loc"]
76 demuxed = esi.ChannelDemux(mmio_data_only_chan, cmd_sink_sel, num_sinks)
77 mailbox_mod = esi.Mailbox(Bits(64))
82 instance_name=
"mailbox_" + name)
83 for name, c
in zip(mailbox_names, demuxed)
85 [_, buffer_loc] = mailboxes
89 next_buffer_loc_chan = buffer_loc.output
90 hostwr_type = esi.HostMem.write_req_channel_type(
91 OneItemBuffersToHost.xfer_data_type)
92 hostwr_joined = Channel.join(next_buffer_loc_chan, ports.input_channel)
93 hostwr = hostwr_joined.transform(
lambda joined: hostwr_type({
94 "address": joined.a.as_uint(),
98 "client_data": joined.b
101 ports.hostmem_write.unpack(req=hostwr)
103 return OneItemBuffersToHost
106def OneItemBuffersFromHost(client_type: Type):
107 """Create a simple, non-performant DMA-base from host communication channel.
109 1) Host sends address of buffer address via MMIO write to register 0x08.
110 2) Host sends address of completion address via MMIO write to register 0x10.
111 3) Device reads data from said buffer and sends down the channel. Only keeps
112 one transfer outstanding by buffering the read response locally before
114 4) Device writes '1' to the first byte of the completion buffer to signal that
115 the transfer is done.
118 class OneItemBuffersFromHost(esi.EngineModule):
122 return "OneItemBuffersFromHost"
128 output_channel = OutputChannel(client_type)
133 mmio = Input(esi.MMIO.read_write.type)
134 xfer_data_type = Bits(8)
135 hostmem_write = Input(esi.HostMem.write_req_bundle_type(xfer_data_type))
136 hostmem_read = Input(esi.HostMem.read_bundle_type(client_type))
144 mmio_resp_chan = Wire(Channel(Bits(64)))
146 mmio_cmd_chan_raw = mmio_rw.unpack(data=mmio_resp_chan)[
'cmd']
147 mmio_cmd_chan, mmio_cmd_fork_resp = mmio_cmd_chan_raw.fork(clk, rst)
150 mmio_resp_data = NamedWire(Bits(64)(0),
"mmio_resp_data")
151 mmio_resp_chan.assign(
152 mmio_cmd_fork_resp.transform(
lambda _: mmio_resp_data))
155 _, _, mmio_cmd = mmio_cmd_chan.snoop()
156 mailbox_names = [
"null",
"buffer_loc",
"completion_addr"]
157 num_sinks = len(mailbox_names)
158 mmio_offset_words = NamedWire((mmio_cmd.offset.as_bits()[3:]).as_uint(),
160 addr_above = mmio_offset_words >= UInt(32)(num_sinks)
161 addr_is_zero = mmio_offset_words == UInt(32)(0)
162 force_to_null = NamedWire(addr_above | ~addr_is_zero | mmio_cmd.write,
164 cmd_sink_sel = Mux(force_to_null,
165 Bits(clog2(num_sinks))(0),
166 mmio_offset_words.as_bits()[:clog2(num_sinks)])
167 mmio_data_only_chan = mmio_cmd_chan.transform(
lambda m: m.data)
168 demuxed = esi.ChannelDemux(mmio_data_only_chan, cmd_sink_sel, num_sinks)
172 mailbox_mod = esi.Mailbox(Bits(64))
177 instance_name=
"mailbox_" + name)
178 for name, c
in zip(mailbox_names, demuxed)
180 [_, buffer_loc, completion_loc] = mailboxes
181 buffer_loc_for_read = buffer_loc.output
183 output_chan = Wire(Channel(client_type))
184 ports.output_channel = output_chan
185 output_buf_ready = Wire(Bits(1), name=
"output_buf_ready")
190 read_req_accept = Wire(Bits(1), name=
"read_req_accept")
191 buffer_loc_data, buffer_loc_valid = buffer_loc_for_read.unwrap(
193 read_req_valid = NamedWire(buffer_loc_valid & output_buf_ready,
195 read_req, read_req_ready = Channel(esi.HostMem.ReadReqType).
wrap(
196 esi.HostMem.ReadReqType({
197 "address": buffer_loc_data.as_uint(),
200 read_req_xact = NamedWire(read_req_valid & read_req_ready,
202 read_req_accept.assign(read_req_xact)
207 read_resp = ports.hostmem_read.unpack(req=read_req)[
'resp']
208 output_ready = Wire(Bits(1), name=
"output_ready")
209 output_valid_reset = Wire(Bits(1), name=
"output_valid_reset")
210 read_resp_ready = Wire(Bits(1), name=
"read_resp_ready")
211 read_resp_msg, read_resp_valid = read_resp.unwrap(read_resp_ready)
212 read_resp_xact = NamedWire(read_resp_valid & read_resp_ready,
214 output_valid = ControlReg(
217 asserts=[read_resp_xact],
218 resets=[output_valid_reset],
221 output_data = read_resp_msg.data.reg(clk=clk,
225 output_buf_ready.assign((~output_valid | output_ready).as_bits())
226 read_resp_ready.assign(output_buf_ready)
227 output_valid_reset.assign(output_valid & output_ready)
228 output_buf_chan, output_chan_ready = Channel(client_type).
wrap(
229 output_data, output_valid)
230 output_chan.assign(output_buf_chan)
231 output_ready.assign(output_chan_ready)
235 completion_pending_reset = Wire(Bits(1), name=
"completion_pending_reset")
236 completion_pending = ControlReg(
239 asserts=[read_resp_xact],
240 resets=[completion_pending_reset],
241 name=
"completion_pending",
244 write_ch_type = esi.HostMem.write_req_channel_type(
245 OneItemBuffersFromHost.xfer_data_type)
246 completion_loc_ready = Wire(Bits(1), name=
"completion_loc_ready")
247 completion_loc_data, completion_loc_valid = completion_loc.output.unwrap(
248 completion_loc_ready)
249 completion_write_valid = NamedWire(
250 completion_loc_valid & completion_pending,
"completion_write_valid")
251 write_done_chan, completion_write_ready = Channel(write_ch_type).
wrap(
253 "address": completion_loc_data.as_uint(),
256 }), completion_write_valid)
257 completion_write_xact = NamedWire(
258 completion_write_valid & completion_write_ready,
259 "completion_write_xact")
260 completion_loc_ready.assign(completion_write_xact)
261 completion_pending_reset.assign(completion_write_xact)
264 ports.hostmem_write.unpack(req=write_done_chan)
266 return OneItemBuffersFromHost