riscv-formal-nmigen/nmigen/compat/fhdl/specials.py

141 lines
5.1 KiB
Python

import warnings
from ..._utils 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 .structure import Signal
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, attrs={}, invert=None)
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, Elaboratable):
def __init__(self, width, depth, init=None, name=None):
super().__init__(width=width, depth=depth, init=init, name=name)
@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