back.rtlil: implement memories.

This commit is contained in:
whitequark 2018-12-21 01:55:59 +00:00
parent 6d9a6b5d84
commit 2b4a8510ca
3 changed files with 88 additions and 11 deletions

31
examples/mem.py Normal file
View file

@ -0,0 +1,31 @@
from nmigen import *
from nmigen.back import rtlil, verilog
class RegisterFile:
def __init__(self):
self.adr = Signal(4)
self.dat_r = Signal(8)
self.dat_w = Signal(8)
self.we = Signal()
self.mem = Memory(width=8, depth=16, init=[0xaa, 0x55])
def get_fragment(self, platform):
m = Module()
m.submodules.rdport = rdport = self.mem.read_port()
m.submodules.wrport = wrport = self.mem.write_port()
m.d.comb += [
rdport.addr.eq(self.adr),
self.dat_r.eq(rdport.data),
rdport.en.eq(1),
wrport.addr.eq(self.adr),
wrport.data.eq(self.dat_w),
wrport.en.eq(self.we),
]
return m.lower(platform)
rf = RegisterFile()
frag = rf.get_fragment(platform=None)
# print(rtlil.convert(frag, ports=[rf.adr, rf.dat_r, rf.dat_w, rf.we]))
print(verilog.convert(frag, ports=[rf.adr, rf.dat_r, rf.dat_w, rf.we]))

View file

@ -3,7 +3,8 @@ import textwrap
from collections import defaultdict, OrderedDict from collections import defaultdict, OrderedDict
from contextlib import contextmanager from contextlib import contextmanager
from ..hdl import ast, ir, xfrm from ..tools import bits_for
from ..hdl import ast, ir, mem, xfrm
class _Namer: class _Namer:
@ -96,16 +97,23 @@ class _ModuleBuilder(_Namer, _Bufferer):
def connect(self, lhs, rhs): def connect(self, lhs, rhs):
self._append(" connect {} {}\n", lhs, rhs) self._append(" connect {} {}\n", lhs, rhs)
def memory(self, width, size, name=None, src=""):
self._src(src)
name = self._make_name(name, local=False)
self._append(" memory width {} size {} {}\n", width, size, name)
return name
def cell(self, kind, name=None, params={}, ports={}, src=""): def cell(self, kind, name=None, params={}, ports={}, src=""):
self._src(src) self._src(src)
name = self._make_name(name, local=True) name = self._make_name(name, local=False)
self._append(" cell {} {}\n", kind, name) self._append(" cell {} {}\n", kind, name)
for param, value in params.items(): for param, value in params.items():
if isinstance(value, str): if isinstance(value, str):
value = repr(value) self._append(" parameter \\{} \"{}\"\n",
param, value.translate(self._escape_map))
else: else:
value = int(value) self._append(" parameter \\{} {:d}\n",
self._append(" parameter \\{} {}\n", param, value) param, value)
for port, wire in ports.items(): for port, wire in ports.items():
self._append(" connect {} {}\n", port, wire) self._append(" connect {} {}\n", port, wire)
self._append(" end\n") self._append(" end\n")
@ -572,7 +580,10 @@ def convert_fragment(builder, fragment, name, top):
for port_name, value in fragment.named_ports.items(): for port_name, value in fragment.named_ports.items():
port_map["\\{}".format(port_name)] = value port_map["\\{}".format(port_name)] = value
return "\\{}".format(fragment.type), port_map if fragment.type[0] == "$":
return fragment.type, port_map
else:
return "\\{}".format(fragment.type), port_map
with builder.module(name or "anonymous", attrs={"top": 1} if top else {}) as module: with builder.module(name or "anonymous", attrs={"top": 1} if top else {}) as module:
compiler_state = _ValueCompilerState(module) compiler_state = _ValueCompilerState(module)
@ -602,13 +613,45 @@ def convert_fragment(builder, fragment, name, top):
# Transform all subfragments to their respective cells. Transforming signals connected # Transform all subfragments to their respective cells. Transforming signals connected
# to their ports into wires eagerly makes sure they get sensible (prefixed with submodule # to their ports into wires eagerly makes sure they get sensible (prefixed with submodule
# name) names. # name) names.
memories = OrderedDict()
for subfragment, sub_name in fragment.subfragments: for subfragment, sub_name in fragment.subfragments:
sub_name, sub_port_map = \ sub_params = OrderedDict()
if hasattr(subfragment, "parameters"):
for param_name, param_value in subfragment.parameters.items():
if isinstance(param_value, mem.Memory):
memory = param_value
if memory not in memories:
memories[memory] = module.memory(width=memory.width, size=memory.depth,
name=memory.name)
addr_bits = bits_for(memory.depth)
for addr, data in enumerate(memory.init):
module.cell("$meminit", ports={
"\\ADDR": rhs_compiler(ast.Const(addr, addr_bits)),
"\\DATA": rhs_compiler(ast.Const(data, memory.width)),
}, params={
"MEMID": memories[memory],
"ABITS": addr_bits,
"WIDTH": memory.width,
"WORDS": 1,
"PRIORITY": 0,
})
param_value = memories[memory]
sub_params[param_name] = param_value
sub_type, sub_port_map = \
convert_fragment(builder, subfragment, top=False, name=sub_name) convert_fragment(builder, subfragment, top=False, name=sub_name)
module.cell(sub_name, name=sub_name, ports={
port: compiler_state.resolve_curr(signal, prefix=sub_name) sub_ports = OrderedDict()
for port, signal in sub_port_map.items() for port, value in sub_port_map.items():
}, params=subfragment.parameters) if isinstance(value, ast.Signal):
sigspec = compiler_state.resolve_curr(value, prefix=sub_name)
else:
sigspec = rhs_compiler(value)
sub_ports[port] = sigspec
module.cell(sub_type, name=sub_name, ports=sub_ports, params=sub_params)
with module.process() as process: with module.process() as process:
with process.case() as case: with process.case() as case:

View file

@ -27,8 +27,11 @@ proc_init
proc_arst proc_arst
proc_dff proc_dff
proc_clean proc_clean
design -save orig
memory_collect
write_verilog write_verilog
# Make sure there are no undriven wires in generated RTLIL. # Make sure there are no undriven wires in generated RTLIL.
design -load orig
proc proc
select -assert-none w:* i:* %a %d o:* %a %ci* %d c:* %co* %a %d n:$* %d select -assert-none w:* i:* %a %d o:* %a %ci* %d c:* %co* %a %d n:$* %d
""".format(il_text)) """.format(il_text))