mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
New 'specials' API
This commit is contained in:
parent
e82ea19cdc
commit
49cfba50fa
18 changed files with 406 additions and 412 deletions
|
@ -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.Input("interrupt", self.interrupt),
|
||||
#Instance.Input("ext_break", self.ext_break),
|
||||
|
||||
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("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),
|
||||
|
||||
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),
|
||||
|
||||
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}))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}))
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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:
|
||||
|
|
311
migen/fhdl/specials.py
Normal file
311
migen/fhdl/specials.py
Normal file
|
@ -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
|
|
@ -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:
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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 *
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in a new issue