From: Sebastien Bourdeauducq Date: Thu, 14 Feb 2013 23:17:24 +0000 (+0100) Subject: fhdl: tristate support X-Git-Tag: 24jan2021_ls180~2099^2~697 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=dc93a231c65dc644d5a360ae4f4a4f52965f33b0;p=litex.git fhdl: tristate support --- diff --git a/examples/basic/tristate.py b/examples/basic/tristate.py new file mode 100644 index 00000000..3886b969 --- /dev/null +++ b/examples/basic/tristate.py @@ -0,0 +1,11 @@ +from migen.fhdl.structure import * +from migen.fhdl import verilog + +n = 6 +pad = Signal(n) +o = Signal(n) +oe = Signal() +i = Signal(n) + +f = Fragment(tristates={Tristate(pad, o, oe, i)}) +print(verilog.convert(f, ios={pad, o, oe, i})) diff --git a/migen/fhdl/structure.py b/migen/fhdl/structure.py index 09d056d4..fed0a3d9 100644 --- a/migen/fhdl/structure.py +++ b/migen/fhdl/structure.py @@ -229,6 +229,13 @@ 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 + # extras class Instance(HUID): @@ -327,10 +334,11 @@ class Memory(HUID): # class Fragment: - def __init__(self, comb=None, sync=None, instances=None, memories=None, sim=None): + def __init__(self, comb=None, sync=None, instances=None, tristates=None, memories=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 sim is None: sim = [] @@ -340,9 +348,9 @@ class Fragment: self.comb = comb self.sync = sync self.instances = set(instances) + self.tristates = set(tristates) self.memories = set(memories) self.sim = sim - def __add__(self, other): newsync = defaultdict(list) @@ -352,6 +360,7 @@ class Fragment: newsync[k].extend(v) return Fragment(self.comb + other.comb, newsync, self.instances | other.instances, + self.tristates | other.tristates, self.memories | other.memories, self.sim + other.sim) diff --git a/migen/fhdl/tools.py b/migen/fhdl/tools.py index ab9f9d25..02564925 100644 --- a/migen/fhdl/tools.py +++ b/migen/fhdl/tools.py @@ -64,7 +64,7 @@ def list_inst_ios(i, ins, outs, inouts): return set.union(*(list_inst_ios(e, ins, outs, inouts) for e in i)) else: return set() - else: + 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)) @@ -74,6 +74,33 @@ def list_inst_ios(i, ins, outs, inouts): return set.union(*subsets) else: return set() + else: + return set() + +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): diff --git a/migen/fhdl/verilog.py b/migen/fhdl/verilog.py index 1c4d6082..0e0821cd 100644 --- a/migen/fhdl/verilog.py +++ b/migen/fhdl/verilog.py @@ -5,7 +5,7 @@ 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_mem_behavioral +from migen.fhdl import verilog_behavioral as behavioral def _printsig(ns, s): if s.signed: @@ -135,11 +135,11 @@ def _list_comb_wires(f): return r def _printheader(f, ios, name, ns): - sigs = list_signals(f) | list_inst_ios(f, True, True, True) | list_mem_ios(f, True, True) - inst_mem_outs = list_inst_ios(f, False, True, False) | list_mem_ios(f, False, True) - inouts = list_inst_ios(f, False, False, True) - targets = list_targets(f) | inst_mem_outs - wires = _list_comb_wires(f) | inst_mem_outs + 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) + targets = list_targets(f) | it_mem_outs + wires = _list_comb_wires(f) | it_mem_outs r = "module " + name + "(\n" firstp = True for sig in sorted(ios, key=lambda x: x.huid): @@ -259,6 +259,12 @@ def _printinstances(f, ns, clock_domains): 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: @@ -270,7 +276,7 @@ def _printinit(f, ios, ns): signals = list_signals(f) \ - ios \ - list_targets(f) \ - - list_inst_ios(f, False, True, False) \ + - list_it_ios(f, False, True, False) \ - list_mem_ios(f, False, True) if signals: r += "initial begin\n" @@ -282,7 +288,8 @@ def _printinit(f, ios, ns): def convert(f, ios=None, name="top", clock_domains=None, return_ns=False, - memory_handler=verilog_mem_behavioral.handler, + memory_handler=behavioral.mem_handler, + tristate_handler=behavioral.tristate_handler, display_run=False): if ios is None: ios = set() @@ -297,7 +304,7 @@ def convert(f, ios=None, name="top", f = lower_arrays(f) ns = build_namespace(list_signals(f) \ - | list_inst_ios(f, True, True, True) \ + | list_it_ios(f, True, True, True) \ | list_mem_ios(f, True, True) \ | ios) @@ -306,6 +313,7 @@ def convert(f, ios=None, name="top", 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 += _printinit(f, ios, ns) r += "endmodule\n" diff --git a/migen/fhdl/verilog_behavioral.py b/migen/fhdl/verilog_behavioral.py new file mode 100644 index 00000000..2835af26 --- /dev/null +++ b/migen/fhdl/verilog_behavioral.py @@ -0,0 +1,86 @@ +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/fhdl/verilog_mem_behavioral.py b/migen/fhdl/verilog_mem_behavioral.py deleted file mode 100644 index a9c88e8c..00000000 --- a/migen/fhdl/verilog_mem_behavioral.py +++ /dev/null @@ -1,74 +0,0 @@ -from migen.fhdl.structure import * - -def 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