soc/interconnect: add AXILite SRAM
authorJędrzej Boczar <jboczar@antmicro.com>
Wed, 15 Jul 2020 08:58:34 +0000 (10:58 +0200)
committerJędrzej Boczar <jboczar@antmicro.com>
Wed, 15 Jul 2020 08:58:34 +0000 (10:58 +0200)
litex/soc/integration/soc.py
litex/soc/interconnect/axi.py

index 7111921cdee8d6f928a3782373e9fbf143b31230..28ee0cc220fd9c6f53e8b53fda8cbf3bb641544f 100644 (file)
@@ -743,19 +743,28 @@ class SoC(Module):
         setattr(self.submodules, name, SoCController(**kwargs))
         self.csr.add(name, use_loc_if_exists=True)
 
-    def add_ram(self, name, origin, size, contents=[], mode="rw"):
-        ram_bus = wishbone.Interface(data_width=self.bus.data_width)
-        ram     = wishbone.SRAM(size, bus=ram_bus, init=contents, read_only=(mode == "r"))
+    def add_ram(self, name, origin, size, contents=[], mode="rw", bus=None):
+        if bus is None:
+            bus = wishbone.Interface(data_width=self.bus.data_width)
+
+        if isinstance(bus, wishbone.Interface):
+            ram = wishbone.SRAM(size, bus=bus, init=contents, read_only=(mode == "r"))
+        elif isinstance(bus, axi.AXILiteInterface):
+            ram = axi.AXILiteSRAM(size, bus=bus, init=contents, read_only=(mode == "r"))
+        else:
+            raise TypeError(bus)
+
         self.bus.add_slave(name, ram.bus, SoCRegion(origin=origin, size=size, mode=mode))
         self.check_if_exists(name)
-        self.logger.info("RAM {} {} {}.".format(
+        self.logger.info("{} RAM {} {} {}.".format(
+            colorer("Wishbone" if isinstance(bus, wishbone.Interface) else "AXILite"),
             colorer(name),
             colorer("added", color="green"),
             self.bus.regions[name]))
         setattr(self.submodules, name, ram)
 
-    def add_rom(self, name, origin, size, contents=[]):
-        self.add_ram(name, origin, size, contents, mode="r")
+    def add_rom(self, name, origin, size, contents=[], bus=None):
+        self.add_ram(name, origin, size, contents, mode="r", bus=bus)
 
     def add_csr_bridge(self, origin):
         self.submodules.csr_bridge = wishbone.Wishbone2CSR(
index 83f5044bf4e6a4c4154ed631c1e0bb82da3c1c12..a9ee719ca1e03c7c69c07ff9ccf828e5c4a3ba88 100644 (file)
@@ -565,3 +565,92 @@ class AXILite2CSR(Module):
                 NextState("IDLE")
             )
         )
+
+# AXILite SRAM -------------------------------------------------------------------------------------
+
+class AXILiteSRAM(Module):
+    def __init__(self, mem_or_size, read_only=None, init=None, bus=None):
+        if bus is None:
+            bus = AXILiteInterface()
+        self.bus = bus
+
+        bus_data_width = len(self.bus.r.data)
+        if isinstance(mem_or_size, Memory):
+            assert(mem_or_size.width <= bus_data_width)
+            self.mem = mem_or_size
+        else:
+            self.mem = Memory(bus_data_width, mem_or_size//(bus_data_width//8), init=init)
+
+        if read_only is None:
+            if hasattr(self.mem, "bus_read_only"):
+                read_only = self.mem.bus_read_only
+            else:
+                read_only = False
+
+        ###
+
+        # Create memory port
+        port = self.mem.get_port(write_capable=not read_only, we_granularity=8,
+            mode=READ_FIRST if read_only else WRITE_FIRST)
+        self.specials += self.mem, port
+
+        # Generate write enable signal
+        if not read_only:
+            self.comb += port.dat_w.eq(self.bus.w.data),
+            self.comb += [port.we[i].eq(self.bus.w.valid & self.bus.w.ready & self.bus.w.strb[i])
+                for i in range(bus_data_width//8)]
+
+        # Access logic
+        adr_shift = log2_int(self.bus.data_width//8)
+        rdata = Signal.like(port.dat_r)
+        do_read = Signal()
+        do_write = Signal()
+        last_was_read = Signal()
+
+        self.submodules.fsm = fsm = FSM(reset_state="IDLE")
+        fsm.act("IDLE",
+            # if last access was a read, do a write, and vice versa
+            If(self.bus.aw.valid & self.bus.ar.valid,
+                do_write.eq(last_was_read),
+                do_read.eq(~last_was_read),
+            ).Else(
+                do_write.eq(self.bus.aw.valid),
+                do_read.eq(self.bus.ar.valid),
+            ),
+            If(do_write,
+                NextValue(last_was_read, 0),
+                NextState("DO-WRITE"),
+            ).Elif(do_read,
+                port.adr.eq(self.bus.ar.addr[adr_shift:]),
+                NextValue(last_was_read, 1),
+                NextState("DO-READ"),
+            )
+        )
+        fsm.act("DO-READ",
+            self.bus.ar.ready.eq(1),
+            NextValue(rdata, port.dat_r),
+            NextState("SEND-READ-RESPONSE"),
+        )
+        fsm.act("SEND-READ-RESPONSE",
+            self.bus.r.valid.eq(1),
+            self.bus.r.resp.eq(RESP_OKAY),
+            self.bus.r.data.eq(rdata),
+            If(self.bus.r.ready,
+                NextState("IDLE")
+            )
+        )
+        fsm.act("DO-WRITE",
+            port.adr.eq(self.bus.aw.addr[adr_shift:]),
+            If(self.bus.w.valid,
+                self.bus.aw.ready.eq(1),
+                self.bus.w.ready.eq(1),
+                NextState("SEND-WRITE-RESPONSE")
+            )
+        )
+        fsm.act("SEND-WRITE-RESPONSE",
+            self.bus.b.valid.eq(1),
+            self.bus.b.resp.eq(RESP_OKAY),
+            If(self.bus.b.ready,
+                NextState("IDLE")
+            )
+        )