| from amaranth import *
from amaranth.lib.wiring import Component, In
from amaranth.utils import exact_log2
from amaranth_soc import wishbone
from amaranth_soc.memory import MemoryMap
class GranularityConverter(Component):
def __init__(self, target_bus, *, granularity = 8):
assert target_bus.data_width == target_bus.granularity, 'Target bus must have a granularity equal to width.' # This can be relaxed later.
assert target_bus.data_width % granularity == 0, 'Target bus width must be a multiple of granularity'
ratio = target_bus.data_width // granularity
ratio_bits = exact_log2(ratio)
wb_sig = wishbone.Signature(addr_width = target_bus.addr_width, data_width=target_bus.data_width, granularity = granularity)
super().__init__({"wb_bus": In(wb_sig)})
self.wb_bus.memory_map = MemoryMap(addr_width=target_bus.addr_width + ratio_bits,
data_width=granularity)
target_bus.memory_map.freeze()
# MemoryMap doesn't support adding windows with a larger granularity than the parent.
# Add and remap all resources directly instead:
for resource in target_bus.memory_map.all_resources():
self.wb_bus.memory_map.add_resource(resource.resource, name = tuple(part for name in resource.path for part in name), addr = resource.start * ratio, size = (resource.end - resource.start) * ratio)
self._target_bus = target_bus
def elaborate(self, platform):
target = self._target_bus
initiator = self.wb_bus
m = Module()
m.d.comb += [
target.adr.eq(initiator.adr),
target.dat_w.eq(initiator.dat_w),
initiator.dat_r.eq(target.dat_r),
target.sel.eq(initiator.sel.all()), # With .all(), smaller writes will be silently ignored.
target.cyc.eq(initiator.cyc),
target.stb.eq(initiator.stb),
target.we.eq(initiator.we),
initiator.ack.eq(target.ack),
]
return m
|