
In compat.fhdl.module, we already default to "sync" as the default clocked domain. Using "sys" in memories only would be inconsistent and result in more bugs.
137 lines
4.9 KiB
Python
137 lines
4.9 KiB
Python
import warnings
|
|
|
|
from ...tools import deprecated, extend
|
|
from ...hdl.ast import *
|
|
from ...hdl.ir import Elaboratable
|
|
from ...hdl.mem import Memory as NativeMemory
|
|
from ...hdl.ir import Fragment, Instance
|
|
from ...hdl.dsl import Module
|
|
from .module import Module as CompatModule
|
|
from ...lib.io import Pin
|
|
|
|
|
|
__all__ = ["TSTriple", "Instance", "Memory", "READ_FIRST", "WRITE_FIRST", "NO_CHANGE"]
|
|
|
|
|
|
class TSTriple:
|
|
def __init__(self, bits_sign=None, min=None, max=None, reset_o=0, reset_oe=0, reset_i=0,
|
|
name=None):
|
|
self.o = Signal(bits_sign, min=min, max=max, reset=reset_o,
|
|
name=None if name is None else name + "_o")
|
|
self.oe = Signal(reset=reset_oe,
|
|
name=None if name is None else name + "_oe")
|
|
self.i = Signal(bits_sign, min=min, max=max, reset=reset_i,
|
|
name=None if name is None else name + "_i")
|
|
|
|
def __len__(self):
|
|
return len(self.o)
|
|
|
|
def get_tristate(self, io):
|
|
return Tristate(io, self.o, self.oe, self.i)
|
|
|
|
|
|
class Tristate(Elaboratable):
|
|
def __init__(self, target, o, oe, i=None):
|
|
self.target = target
|
|
self.o = o
|
|
self.oe = oe
|
|
self.i = i if i is not None else None
|
|
|
|
def elaborate(self, platform):
|
|
if hasattr(platform, "get_input_output"):
|
|
pin = Pin(len(self.target), dir="oe" if self.i is None else "io")
|
|
pin.o = self.o
|
|
pin.oe = self.oe
|
|
if self.i is not None:
|
|
pin.i = self.i
|
|
return platform.get_input_output(pin, self.target, extras={})
|
|
|
|
m = Module()
|
|
m.d.comb += self.i.eq(self.target)
|
|
m.submodules += Instance("$tribuf",
|
|
p_WIDTH=len(self.target),
|
|
i_EN=self.oe,
|
|
i_A=self.o,
|
|
o_Y=self.target,
|
|
)
|
|
|
|
f = m.elaborate(platform)
|
|
f.flatten = True
|
|
return f
|
|
|
|
|
|
(READ_FIRST, WRITE_FIRST, NO_CHANGE) = range(3)
|
|
|
|
|
|
class _MemoryPort(CompatModule):
|
|
def __init__(self, adr, dat_r, we=None, dat_w=None, async_read=False, re=None,
|
|
we_granularity=0, mode=WRITE_FIRST, clock_domain="sync"):
|
|
self.adr = adr
|
|
self.dat_r = dat_r
|
|
self.we = we
|
|
self.dat_w = dat_w
|
|
self.async_read = async_read
|
|
self.re = re
|
|
self.we_granularity = we_granularity
|
|
self.mode = mode
|
|
self.clock = ClockSignal(clock_domain)
|
|
|
|
|
|
@extend(NativeMemory)
|
|
@deprecated("it is not necessary or permitted to add Memory as a special or submodule")
|
|
def elaborate(self, platform):
|
|
return Fragment()
|
|
|
|
|
|
class CompatMemory(NativeMemory):
|
|
@deprecated("instead of `get_port()`, use `read_port()` and `write_port()`")
|
|
def get_port(self, write_capable=False, async_read=False, has_re=False, we_granularity=0,
|
|
mode=WRITE_FIRST, clock_domain="sync"):
|
|
if we_granularity >= self.width:
|
|
warnings.warn("do not specify `we_granularity` greater than memory width, as it "
|
|
"is a hard error in non-compatibility mode",
|
|
DeprecationWarning, stacklevel=1)
|
|
we_granularity = 0
|
|
if we_granularity == 0:
|
|
warnings.warn("instead of `we_granularity=0`, use `we_granularity=None` or avoid "
|
|
"specifying it at all, as it is a hard error in non-compatibility mode",
|
|
DeprecationWarning, stacklevel=1)
|
|
we_granularity = None
|
|
assert mode != NO_CHANGE
|
|
rdport = self.read_port(domain="comb" if async_read else clock_domain,
|
|
transparent=mode == WRITE_FIRST)
|
|
rdport.addr.name = "{}_addr".format(self.name)
|
|
adr = rdport.addr
|
|
dat_r = rdport.data
|
|
if write_capable:
|
|
wrport = self.write_port(domain=clock_domain, granularity=we_granularity)
|
|
wrport.addr = rdport.addr
|
|
we = wrport.en
|
|
dat_w = wrport.data
|
|
else:
|
|
we = None
|
|
dat_w = None
|
|
if has_re:
|
|
if mode == READ_FIRST:
|
|
re = rdport.en
|
|
else:
|
|
warnings.warn("the combination of `has_re=True` and `mode=WRITE_FIRST` has "
|
|
"surprising behavior: keeping `re` low would merely latch "
|
|
"the address, while the data will change with changing memory "
|
|
"contents; avoid using `re` with transparent ports as it is a hard "
|
|
"error in non-compatibility mode",
|
|
DeprecationWarning, stacklevel=1)
|
|
re = Signal()
|
|
else:
|
|
re = None
|
|
mp = _MemoryPort(adr, dat_r, we, dat_w,
|
|
async_read, re, we_granularity, mode,
|
|
clock_domain)
|
|
mp.submodules.rdport = rdport
|
|
if write_capable:
|
|
mp.submodules.wrport = wrport
|
|
return mp
|
|
|
|
|
|
Memory = CompatMemory
|