From 2b4a8510ca3653e796b0a6f8ac0d7868cfdf9a9b Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 21 Dec 2018 01:55:59 +0000 Subject: [PATCH] back.rtlil: implement memories. --- examples/mem.py | 31 ++++++++++++++++++++ nmigen/back/rtlil.py | 65 +++++++++++++++++++++++++++++++++++------- nmigen/back/verilog.py | 3 ++ 3 files changed, 88 insertions(+), 11 deletions(-) create mode 100644 examples/mem.py diff --git a/examples/mem.py b/examples/mem.py new file mode 100644 index 0000000..f966a30 --- /dev/null +++ b/examples/mem.py @@ -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])) diff --git a/nmigen/back/rtlil.py b/nmigen/back/rtlil.py index 0b61268..370b42c 100644 --- a/nmigen/back/rtlil.py +++ b/nmigen/back/rtlil.py @@ -3,7 +3,8 @@ import textwrap from collections import defaultdict, OrderedDict from contextlib import contextmanager -from ..hdl import ast, ir, xfrm +from ..tools import bits_for +from ..hdl import ast, ir, mem, xfrm class _Namer: @@ -96,16 +97,23 @@ class _ModuleBuilder(_Namer, _Bufferer): def connect(self, 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=""): self._src(src) - name = self._make_name(name, local=True) + name = self._make_name(name, local=False) self._append(" cell {} {}\n", kind, name) for param, value in params.items(): if isinstance(value, str): - value = repr(value) + self._append(" parameter \\{} \"{}\"\n", + param, value.translate(self._escape_map)) else: - value = int(value) - self._append(" parameter \\{} {}\n", param, value) + self._append(" parameter \\{} {:d}\n", + param, value) for port, wire in ports.items(): self._append(" connect {} {}\n", port, wire) self._append(" end\n") @@ -572,7 +580,10 @@ def convert_fragment(builder, fragment, name, top): for port_name, value in fragment.named_ports.items(): 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: 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 # to their ports into wires eagerly makes sure they get sensible (prefixed with submodule # name) names. + memories = OrderedDict() 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) - module.cell(sub_name, name=sub_name, ports={ - port: compiler_state.resolve_curr(signal, prefix=sub_name) - for port, signal in sub_port_map.items() - }, params=subfragment.parameters) + + sub_ports = OrderedDict() + for port, value in sub_port_map.items(): + 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 process.case() as case: diff --git a/nmigen/back/verilog.py b/nmigen/back/verilog.py index c9822c0..72bb83c 100644 --- a/nmigen/back/verilog.py +++ b/nmigen/back/verilog.py @@ -27,8 +27,11 @@ proc_init proc_arst proc_dff proc_clean +design -save orig +memory_collect write_verilog # Make sure there are no undriven wires in generated RTLIL. +design -load orig proc select -assert-none w:* i:* %a %d o:* %a %ci* %d c:* %co* %a %d n:$* %d """.format(il_text)) -- 2.30.2