-
Notifications
You must be signed in to change notification settings - Fork 593
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1267 from antmicro/wb-sram-inc-burst
soc/interconnect/wishbone: Add incrementing address burst mode to SRAM
- Loading branch information
Showing
5 changed files
with
174 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
# Copyright (c) 2015 Sebastien Bourdeauducq <[email protected]> | ||
# Copyright (c) 2015-2020 Florent Kermarrec <[email protected]> | ||
# Copyright (c) 2018 Tim 'mithro' Ansell <[email protected]> | ||
# Copytight (c) 2022 Antmicro <www.antmicro.com> | ||
# SPDX-License-Identifier: BSD-2-Clause | ||
|
||
"""Wishbone Classic support for LiteX (Standard HandShaking/Synchronous Feedback)""" | ||
|
@@ -38,11 +39,17 @@ | |
("err", 1, DIR_S_TO_M) | ||
] | ||
|
||
CTI_BURST_NONE = 0b000 | ||
CTI_BURST_CONSTANT = 0b001 | ||
CTI_BURST_INCREMENTING = 0b010 | ||
CTI_BURST_END = 0b111 | ||
|
||
|
||
class Interface(Record): | ||
def __init__(self, data_width=32, adr_width=30): | ||
def __init__(self, data_width=32, adr_width=30, bursting=False): | ||
self.data_width = data_width | ||
self.adr_width = adr_width | ||
self.bursting = bursting | ||
Record.__init__(self, set_layout_parameters(_layout, | ||
adr_width = adr_width, | ||
data_width = data_width, | ||
|
@@ -65,18 +72,26 @@ def _do_transaction(self): | |
yield self.cyc.eq(0) | ||
yield self.stb.eq(0) | ||
|
||
def write(self, adr, dat, sel=None): | ||
def write(self, adr, dat, sel=None, cti=None, bte=None): | ||
if sel is None: | ||
sel = 2**len(self.sel) - 1 | ||
yield self.adr.eq(adr) | ||
yield self.dat_w.eq(dat) | ||
yield self.sel.eq(sel) | ||
if cti is not None: | ||
yield self.cti.eq(cti) | ||
if bte is not None: | ||
yield self.bte.eq(bte) | ||
yield self.we.eq(1) | ||
yield from self._do_transaction() | ||
|
||
def read(self, adr): | ||
def read(self, adr, cti=None, bte=None): | ||
yield self.adr.eq(adr) | ||
yield self.we.eq(0) | ||
if cti is not None: | ||
yield self.cti.eq(cti) | ||
if bte is not None: | ||
yield self.bte.eq(bte) | ||
yield from self._do_transaction() | ||
return (yield self.dat_r) | ||
|
||
|
@@ -348,6 +363,80 @@ def __init__(self, mem_or_size, read_only=None, init=None, bus=None): | |
|
||
### | ||
|
||
adr_burst = Signal() | ||
|
||
if self.bus.bursting: | ||
adr_wrap_mask = Array((0b0000, 0b0011, 0b0111, 0b1111)) | ||
adr_wrap_max = adr_wrap_mask[-1].bit_length() | ||
|
||
adr_burst_wrap = Signal() | ||
adr_latched = Signal() | ||
|
||
adr_counter = Signal(len(self.bus.adr)) | ||
adr_counter_base = 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 | ||
CTI_BURST_INCREMENTING: adr_burst.eq(1), | ||
# end current burst cycle | ||
CTI_BURST_END: adr_burst.eq(0), | ||
# unsupported burst cycle | ||
"default": adr_burst.eq(0) | ||
}), | ||
adr_burst_wrap.eq(self.bus.bte[0] | self.bus.bte[1]), | ||
adr_counter_base.eq( | ||
Cat(self.bus.adr & ~adr_wrap_mask[self.bus.bte], | ||
self.bus.adr[adr_wrap_max:] | ||
) | ||
) | ||
] | ||
|
||
# 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]), | ||
adr_counter.eq(adr_counter_base + Cat(~self.bus.we, | ||
Replicate(0, len(adr_counter)-1) | ||
) | ||
) | ||
), | ||
If(self.bus.cti == CTI_BURST_END, | ||
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) | ||
] | ||
|
||
else: # self.ram.bursting == False | ||
self.comb += adr_burst.eq(0) | ||
|
||
### | ||
|
||
# memory | ||
port = self.mem.get_port(write_capable=not read_only, we_granularity=8, | ||
mode=READ_FIRST if read_only else WRITE_FIRST) | ||
|
@@ -357,16 +446,21 @@ def __init__(self, mem_or_size, read_only=None, init=None, bus=None): | |
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 | ||
self.comb += port.adr.eq(self.bus.adr[:len(port.adr)]) | ||
if self.bus.bursting: | ||
self.comb += If(adr_burst & adr_latched, | ||
port.adr.eq(adr_next[: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)) | ||
If(self.bus.cyc & self.bus.stb & (~self.bus.ack | adr_burst), self.bus.ack.eq(1)) | ||
] | ||
|
||
# Wishbone To CSR ---------------------------------------------------------------------------------- | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters