From 8ef51a00ee0dea1a390d675ad4f9ac7c5c4bff14 Mon Sep 17 00:00:00 2001 From: Rafal Kolucki Date: Thu, 17 Feb 2022 17:45:56 +0100 Subject: [PATCH] soc/interconnect/wishbone: Add incrementing burst cycles support to SRAM This commit adds support for incrementing burst cycles in SRAM peripheral. By default it's enabled, but can be disabled by passing `burst=False` to the class while initializing, if it won't be useful for created design (e.g. no Wishbone bus masters with burst support). --- litex/soc/interconnect/wishbone.py | 101 +++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 4 deletions(-) diff --git a/litex/soc/interconnect/wishbone.py b/litex/soc/interconnect/wishbone.py index 715fece22..d08e97ee6 100644 --- a/litex/soc/interconnect/wishbone.py +++ b/litex/soc/interconnect/wishbone.py @@ -4,6 +4,7 @@ # Copyright (c) 2015 Sebastien Bourdeauducq # Copyright (c) 2015-2020 Florent Kermarrec # Copyright (c) 2018 Tim 'mithro' Ansell +# Copytight (c) 2022 Antmicro # SPDX-License-Identifier: BSD-2-Clause """Wishbone Classic support for LiteX (Standard HandShaking/Synchronous Feedback)""" @@ -329,7 +330,7 @@ class Converter(Module): # Wishbone SRAM ------------------------------------------------------------------------------------ class SRAM(Module): - def __init__(self, mem_or_size, read_only=None, init=None, bus=None): + def __init__(self, mem_or_size, read_only=None, init=None, bus=None, burst=True): if bus is None: bus = Interface() self.bus = bus @@ -346,6 +347,79 @@ class SRAM(Module): else: read_only = False + ### + if burst: + adr_wrap_mask = Array((0b0000, 0b0011, 0b0111, 0b1111)) + adr_wrap_max = adr_wrap_mask[-1].bit_length() + + adr_burst_wrap = Signal() + adr_burst_end = Signal() + adr_burst = Signal() + adr_latched = Signal() + + adr_counter = Signal(len(self.bus.adr)) + adr_counter_offset = Signal(adr_wrap_max) + adr_offset_lsb = Signal(adr_wrap_max) + adr_offset_msb = Signal(len(self.bus.adr)) + + adr_next = Signal(len(self.bus.adr)) + + # only incrementing burst cycles are supported + self.comb += [ + Case(self.bus.cti, { + # incrementing address burst cycle + 0b010: adr_burst.eq(1), + # end current burst cycle + 0b111: adr_burst.eq(0), + # unsupported burst cycle + "default": adr_burst.eq(0) + }), + adr_burst_wrap.eq(self.bus.bte[0] | self.bus.bte[1]) + ] + + # latch initial address - initial address without wrapping bits and wrap offset + self.sync += [ + If(self.bus.cyc & self.bus.stb & adr_burst, + adr_latched.eq(1), + # latch initial address, then increment it every clock cycle + If(adr_latched, + adr_counter.eq(adr_counter + 1) + ).Else( + adr_counter_offset.eq(self.bus.adr & adr_wrap_mask[self.bus.bte]), + If(self.bus.we, + adr_counter.eq( + Cat(self.bus.adr & ~adr_wrap_mask[self.bus.bte], + self.bus.adr[adr_wrap_max:] + ) + ), + ).Else( + adr_counter.eq( + Cat(self.bus.adr & ~adr_wrap_mask[self.bus.bte], + self.bus.adr[adr_wrap_max:] + ) + 1 + ), + ) + ), + If(self.bus.cti == 0b111, + adr_latched.eq(0), + adr_counter.eq(0), + adr_counter_offset.eq(0) + ) + ).Else( + adr_latched.eq(0), + adr_counter.eq(0), + adr_counter_offset.eq(0) + ), + ] + + # next address = sum of counter value without wrapped bits + # and wrapped counter bits with offset + self.comb += [ + adr_offset_lsb.eq((adr_counter + adr_counter_offset) & adr_wrap_mask[self.bus.bte]), + adr_offset_msb.eq(adr_counter & ~adr_wrap_mask[self.bus.bte]), + adr_next.eq(adr_offset_msb + adr_offset_lsb) + ] + ### # memory @@ -357,17 +431,36 @@ class SRAM(Module): self.comb += [port.we[i].eq(self.bus.cyc & self.bus.stb & self.bus.we & self.bus.sel[i]) for i in range(bus_data_width//8)] # address and data + if burst: + self.comb += [ + If(adr_burst & adr_latched, + port.adr.eq(adr_next[:len(port.adr)]), + ).Else( + port.adr.eq(self.bus.adr[:len(port.adr)]), + ), + ] + else: + self.comb += [ + port.adr.eq(self.bus.adr[:len(port.adr)]), + ] self.comb += [ - port.adr.eq(self.bus.adr[:len(port.adr)]), self.bus.dat_r.eq(port.dat_r) ] if not read_only: self.comb += port.dat_w.eq(self.bus.dat_w), + # generate ack self.sync += [ - self.bus.ack.eq(0), - If(self.bus.cyc & self.bus.stb & ~self.bus.ack, self.bus.ack.eq(1)) + self.bus.ack.eq(0) ] + if burst: + self.sync += [ + If(self.bus.cyc & self.bus.stb & (~self.bus.ack | adr_burst), self.bus.ack.eq(1)) + ] + else: + self.sync += [ + If(self.bus.cyc & self.bus.stb & ~self.bus.ack, self.bus.ack.eq(1)) + ] # Wishbone To CSR ----------------------------------------------------------------------------------