bus_adapter.py
1 from typing import Protocol 2 3 from amaranth import * 4 from amaranth_types import HasElaborate 5 6 from coreblocks.peripherals.wishbone import WishboneMaster 7 from coreblocks.peripherals.axi_lite import AXILiteMaster 8 9 from transactron import Method, def_method, TModule 10 from transactron.lib import Serializer 11 from transactron.utils.transactron_helpers import make_layout 12 13 __all__ = ["BusMasterInterface", "WishboneMasterAdapter", "AXILiteMasterAdapter"] 14 15 16 class BusParametersInterface(Protocol): 17 """ 18 An interface for parameters of a common bus. 19 20 Parameters 21 ---------- 22 data_width : int 23 An integer that describes the data width of a parametrized bus. 24 addr_width : int 25 An integer that describes the address width of a parametrized bus. 26 granularity : int 27 An integer that describes the granularity of accesses of a parametrized bus. 28 """ 29 30 data_width: int 31 addr_width: int 32 granularity: int 33 34 35 class BusMasterInterface(HasElaborate, Protocol): 36 """ 37 An interface of a common bus. 38 39 The bus interface is the preferred way to gain access to a specific bus. 40 It simplifies interchangeability of buses on the core configuration level. 41 42 Parameters 43 ---------- 44 params : BusParametersInterface 45 Parameters of the bus. 46 request_read : Method 47 A method that is used to send a read request to a bus. 48 request_write : Method 49 A method that is used to send a write request to a bus. 50 get_read_response : Method 51 A method that is used to receive a response from a bus for a previously sent read request. 52 get_write_response : Method 53 A method that is used to receive a response from a bus for a previously sent write request. 54 """ 55 56 params: BusParametersInterface 57 request_read: Method 58 request_write: Method 59 get_read_response: Method 60 get_write_response: Method 61 62 63 class CommonBusMasterMethodLayout: 64 """ 65 Layouts of methods for a common bus master. 66 67 Parameters 68 ---------- 69 bus_params: BusParametersInterface 70 Parameters used to generate common bus master methods layouts. 71 72 Attributes 73 ---------- 74 request_read_layout: Layout 75 A layout for the `request_read` method of a common bus master. 76 77 request_write_layout: Layout 78 A layout for the `request_write` method of a common bus master. 79 80 read_response_layout: Layout 81 A layout for the `get_read_response` method of a common bus master. 82 83 write_response_layout: Layout 84 A layout for the `get_write_response` method of a common bus master. 85 """ 86 87 def __init__(self, bus_params: BusParametersInterface): 88 self.bus_params = bus_params 89 90 self.request_read_layout = make_layout( 91 ("addr", self.bus_params.addr_width), 92 ("sel", self.bus_params.data_width // self.bus_params.granularity), 93 ) 94 95 self.request_write_layout = make_layout( 96 ("addr", self.bus_params.addr_width), 97 ("data", self.bus_params.data_width), 98 ("sel", self.bus_params.data_width // self.bus_params.granularity), 99 ) 100 101 self.read_response_layout = make_layout(("data", self.bus_params.data_width), ("err", 1)) 102 103 self.write_response_layout = make_layout(("err", 1)) 104 105 106 class WishboneMasterAdapter(Elaboratable, BusMasterInterface): 107 """ 108 An adapter for Wishbone master. 109 110 The adapter module is for use in places where BusMasterInterface is expected. 111 112 Parameters 113 ---------- 114 bus: WishboneMaster 115 Specific Wishbone master module which is to be adapted. 116 117 Attributes 118 ---------- 119 params: BusParametersInterface 120 Parameters of the bus. 121 122 method_layouts: CommonBusMasterMethodLayout 123 Layouts of common bus master methods. 124 125 request_read: Method 126 Transactional method for initiating a read request. 127 It is ready if the `request` method of the underlying Wishbone master is ready. 128 Input layout is `request_read_layout`. 129 130 request_write: Method 131 Transactional method for initiating a write request. 132 It is ready if the `request` method of the underlying Wishbone master is ready. 133 Input layout is `request_write_layout`. 134 135 get_read_response: Method 136 Transactional method for reading a response of a read action. 137 It is ready if the `result` method of the underlying Wishbone master is ready. 138 Output layout is `read_response_layout`. 139 140 get_write_response: Method 141 Transactional method for reading a response of a write action. 142 It is ready if the `result` method of the underlying Wishbone master is ready. 143 Output layout is `write_response_layout`. 144 """ 145 146 def __init__(self, bus: WishboneMaster): 147 self.bus = bus 148 self.params = self.bus.wb_params 149 150 self.method_layouts = CommonBusMasterMethodLayout(self.params) 151 152 self.request_read = Method(i=self.method_layouts.request_read_layout) 153 self.request_write = Method(i=self.method_layouts.request_write_layout) 154 self.get_read_response = Method(o=self.method_layouts.read_response_layout) 155 self.get_write_response = Method(o=self.method_layouts.write_response_layout) 156 157 def elaborate(self, platform): 158 m = TModule() 159 160 bus_serializer = Serializer( 161 port_count=2, serialized_req_method=self.bus.request, serialized_resp_method=self.bus.result 162 ) 163 m.submodules.bus_serializer = bus_serializer 164 165 @def_method(m, self.request_read) 166 def _(arg): 167 we = C(0, unsigned(1)) 168 data = C(0, unsigned(self.params.data_width)) 169 bus_serializer.serialize_in[0](m, addr=arg.addr, data=data, we=we, sel=arg.sel) 170 171 @def_method(m, self.request_write) 172 def _(arg): 173 we = C(1, unsigned(1)) 174 bus_serializer.serialize_in[1](m, addr=arg.addr, data=arg.data, we=we, sel=arg.sel) 175 176 @def_method(m, self.get_read_response) 177 def _(): 178 res = bus_serializer.serialize_out[0](m) 179 return {"data": res.data, "err": res.err} 180 181 @def_method(m, self.get_write_response) 182 def _(): 183 res = bus_serializer.serialize_out[1](m) 184 return {"err": res.err} 185 186 return m 187 188 189 class AXILiteMasterAdapter(Elaboratable, BusMasterInterface): 190 """ 191 An adapter for AXI Lite master. 192 193 The adapter module is for use in places where BusMasterInterface is expected. 194 195 Parameters 196 ---------- 197 bus: AXILiteMaster 198 Specific AXI Lite master module which is to be adapted. 199 200 Attributes 201 ---------- 202 params: BusParametersInterface 203 Parameters of the bus. 204 205 method_layouts: CommonBusMasterMethodLayout 206 Layouts of common bus master methods. 207 208 request_read: Method 209 Transactional method for initiating a read request. 210 It is ready if the `ra_request` method of the underlying AXI Lite master is ready. 211 Input layout is `request_read_layout`. 212 213 request_write: Method 214 Transactional method for initiating a write request. 215 It is ready if the 'wa_request' and 'wd_request' methods of the underlying AXI Lite master are ready. 216 Input layout is `request_write_layout`. 217 218 get_read_response: Method 219 Transactional method for reading a response of a read action. 220 It is ready if the `rd_response` method of the underlying AXI Lite master is ready. 221 Output layout is `read_response_layout`. 222 223 get_write_response: Method 224 Transactional method for reading a response of a write action. 225 It is ready if the `wr_response` method of the underlying AXI Lite master is ready. 226 Output layout is `write_response_layout`. 227 """ 228 229 def __init__(self, bus: AXILiteMaster): 230 self.bus = bus 231 self.params = self.bus.axil_params 232 233 self.method_layouts = CommonBusMasterMethodLayout(self.params) 234 235 self.request_read = Method(i=self.method_layouts.request_read_layout) 236 self.request_write = Method(i=self.method_layouts.request_write_layout) 237 self.get_read_response = Method(o=self.method_layouts.read_response_layout) 238 self.get_write_response = Method(o=self.method_layouts.write_response_layout) 239 240 def elaborate(self, platform): 241 m = TModule() 242 243 @def_method(m, self.request_read) 244 def _(arg): 245 prot = C(0, unsigned(3)) 246 self.bus.ra_request(m, addr=arg.addr, prot=prot) 247 248 @def_method(m, self.request_write) 249 def _(arg): 250 prot = C(0, unsigned(3)) 251 self.bus.wa_request(m, addr=arg.addr, prot=prot) 252 self.bus.wd_request(m, data=arg.data, strb=arg.sel) 253 254 @def_method(m, self.get_read_response) 255 def _(): 256 res = self.bus.rd_response(m) 257 err = res.resp != 0 258 return {"data": res.data, "err": err} 259 260 @def_method(m, self.get_write_response) 261 def _(): 262 res = self.bus.wr_response(m) 263 err = res.resp != 0 264 return {"err": err} 265 266 return m