17from pycde
import AppID, Clock, Input, Module, Output, Reset, generator
20from pycde.types
import Array, Bits, Channel, StructType, UInt
32def MmioRegistry(num_ro: int, num_rw: int, num_wo: int):
33 """MMIO register file with automatically-numbered registers (RO < RW < WO)
34 addressed at an 8-byte stride (``index = offset >> 3``).
38 [0, num_ro) -> read-only (RO)
39 [num_ro, num_ro + num_rw) -> read-write (RW)
40 [num_ro + num_rw, num_ro+num_rw+num_wo) -> write-only (WO)
42 The RO and RW registers ("read registers", ``num_ro + num_rw`` of them) are
43 held internally. The client updates any of them via the per-read-register
44 ``read_reg_ce`` / ``read_reg_data`` arrays and observes their current value
45 on ``read_reg_value`` (all length ``num_ro + num_rw``, indexed RO-first then
46 RW). A host write to an RW register additionally stores the written data into
47 that register directly; a host write takes priority over a coincident client
48 update of the same register.
50 Reads -- and the read-back value returned for a write -- respond with the
51 selected register's value, or all-ones (-1) if the offset selects a WO
52 register or is out of bounds.
54 Writes to RW/WO registers are registered and presented to the client on
55 ``write_cmd_r`` / ``write_cmd_xact_r`` (writes to RO offsets or out-of-bounds
56 offsets are dropped). ``mmio_write_we`` derives per-offset write strobes from
59 The MMIO bundle is created inside this submodule's ``@generator``, so the
60 request's AppID is anchored at this instance's hierarchical position.
63 read_reg_ce : Input Array(Bits(1), num_ro + num_rw)
64 read_reg_data : Input Array(Bits(64), num_ro + num_rw)
65 read_reg_value : Output Array(Bits(64), num_ro + num_rw)
66 write_cmd_r : Output MMIOWriteCmdType (last presented write)
67 write_cmd_xact_r : Output Bits(1) (1-cycle pulse on a presented write)
69 num_read = num_ro + num_rw
70 num_total = num_ro + num_rw + num_wo
71 assert num_read >= 1,
"MmioRegistry needs at least one read register."
73 class MmioRegistryImpl(Module):
77 read_reg_ce = Input(Array(Bits(1), num_read))
78 read_reg_data = Input(Array(Bits(64), num_read))
79 read_reg_value = Output(Array(Bits(64), num_read))
81 write_cmd_r = Output(MMIOWriteCmdType)
82 write_cmd_xact_r = Output(Bits(1))
89 mmio_bundle = esi.MMIO.read_write(appid=AppID(
"cmd"))
91 cmd_chan_wire = Wire(Channel(esi.MMIOReadWriteCmdType))
92 cmd_ready_wire = Wire(Bits(1))
93 cmd, cmd_valid = cmd_chan_wire.unwrap(cmd_ready_wire)
95 resp_pending_wire = Wire(Bits(1))
96 resp_data_r = Wire(Bits(64))
97 resp_chan, resp_ready = Channel(Bits(64)).
wrap(resp_data_r,
99 resp_xact = resp_pending_wire & resp_ready
100 cmd_xact = cmd_valid & ~resp_pending_wire
101 cmd_ready_wire.assign(~resp_pending_wire)
102 resp_pending_wire.assign(
112 idx = cmd.offset.as_bits()[3:].as_uint()
113 idx_w = idx.type.width
116 return idx == UInt(idx_w)(i)
121 for i
in range(num_read):
123 host_we = cmd_xact & cmd.write & is_index(i)
124 reg_ce = host_we | ports.read_reg_ce[i]
125 reg_data = Mux(host_we, ports.read_reg_data[i], cmd.data)
127 reg_ce = ports.read_reg_ce[i]
128 reg_data = ports.read_reg_data[i]
133 rst_value=Bits(64)(0),
135 name=f
"read_reg_{i}",
137 read_values_arr = Array(Bits(64), num_read)(read_values)
138 ports.read_reg_value = read_values_arr
142 sel_read_value = read_values_arr[idx.as_bits(clog2(num_read))]
144 idx < UInt(idx_w)(num_read),
152 rst_value=Bits(64)(0),
158 presented = (cmd_xact & cmd.write & (idx >= UInt(idx_w)(num_ro)) &
159 (idx < UInt(idx_w)(num_total)))
161 ports.write_cmd_r = write_cmd.reg(clk=clk,
165 ports.write_cmd_xact_r = presented.reg(clk=clk,
167 rst_value=Bits(1)(0),
168 name=
"write_cmd_xact_r")
170 mmio_rw_cmd_chan = mmio_bundle.unpack(data=resp_chan)[
"cmd"]
171 cmd_chan_wire.assign(mmio_rw_cmd_chan)
173 return MmioRegistryImpl