From: Sebastien Bourdeauducq Date: Fri, 22 Feb 2013 16:56:35 +0000 (+0100) Subject: New 'specials' API X-Git-Tag: 24jan2021_ls180~2099^2~694 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=49cfba50fabfed542980e7dca4683bef2fbb4110;p=litex.git New 'specials' API --- diff --git a/examples/basic/lm32_inst.py b/examples/basic/lm32_inst.py index 8711dae3..1ea05a05 100644 --- a/examples/basic/lm32_inst.py +++ b/examples/basic/lm32_inst.py @@ -1,50 +1,60 @@ from migen.fhdl.structure import * +from migen.fhdl.specials import Instance +from migen.bus import wishbone from migen.fhdl import verilog class LM32: def __init__(self): - self.inst = Instance("lm32_top", + self.ibus = i = wishbone.Interface() + self.dbus = d = wishbone.Interface() + self.interrupt = Signal(32) + self.ext_break = Signal() + self._i_adr_o = Signal(32) + self._d_adr_o = Signal(32) + self._inst = Instance("lm32_top", Instance.ClockPort("clk_i"), Instance.ResetPort("rst_i"), - - Instance.Input("interrupt", 32), - Instance.Input("ext_break", 1), - - Instance.Output("I_ADR_O", 32), - Instance.Output("I_DAT_O", 32), - Instance.Output("I_SEL_O", 4), - Instance.Output("I_CYC_O", 1), - Instance.Output("I_STB_O", 1), - Instance.Output("I_WE_O", 1), - Instance.Output("I_CTI_O", 3), - Instance.Output("I_LOCK_O", 1), - Instance.Output("I_BTE_O", 1), - Instance.Input("I_DAT_I", 32), - Instance.Input("I_ACK_I", 1), - Instance.Input("I_ERR_I", 1), - Instance.Input("I_RTY_I", 1), - Instance.Output("D_ADR_O", 32), - Instance.Output("D_DAT_O", 32), - Instance.Output("D_SEL_O", 4), - Instance.Output("D_CYC_O", 1), - Instance.Output("D_STB_O", 1), - Instance.Output("D_WE_O", 1), - Instance.Output("D_CTI_O", 3), - Instance.Output("D_LOCK_O", 1), - Instance.Output("D_BTE_O", 1), - Instance.Input("D_DAT_I", 32), - Instance.Input("D_ACK_I", 1), - Instance.Input("D_ERR_I", 1), - Instance.Input("D_RTY_I", 1), + Instance.Input("interrupt", self.interrupt), + #Instance.Input("ext_break", self.ext_break), + + Instance.Output("I_ADR_O", self._i_adr_o), + Instance.Output("I_DAT_O", i.dat_w), + Instance.Output("I_SEL_O", i.sel), + Instance.Output("I_CYC_O", i.cyc), + Instance.Output("I_STB_O", i.stb), + Instance.Output("I_WE_O", i.we), + Instance.Output("I_CTI_O", i.cti), + Instance.Output("I_LOCK_O"), + Instance.Output("I_BTE_O", i.bte), + Instance.Input("I_DAT_I", i.dat_r), + Instance.Input("I_ACK_I", i.ack), + Instance.Input("I_ERR_I", i.err), + Instance.Input("I_RTY_I", 0), - name="lm32") - + Instance.Output("D_ADR_O", self._d_adr_o), + Instance.Output("D_DAT_O", d.dat_w), + Instance.Output("D_SEL_O", d.sel), + Instance.Output("D_CYC_O", d.cyc), + Instance.Output("D_STB_O", d.stb), + Instance.Output("D_WE_O", d.we), + Instance.Output("D_CTI_O", d.cti), + Instance.Output("D_LOCK_O"), + Instance.Output("D_BTE_O", d.bte), + Instance.Input("D_DAT_I", d.dat_r), + Instance.Input("D_ACK_I", d.ack), + Instance.Input("D_ERR_I", d.err), + Instance.Input("D_RTY_I", 0)) + def get_fragment(self): - return Fragment(instances=[self.inst]) + comb = [ + self.ibus.adr.eq(self._i_adr_o[2:]), + self.dbus.adr.eq(self._d_adr_o[2:]) + ] + return Fragment(comb=comb, specials={self._inst}) cpus = [LM32() for i in range(4)] frag = Fragment() for cpu in cpus: frag += cpu.get_fragment() -print(verilog.convert(frag, set([cpus[0].inst.get_io("interrupt"), cpus[0].inst.get_io("I_WE_O")]))) +print(verilog.convert(frag, {cpus[0].interrupt})) diff --git a/examples/basic/memory.py b/examples/basic/memory.py index 3d0aab45..edfedf23 100644 --- a/examples/basic/memory.py +++ b/examples/basic/memory.py @@ -1,11 +1,12 @@ -from migen.fhdl.structure import * +from migen.fhdl.structure import Fragment +from migen.fhdl.specials import Memory from migen.fhdl import verilog mem = Memory(32, 100, init=[5, 18, 32]) p1 = mem.get_port(write_capable=True, we_granularity=8) p2 = mem.get_port(has_re=True, clock_domain="rd") -f = Fragment(memories=[mem]) +f = Fragment(specials={mem}) v = verilog.convert(f, ios={p1.adr, p1.dat_r, p1.we, p1.dat_w, p2.adr, p2.dat_r, p2.re}) print(v) diff --git a/examples/basic/tristate.py b/examples/basic/tristate.py index 3886b969..375524bf 100644 --- a/examples/basic/tristate.py +++ b/examples/basic/tristate.py @@ -1,4 +1,5 @@ from migen.fhdl.structure import * +from migen.fhdl.specials import Tristate from migen.fhdl import verilog n = 6 @@ -7,5 +8,5 @@ o = Signal(n) oe = Signal() i = Signal(n) -f = Fragment(tristates={Tristate(pad, o, oe, i)}) +f = Fragment(specials={Tristate(pad, o, oe, i)}) print(verilog.convert(f, ios={pad, o, oe, i})) diff --git a/examples/pytholite/uio.py b/examples/pytholite/uio.py index 42e66463..01b52e11 100644 --- a/examples/pytholite/uio.py +++ b/examples/pytholite/uio.py @@ -7,6 +7,7 @@ from migen.uio.ioo import UnifiedIOSimulation from migen.pytholite.transel import Register from migen.pytholite.compiler import make_pytholite from migen.sim.generic import Simulator +from migen.fhdl.specials import Memory from migen.fhdl import verilog layout = [("r", 32)] diff --git a/examples/sim/memory.py b/examples/sim/memory.py index 7d66f234..44330179 100644 --- a/examples/sim/memory.py +++ b/examples/sim/memory.py @@ -2,6 +2,7 @@ # License: GPLv3 with additional permissions (see README). from migen.fhdl.structure import * +from migen.fhdl.specials import Memory from migen.sim.generic import Simulator class Mem: @@ -24,7 +25,7 @@ class Mem: s.interrupt = True def get_fragment(self): - return Fragment(memories=[self.mem], sim=[self.do_simulation]) + return Fragment(specials={self.mem}, sim=[self.do_simulation]) def main(): dut = Mem() diff --git a/migen/actorlib/spi.py b/migen/actorlib/spi.py index 674c36c3..649d24bd 100644 --- a/migen/actorlib/spi.py +++ b/migen/actorlib/spi.py @@ -1,6 +1,7 @@ # Simple Processor Interface from migen.fhdl.structure import * +from migen.fhdl.specials import Memory from migen.bank.description import * from migen.flow.actor import * @@ -117,4 +118,4 @@ class Collector(Actor): self._reg_rd.field.w.eq(rp.dat_r) ] - return Fragment(comb, memories=[mem]) + return Fragment(comb, specials={mem}) diff --git a/migen/bus/csr.py b/migen/bus/csr.py index 6a75d7cd..264c63c0 100644 --- a/migen/bus/csr.py +++ b/migen/bus/csr.py @@ -1,4 +1,5 @@ from migen.fhdl.structure import * +from migen.fhdl.specials import Memory from migen.bus.simple import * from migen.bus.transactions import * from migen.sim.generic import PureSimulable @@ -97,4 +98,4 @@ class SRAM: pv = self._page.field.r comb.append(port.adr.eq(Cat(self.bus.adr[:len(port.adr)-len(pv)], pv))) - return Fragment(comb, sync, memories=[self.mem]) + return Fragment(comb, sync, specials={self.mem}) diff --git a/migen/bus/wishbone.py b/migen/bus/wishbone.py index efdf09ad..fb7ec125 100644 --- a/migen/bus/wishbone.py +++ b/migen/bus/wishbone.py @@ -1,4 +1,5 @@ from migen.fhdl.structure import * +from migen.fhdl.specials import Memory from migen.corelogic import roundrobin from migen.corelogic.misc import optree from migen.bus.simple import * @@ -228,4 +229,4 @@ class SRAM: self.bus.ack.eq(1) ) ] - return Fragment(comb, sync, memories=[self.mem]) + return Fragment(comb, sync, specials={self.mem}) diff --git a/migen/bus/wishbone2asmi.py b/migen/bus/wishbone2asmi.py index e19f9f98..0fccefcc 100644 --- a/migen/bus/wishbone2asmi.py +++ b/migen/bus/wishbone2asmi.py @@ -1,5 +1,6 @@ -from migen.bus import wishbone from migen.fhdl.structure import * +from migen.fhdl.specials import Memory +from migen.bus import wishbone from migen.corelogic.fsm import FSM from migen.corelogic.misc import split, displacer, chooser from migen.corelogic.record import Record @@ -136,5 +137,5 @@ class WB2ASMI: fsm.next_state(fsm.TEST_HIT) ) - return Fragment(comb, sync, memories=[data_mem, tag_mem]) \ + return Fragment(comb, sync, specials={data_mem, tag_mem}) \ + fsm.get_fragment() diff --git a/migen/fhdl/namer.py b/migen/fhdl/namer.py index 4f5e317e..d27f303f 100644 --- a/migen/fhdl/namer.py +++ b/migen/fhdl/namer.py @@ -131,13 +131,10 @@ class Namespace: self.pnd = pnd def get_name(self, sig): - if isinstance(sig, Memory): - sig_name = "mem" + if sig.name_override is not None: + sig_name = sig.name_override else: - if sig.name_override is not None: - sig_name = sig.name_override - else: - sig_name = self.pnd[sig] + sig_name = self.pnd[sig] try: n = self.sigs[sig] except KeyError: diff --git a/migen/fhdl/specials.py b/migen/fhdl/specials.py new file mode 100644 index 00000000..829601d8 --- /dev/null +++ b/migen/fhdl/specials.py @@ -0,0 +1,311 @@ +from migen.fhdl.structure import * +from migen.fhdl.tools import list_signals, value_bits_sign + +from migen.fhdl.verilog import _printexpr as verilog_printexpr + +class Special(HUID): + def rename_clock_domain(self): + pass + + def get_clock_domains(self): + return set() + +class Tristate(Special): + def __init__(self, target, o, oe, i=None): + Special.__init__(self) + self.target = target + self.o = o + self.oe = oe + self.i = i + + def list_ios(self, ins, outs, inouts): + r = set() + if inouts: + r.update(list_signals(self.target)) + if ins: + r.update(list_signals(self.o)) + r.update(list_signals(self.oe)) + if outs: + r.update(list_signals(self.i)) + return r + + @staticmethod + def emit_verilog(tristate, ns, clock_domains): + def pe(e): + return verilog_printexpr(ns, e)[0] + w, s = value_bits_sign(tristate.target) + r = "assign " + pe(tristate.target) + " = " \ + + pe(tristate.oe) + " ? " + pe(tristate.o) \ + + " : " + str(w) + "'bz;\n" + if tristate.i is not None: + r += "assign " + pe(tristate.i) + " = " + pe(tristate.target) + ";\n" + r += "\n" + return r + +class TSTriple: + def __init__(self, bits_sign=None, min=None, max=None, reset_o=0, reset_oe=0): + self.o = Signal(bits_sign, min=min, max=max, reset=reset_o) + self.oe = Signal(reset=reset_oe) + self.i = Signal(bits_sign, min=min, max=max) + + def get_tristate(self, target): + return Tristate(target, self.o, self.oe, self.i) + +class Instance(Special): + def __init__(self, of, *items, name=""): + Special.__init__(self) + self.of = of + if name: + self.name_override = name + else: + self.name_override = of + self.items = items + + class _IO: + def __init__(self, name, expr=None): + self.name = name + if expr is None: + expr = Signal() + self.expr = expr + class Input(_IO): + pass + class Output(_IO): + pass + class InOut(_IO): + pass + + class Parameter: + def __init__(self, name, value): + self.name = name + self.value = value + + class _CR: + def __init__(self, name_inst, domain="sys", invert=False): + self.name_inst = name_inst + self.domain = domain + self.invert = invert + class ClockPort(_CR): + pass + class ResetPort(_CR): + pass + + def get_io(self, name): + for item in self.items: + if isinstance(item, Instance._IO) and item.name == name: + return item.expr + + def rename_clock_domain(self): + for cr in filter(lambda x: isinstance(x, Instance._CR), self.items): + if cr.domain == old: + cr.domain = new + + def get_clock_domains(self): + return set(cr.domain + for cr in filter(lambda x: isinstance(x, Instance._CR), self.items)) + + def list_ios(self, ins, outs, inouts): + subsets = [list_signals(item.expr) for item in filter(lambda x: + (ins and isinstance(x, Instance.Input)) + or (outs and isinstance(x, Instance.Output)) + or (inouts and isinstance(x, Instance.InOut)), + self.items)] + if subsets: + return set.union(*subsets) + else: + return set() + + @staticmethod + def emit_verilog(instance, ns, clock_domains): + r = instance.of + " " + parameters = list(filter(lambda i: isinstance(i, Instance.Parameter), instance.items)) + if parameters: + r += "#(\n" + firstp = True + for p in parameters: + if not firstp: + r += ",\n" + firstp = False + r += "\t." + p.name + "(" + if isinstance(p.value, (int, bool)): + r += _printintbool(p.value)[0] + elif isinstance(p.value, float): + r += str(p.value) + elif isinstance(p.value, str): + r += "\"" + p.value + "\"" + else: + raise TypeError + r += ")" + r += "\n) " + r += ns.get_name(instance) + if parameters: r += " " + r += "(\n" + firstp = True + for p in instance.items: + if isinstance(p, Instance._IO): + name_inst = p.name + name_design = verilog_printexpr(ns, p.expr)[0] + elif isinstance(p, Instance.ClockPort): + name_inst = p.name_inst + name_design = ns.get_name(clock_domains[p.domain].clk) + if p.invert: + name_design = "~" + name_design + elif isinstance(p, Instance.ResetPort): + name_inst = p.name_inst + name_design = ns.get_name(clock_domains[p.domain].rst) + else: + continue + if not firstp: + r += ",\n" + firstp = False + r += "\t." + name_inst + "(" + name_design + ")" + if not firstp: + r += "\n" + r += ");\n\n" + return r + +(READ_FIRST, WRITE_FIRST, NO_CHANGE) = range(3) + +class _MemoryPort: + def __init__(self, adr, dat_r, we=None, dat_w=None, + async_read=False, re=None, we_granularity=0, mode=WRITE_FIRST, + clock_domain="sys"): + 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_domain = clock_domain + +class Memory(Special): + def __init__(self, width, depth, init=None): + Special.__init__(self) + self.width = width + self.depth = depth + self.ports = [] + self.init = init + + def get_port(self, write_capable=False, async_read=False, + has_re=False, we_granularity=0, mode=WRITE_FIRST, + clock_domain="sys"): + if we_granularity >= self.width: + we_granularity = 0 + adr = Signal(max=self.depth) + dat_r = Signal(self.width) + if write_capable: + if we_granularity: + we = Signal(self.width//we_granularity) + else: + we = Signal() + dat_w = Signal(self.width) + else: + we = None + dat_w = None + if has_re: + re = Signal() + else: + re = None + mp = _MemoryPort(adr, dat_r, we, dat_w, + async_read, re, we_granularity, mode, + clock_domain) + self.ports.append(mp) + return mp + + def rename_clock_domain(self): + for port in self.ports: + if port.clock_domain == old: + port.clock_domain = new + + def get_clock_domains(self): + return set(port.clock_domain for port in self.ports) + + def list_ios(self, ins, outs, inouts): + s = set() + def add(*sigs): + for sig in sigs: + if sig is not None: + s.add(sig) + for p in self.ports: + if ins: + add(p.adr, p.we, p.dat_w, p.re) + if outs: + add(p.dat_r) + return s + + name_override = "mem" + + @staticmethod + def emit_verilog(memory, ns, clock_domains): + r = "" + gn = ns.get_name # usable instead of verilog_printexpr as ports contain only signals + adrbits = bits_for(memory.depth-1) + + r += "reg [" + str(memory.width-1) + ":0] " \ + + gn(memory) \ + + "[0:" + str(memory.depth-1) + "];\n" + + adr_regs = {} + data_regs = {} + for port in memory.ports: + if not port.async_read: + if port.mode == WRITE_FIRST and port.we is not None: + adr_reg = Signal(name_override="memadr") + r += "reg [" + str(adrbits-1) + ":0] " \ + + gn(adr_reg) + ";\n" + adr_regs[id(port)] = adr_reg + else: + data_reg = Signal(name_override="memdat") + r += "reg [" + str(memory.width-1) + ":0] " \ + + gn(data_reg) + ";\n" + data_regs[id(port)] = data_reg + + for port in memory.ports: + r += "always @(posedge " + gn(clock_domains[port.clock_domain].clk) + ") begin\n" + if port.we is not None: + if port.we_granularity: + n = memory.width//port.we_granularity + for i in range(n): + m = i*port.we_granularity + M = (i+1)*port.we_granularity-1 + sl = "[" + str(M) + ":" + str(m) + "]" + r += "\tif (" + gn(port.we) + "[" + str(i) + "])\n" + r += "\t\t" + gn(memory) + "[" + gn(port.adr) + "]" + sl + " <= " + gn(port.dat_w) + sl + ";\n" + else: + r += "\tif (" + gn(port.we) + ")\n" + r += "\t\t" + gn(memory) + "[" + gn(port.adr) + "] <= " + gn(port.dat_w) + ";\n" + if not port.async_read: + if port.mode == WRITE_FIRST and port.we is not None: + rd = "\t" + gn(adr_regs[id(port)]) + " <= " + gn(port.adr) + ";\n" + else: + bassign = gn(data_regs[id(port)]) + " <= " + gn(memory) + "[" + gn(port.adr) + "];\n" + if port.mode == READ_FIRST or port.we is None: + rd = "\t" + bassign + elif port.mode == NO_CHANGE: + rd = "\tif (!" + gn(port.we) + ")\n" \ + + "\t\t" + bassign + if port.re is None: + r += rd + else: + r += "\tif (" + gn(port.re) + ")\n" + r += "\t" + rd.replace("\n\t", "\n\t\t") + r += "end\n\n" + + for port in memory.ports: + if port.async_read: + r += "assign " + gn(port.dat_r) + " = " + gn(memory) + "[" + gn(port.adr) + "];\n" + else: + if port.mode == WRITE_FIRST and port.we is not None: + r += "assign " + gn(port.dat_r) + " = " + gn(memory) + "[" + gn(adr_regs[id(port)]) + "];\n" + else: + r += "assign " + gn(port.dat_r) + " = " + gn(data_regs[id(port)]) + ";\n" + r += "\n" + + if memory.init is not None: + r += "initial begin\n" + for i, c in enumerate(memory.init): + r += "\t" + gn(memory) + "[" + str(i) + "] <= " + str(memory.width) + "'d" + str(c) + ";\n" + r += "end\n\n" + + return r diff --git a/migen/fhdl/structure.py b/migen/fhdl/structure.py index 321347c0..8052fdff 100644 --- a/migen/fhdl/structure.py +++ b/migen/fhdl/structure.py @@ -229,126 +229,11 @@ class Array(list): else: return list.__getitem__(self, key) -class Tristate: - def __init__(self, target, o, oe, i=None): - self.target = target - self.o = o - self.oe = oe - self.i = i - -class TSTriple: - def __init__(self, bits_sign=None, min=None, max=None, reset_o=0, reset_oe=0): - self.o = Signal(bits_sign, min=min, max=max, reset=reset_o) - self.oe = Signal(reset=reset_oe) - self.i = Signal(bits_sign, min=min, max=max) - - def get_tristate(self, target): - return Tristate(target, self.o, self.oe, self.i) - -# extras - -class Instance(HUID): - def __init__(self, of, *items, name=""): - HUID.__init__(self) - self.of = of - if name: - self.name_override = name - else: - self.name_override = of - self.items = items - - class _IO: - def __init__(self, name, expr=None): - self.name = name - if expr is None: - expr = Signal() - self.expr = expr - class Input(_IO): - pass - class Output(_IO): - pass - class InOut(_IO): - pass - - class Parameter: - def __init__(self, name, value): - self.name = name - self.value = value - - class _CR: - def __init__(self, name_inst, domain="sys", invert=False): - self.name_inst = name_inst - self.domain = domain - self.invert = invert - class ClockPort(_CR): - pass - class ResetPort(_CR): - pass - - def get_io(self, name): - for item in self.items: - if isinstance(item, Instance._IO) and item.name == name: - return item.expr - -(READ_FIRST, WRITE_FIRST, NO_CHANGE) = range(3) - -class _MemoryPort: - def __init__(self, adr, dat_r, we=None, dat_w=None, - async_read=False, re=None, we_granularity=0, mode=WRITE_FIRST, - clock_domain="sys"): - 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_domain = clock_domain - -class Memory(HUID): - def __init__(self, width, depth, init=None): - HUID.__init__(self) - self.width = width - self.depth = depth - self.ports = [] - self.init = init - - def get_port(self, write_capable=False, async_read=False, - has_re=False, we_granularity=0, mode=WRITE_FIRST, - clock_domain="sys"): - if we_granularity >= self.width: - we_granularity = 0 - adr = Signal(max=self.depth) - dat_r = Signal(self.width) - if write_capable: - if we_granularity: - we = Signal(self.width//we_granularity) - else: - we = Signal() - dat_w = Signal(self.width) - else: - we = None - dat_w = None - if has_re: - re = Signal() - else: - re = None - mp = _MemoryPort(adr, dat_r, we, dat_w, - async_read, re, we_granularity, mode, - clock_domain) - self.ports.append(mp) - return mp - -# - class Fragment: - def __init__(self, comb=None, sync=None, instances=None, tristates=None, memories=None, sim=None): + def __init__(self, comb=None, sync=None, specials=None, sim=None): if comb is None: comb = [] if sync is None: sync = dict() - if instances is None: instances = set() - if tristates is None: tristates = set() - if memories is None: memories = set() + if specials is None: specials = set() if sim is None: sim = [] if isinstance(sync, list): @@ -356,9 +241,7 @@ class Fragment: self.comb = comb self.sync = sync - self.instances = set(instances) - self.tristates = set(tristates) - self.memories = set(memories) + self.specials = set(specials) self.sim = sim def __add__(self, other): @@ -368,32 +251,14 @@ class Fragment: for k, v in other.sync.items(): newsync[k].extend(v) return Fragment(self.comb + other.comb, newsync, - self.instances | other.instances, - self.tristates | other.tristates, - self.memories | other.memories, + self.specials | other.specials, self.sim + other.sim) def rename_clock_domain(self, old, new): self.sync["new"] = self.sync["old"] del self.sync["old"] - for inst in self.instances: - for cr in filter(lambda x: isinstance(x, Instance._CR), inst.items): - if cr.domain == old: - cr.domain = new - for mem in self.memories: - for port in mem.ports: - if port.clock_domain == old: - port.clock_domain = new - - def get_clock_domains(self): - r = set(self.sync.keys()) - r |= set(cr.domain - for inst in self.instances - for cr in filter(lambda x: isinstance(x, Instance._CR), inst.items)) - r |= set(port.clock_domain - for mem in self.memories - for port in mem.ports) - return r + for special in self.specials: + special.rename_clock_domain(old, new) def call_sim(self, simulator): for s in self.sim: diff --git a/migen/fhdl/tools.py b/migen/fhdl/tools.py index 02564925..62e1183e 100644 --- a/migen/fhdl/tools.py +++ b/migen/fhdl/tools.py @@ -56,68 +56,17 @@ def group_by_targets(sl): groups.append((targets, [statement])) return groups -def list_inst_ios(i, ins, outs, inouts): - if isinstance(i, Fragment): - return list_inst_ios(i.instances, ins, outs, inouts) - elif isinstance(i, set): - if i: - return set.union(*(list_inst_ios(e, ins, outs, inouts) for e in i)) - else: - return set() - elif isinstance(i, Instance): - subsets = [list_signals(item.expr) for item in filter(lambda x: - (ins and isinstance(x, Instance.Input)) - or (outs and isinstance(x, Instance.Output)) - or (inouts and isinstance(x, Instance.InOut)), - i.items)] - if subsets: - return set.union(*subsets) - else: - return set() - else: - return set() +def list_special_ios(f, ins, outs, inouts): + r = set() + for special in f.specials: + r |= special.list_ios(ins, outs, inouts) + return r -def list_tristate_ios(i, ins, outs, inouts): - if isinstance(i, Fragment): - return list_tristate_ios(i.tristates, ins, outs, inouts) - elif isinstance(i, set): - if i: - return set.union(*(list_tristate_ios(e, ins, outs, inouts) for e in i)) - else: - return set() - elif isinstance(i, Tristate): - r = set() - if inouts: - r.update(list_signals(i.target)) - if ins: - r.update(list_signals(i.o)) - r.update(list_signals(i.oe)) - if outs: - r.update(list_signals(i.i)) - return r - else: - return set() - -def list_it_ios(i, ins, outs, inouts): - return list_inst_ios(i, ins, outs, inouts) \ - | list_tristate_ios(i, ins, outs, inouts) - -def list_mem_ios(m, ins, outs): - if isinstance(m, Fragment): - return list_mem_ios(m.memories, ins, outs) - else: - s = set() - def add(*sigs): - for sig in sigs: - if sig is not None: - s.add(sig) - for x in m: - for p in x.ports: - if ins: - add(p.adr, p.we, p.dat_w, p.re) - if outs: - add(p.dat_r) - return s +def list_clock_domains(f): + r = set(f.sync.keys()) + for special in f.specials: + r |= special.get_clock_domains() + return r def is_variable(node): if isinstance(node, Signal): diff --git a/migen/fhdl/verilog.py b/migen/fhdl/verilog.py index 0e0821cd..9e84b31a 100644 --- a/migen/fhdl/verilog.py +++ b/migen/fhdl/verilog.py @@ -5,7 +5,6 @@ from migen.fhdl.structure import * from migen.fhdl.structure import _Operator, _Slice, _Assign from migen.fhdl.tools import * from migen.fhdl.namer import Namespace, build_namespace -from migen.fhdl import verilog_behavioral as behavioral def _printsig(ns, s): if s.signed: @@ -135,9 +134,9 @@ def _list_comb_wires(f): return r def _printheader(f, ios, name, ns): - sigs = list_signals(f) | list_it_ios(f, True, True, True) | list_mem_ios(f, True, True) - it_mem_outs = list_it_ios(f, False, True, False) | list_mem_ios(f, False, True) - inouts = list_it_ios(f, False, False, True) + sigs = list_signals(f) | list_special_ios(f, True, True, True) + it_mem_outs = list_special_ios(f, False, True, False) + inouts = list_special_ios(f, False, False, True) targets = list_targets(f) | it_mem_outs wires = _list_comb_wires(f) | it_mem_outs r = "module " + name + "(\n" @@ -209,66 +208,10 @@ def _printsync(f, ns, clock_domains): r += "end\n\n" return r -def _printinstances(f, ns, clock_domains): +def _printspecials(f, ns, clock_domains): r = "" - for x in f.instances: - parameters = list(filter(lambda i: isinstance(i, Instance.Parameter), x.items)) - r += x.of + " " - if parameters: - r += "#(\n" - firstp = True - for p in parameters: - if not firstp: - r += ",\n" - firstp = False - r += "\t." + p.name + "(" - if isinstance(p.value, (int, bool)): - r += _printintbool(p.value)[0] - elif isinstance(p.value, float): - r += str(p.value) - elif isinstance(p.value, str): - r += "\"" + p.value + "\"" - else: - raise TypeError - r += ")" - r += "\n) " - r += ns.get_name(x) - if parameters: r += " " - r += "(\n" - firstp = True - for p in x.items: - if isinstance(p, Instance._IO): - name_inst = p.name - name_design = _printexpr(ns, p.expr)[0] - elif isinstance(p, Instance.ClockPort): - name_inst = p.name_inst - name_design = ns.get_name(clock_domains[p.domain].clk) - if p.invert: - name_design = "~" + name_design - elif isinstance(p, Instance.ResetPort): - name_inst = p.name_inst - name_design = ns.get_name(clock_domains[p.domain].rst) - else: - continue - if not firstp: - r += ",\n" - firstp = False - r += "\t." + name_inst + "(" + name_design + ")" - if not firstp: - r += "\n" - r += ");\n\n" - return r - -def _printtristates(f, ns, handler): - r = "" - for tristate in f.tristates: - r += handler(tristate, ns) - return r - -def _printmemories(f, ns, handler, clock_domains): - r = "" - for memory in f.memories: - r += handler(memory, ns, clock_domains) + for special in sorted(f.specials, key=lambda x: x.huid): + r += special.emit_verilog(special, ns, clock_domains) return r def _printinit(f, ios, ns): @@ -276,8 +219,7 @@ def _printinit(f, ios, ns): signals = list_signals(f) \ - ios \ - list_targets(f) \ - - list_it_ios(f, False, True, False) \ - - list_mem_ios(f, False, True) + - list_special_ios(f, False, True, False) if signals: r += "initial begin\n" for s in sorted(signals, key=lambda x: x.huid): @@ -288,14 +230,12 @@ def _printinit(f, ios, ns): def convert(f, ios=None, name="top", clock_domains=None, return_ns=False, - memory_handler=behavioral.mem_handler, - tristate_handler=behavioral.tristate_handler, display_run=False): if ios is None: ios = set() if clock_domains is None: clock_domains = dict() - for d in f.get_clock_domains(): + for d in list_clock_domains(f): cd = ClockDomain(d) clock_domains[d] = cd ios.add(cd.clk) @@ -304,17 +244,14 @@ def convert(f, ios=None, name="top", f = lower_arrays(f) ns = build_namespace(list_signals(f) \ - | list_it_ios(f, True, True, True) \ - | list_mem_ios(f, True, True) \ + | list_special_ios(f, True, True, True) \ | ios) r = "/* Machine-generated using Migen */\n" r += _printheader(f, ios, name, ns) r += _printcomb(f, ns, display_run) r += _printsync(f, ns, clock_domains) - r += _printinstances(f, ns, clock_domains) - r += _printtristates(f, ns, tristate_handler) - r += _printmemories(f, ns, memory_handler, clock_domains) + r += _printspecials(f, ns, clock_domains) r += _printinit(f, ios, ns) r += "endmodule\n" diff --git a/migen/fhdl/verilog_behavioral.py b/migen/fhdl/verilog_behavioral.py deleted file mode 100644 index 2835af26..00000000 --- a/migen/fhdl/verilog_behavioral.py +++ /dev/null @@ -1,86 +0,0 @@ -from migen.fhdl.structure import * -from migen.fhdl.tools import * - -def mem_handler(memory, ns, clock_domains): - r = "" - gn = ns.get_name - adrbits = bits_for(memory.depth-1) - - r += "reg [" + str(memory.width-1) + ":0] " \ - + gn(memory) \ - + "[0:" + str(memory.depth-1) + "];\n" - - adr_regs = {} - data_regs = {} - for port in memory.ports: - if not port.async_read: - if port.mode == WRITE_FIRST and port.we is not None: - adr_reg = Signal(name_override="memadr") - r += "reg [" + str(adrbits-1) + ":0] " \ - + gn(adr_reg) + ";\n" - adr_regs[id(port)] = adr_reg - else: - data_reg = Signal(name_override="memdat") - r += "reg [" + str(memory.width-1) + ":0] " \ - + gn(data_reg) + ";\n" - data_regs[id(port)] = data_reg - - for port in memory.ports: - r += "always @(posedge " + gn(clock_domains[port.clock_domain].clk) + ") begin\n" - if port.we is not None: - if port.we_granularity: - n = memory.width//port.we_granularity - for i in range(n): - m = i*port.we_granularity - M = (i+1)*port.we_granularity-1 - sl = "[" + str(M) + ":" + str(m) + "]" - r += "\tif (" + gn(port.we) + "[" + str(i) + "])\n" - r += "\t\t" + gn(memory) + "[" + gn(port.adr) + "]" + sl + " <= " + gn(port.dat_w) + sl + ";\n" - else: - r += "\tif (" + gn(port.we) + ")\n" - r += "\t\t" + gn(memory) + "[" + gn(port.adr) + "] <= " + gn(port.dat_w) + ";\n" - if not port.async_read: - if port.mode == WRITE_FIRST and port.we is not None: - rd = "\t" + gn(adr_regs[id(port)]) + " <= " + gn(port.adr) + ";\n" - else: - bassign = gn(data_regs[id(port)]) + " <= " + gn(memory) + "[" + gn(port.adr) + "];\n" - if port.mode == READ_FIRST or port.we is None: - rd = "\t" + bassign - elif port.mode == NO_CHANGE: - rd = "\tif (!" + gn(port.we) + ")\n" \ - + "\t\t" + bassign - if port.re is None: - r += rd - else: - r += "\tif (" + gn(port.re) + ")\n" - r += "\t" + rd.replace("\n\t", "\n\t\t") - r += "end\n\n" - - for port in memory.ports: - if port.async_read: - r += "assign " + gn(port.dat_r) + " = " + gn(memory) + "[" + gn(port.adr) + "];\n" - else: - if port.mode == WRITE_FIRST and port.we is not None: - r += "assign " + gn(port.dat_r) + " = " + gn(memory) + "[" + gn(adr_regs[id(port)]) + "];\n" - else: - r += "assign " + gn(port.dat_r) + " = " + gn(data_regs[id(port)]) + ";\n" - r += "\n" - - if memory.init is not None: - r += "initial begin\n" - for i, c in enumerate(memory.init): - r += "\t" + gn(memory) + "[" + str(i) + "] <= " + str(memory.width) + "'d" + str(c) + ";\n" - r += "end\n\n" - - return r - -def tristate_handler(tristate, ns): - gn = ns.get_name - w, s = value_bits_sign(tristate.target) - r = "assign " + gn(tristate.target) + " = " \ - + gn(tristate.oe) + " ? " + gn(tristate.o) \ - + " : " + str(w) + "'bz;\n" - if tristate.i is not None: - r += "assign " + gn(tristate.i) + " = " + gn(tristate.target) + ";\n" - r += "\n" - return r diff --git a/migen/pytholite/io.py b/migen/pytholite/io.py index 943e9726..63c92a60 100644 --- a/migen/pytholite/io.py +++ b/migen/pytholite/io.py @@ -2,6 +2,7 @@ import ast from itertools import zip_longest from migen.fhdl.structure import * +from migen.fhdl.specials import Memory from migen.uio.ioo import UnifiedIOObject from migen.flow.actor import Source, Sink from migen.flow.transactions import * diff --git a/migen/sim/generic.py b/migen/sim/generic.py index cc72769f..17836612 100644 --- a/migen/sim/generic.py +++ b/migen/sim/generic.py @@ -2,6 +2,7 @@ # License: GPLv3 with additional permissions (see README). from migen.fhdl.structure import * +from migen.fhdl.specials import Memory from migen.fhdl import verilog from migen.sim.ipc import * from migen.sim import icarus diff --git a/migen/uio/ioo.py b/migen/uio/ioo.py index 5dfdcba0..1393d915 100644 --- a/migen/uio/ioo.py +++ b/migen/uio/ioo.py @@ -1,4 +1,5 @@ from migen.fhdl.structure import * +from migen.fhdl.specials import Memory from migen.flow.actor import * from migen.flow.transactions import * from migen.actorlib.sim import TokenExchanger @@ -14,7 +15,7 @@ class UnifiedIOObject(Actor): self._memories = set(v for v in self.buses.values() if isinstance(v, Memory)) def get_fragment(self): - return Fragment(memories=self._memories) + return Fragment(specials={self._memories}) (_WAIT_COMPLETE, _WAIT_POLL) = range(2)