Merge branch 'master' of github.com:milkymist/migen

This commit is contained in:
Sebastien Bourdeauducq 2012-09-11 00:09:11 +02:00
commit 3b3e2f19eb
8 changed files with 223 additions and 107 deletions

View File

@ -4,36 +4,40 @@ from migen.fhdl import verilog
class LM32:
def __init__(self):
self.inst = Instance("lm32_top",
[("I_ADR_O", BV(32)),
("I_DAT_O", BV(32)),
("I_SEL_O", BV(4)),
("I_CYC_O", BV(1)),
("I_STB_O", BV(1)),
("I_WE_O", BV(1)),
("I_CTI_O", BV(3)),
("I_LOCK_O", BV(1)),
("I_BTE_O", BV(1)),
("D_ADR_O", BV(32)),
("D_DAT_O", BV(32)),
("D_SEL_O", BV(4)),
("D_CYC_O", BV(1)),
("D_STB_O", BV(1)),
("D_WE_O", BV(1)),
("D_CTI_O", BV(3)),
("D_LOCK_O", BV(1)),
("D_BTE_O", BV(1))],
[("interrupt", BV(32)),
("ext_break", BV(1)),
("I_DAT_I", BV(32)),
("I_ACK_I", BV(1)),
("I_ERR_I", BV(1)),
("I_RTY_I", BV(1)),
("D_DAT_I", BV(32)),
("D_ACK_I", BV(1)),
("D_ERR_I", BV(1)),
("D_RTY_I", BV(1))],
clkport="clk_i",
rstport="rst_i",
Instance.ClockPort("clk_i"),
Instance.ResetPort("rst_i"),
Instance.Input("interrupt", BV(32)),
Instance.Input("ext_break", BV(1)),
Instance.Output("I_ADR_O", BV(32)),
Instance.Output("I_DAT_O", BV(32)),
Instance.Output("I_SEL_O", BV(4)),
Instance.Output("I_CYC_O", BV(1)),
Instance.Output("I_STB_O", BV(1)),
Instance.Output("I_WE_O", BV(1)),
Instance.Output("I_CTI_O", BV(3)),
Instance.Output("I_LOCK_O", BV(1)),
Instance.Output("I_BTE_O", BV(1)),
Instance.Input("I_DAT_I", BV(32)),
Instance.Input("I_ACK_I", BV(1)),
Instance.Input("I_ERR_I", BV(1)),
Instance.Input("I_RTY_I", BV(1)),
Instance.Output("D_ADR_O", BV(32)),
Instance.Output("D_DAT_O", BV(32)),
Instance.Output("D_SEL_O", BV(4)),
Instance.Output("D_CYC_O", BV(1)),
Instance.Output("D_STB_O", BV(1)),
Instance.Output("D_WE_O", BV(1)),
Instance.Output("D_CTI_O", BV(3)),
Instance.Output("D_LOCK_O", BV(1)),
Instance.Output("D_BTE_O", BV(1)),
Instance.Input("D_DAT_I", BV(32)),
Instance.Input("D_ACK_I", BV(1)),
Instance.Input("D_ERR_I", BV(1)),
Instance.Input("D_RTY_I", BV(1)),
name="lm32")
def get_fragment(self):
@ -43,4 +47,4 @@ 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.ins["interrupt"], cpus[0].inst.outs["I_WE_O"]])))
print(verilog.convert(frag, set([cpus[0].inst.get_io("interrupt"), cpus[0].inst.get_io("I_WE_O")])))

View File

@ -15,7 +15,7 @@ p1 = MemoryPort(a1, d1, we1, dw1, we_granularity=8)
a2 = Signal(BV(d_b))
d2 = Signal(BV(w))
re2 = Signal()
p2 = MemoryPort(a2, d2, re=re2)
p2 = MemoryPort(a2, d2, re=re2, clock_domain="rd")
mem = Memory(w, d, p1, p2, init=[5, 18, 32])
f = Fragment(memories=[mem])

23
examples/basic/psync.py Normal file
View File

@ -0,0 +1,23 @@
from migen.fhdl.structure import *
from migen.fhdl import verilog
# convert pulse into level change
i = Signal()
level = Signal()
isync = [If(i, level.eq(~level))]
# synchronize level to oclk domain
slevel = [Signal() for i in range(3)]
osync = [
slevel[0].eq(level),
slevel[1].eq(slevel[0]),
slevel[2].eq(slevel[1])
]
# regenerate pulse
o = Signal()
comb = [o.eq(slevel[1] ^ slevel[2])]
f = Fragment(comb, {"i": isync, "o": osync})
v = verilog.convert(f, ios={i, o})
print(v)

View File

@ -1,6 +1,7 @@
import math
import inspect
import re
from collections import defaultdict
from migen.fhdl import tracer
@ -240,26 +241,49 @@ class Array(list):
# extras
class Instance:
def __init__(self, of, outs=[], ins=[], inouts=[], parameters=[], clkport="", rstport="", name=""):
def __init__(self, of, *items, name=""):
self.of = of
if name:
self.name_override = name
else:
self.name_override = of
def process_io(x):
if isinstance(x[1], Signal):
return x # override
elif isinstance(x[1], BV):
return (x[0], Signal(x[1], x[0]))
self.items = items
class _IO:
def __init__(self, name, signal_or_bv):
self.name = name
if isinstance(signal_or_bv, Signal):
self.signal = signal_or_bv
elif isinstance(signal_or_bv, BV):
self.signal = Signal(signal_or_bv, name)
else:
raise TypeError
self.outs = dict(map(process_io, outs))
self.ins = dict(map(process_io, ins))
self.inouts = dict(map(process_io, inouts))
self.parameters = parameters
self.clkport = clkport
self.rstport = rstport
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"):
self.name_inst = name_inst
self.domain = domain
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.signal
def __hash__(self):
return id(self)
@ -267,7 +291,8 @@ class Instance:
class MemoryPort:
def __init__(self, adr, dat_r, we=None, dat_w=None,
async_read=False, re=None, we_granularity=0, mode=WRITE_FIRST):
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
@ -276,6 +301,7 @@ class MemoryPort:
self.re = re
self.we_granularity = we_granularity
self.mode = mode
self.clock_domain = clock_domain
class Memory:
def __init__(self, width, depth, *ports, init=None):
@ -289,24 +315,66 @@ class Memory:
class Fragment:
def __init__(self, comb=None, sync=None, instances=None, memories=None, sim=None):
if comb is None: comb = []
if sync is None: sync = []
if sync is None: sync = dict()
if instances is None: instances = []
if memories is None: memories = []
if sim is None: sim = []
if isinstance(sync, list):
sync = {"sys": sync}
self.comb = comb
self.sync = sync
self.instances = instances
self.memories = memories
self.sim = sim
def __add__(self, other):
return Fragment(self.comb + other.comb,
self.sync + other.sync,
newsync = defaultdict(list)
for k, v in self.sync.items():
newsync[k] = v[:]
for k, v in other.sync.items():
newsync[k].extend(v)
return Fragment(self.comb + other.comb, newsync,
self.instances + other.instances,
self.memories + other.memories,
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
def call_sim(self, simulator):
for s in self.sim:
if simulator.cycle_counter >= 0 or (hasattr(s, "initialize") and s.initialize):
s(simulator)
class ClockDomain:
def __init__(self, n1, n2=None):
if n2 is None:
n_clk = n1 + "_clk"
n_rst = n1 + "_rst"
else:
n_clk = n1
n_rst = n2
self.clk = Signal(name_override=n_clk)
self.rst = Signal(name_override=n_rst)

View File

@ -31,7 +31,10 @@ def list_signals(node):
l = list(map(lambda x: list_signals(x[1]), node.cases))
return list_signals(node.test).union(*l).union(list_signals(node.default))
elif isinstance(node, Fragment):
return list_signals(node.comb) | list_signals(node.sync)
l = list_signals(node.comb)
for k, v in node.sync.items():
l |= list_signals(v)
return l
else:
raise TypeError
@ -56,7 +59,10 @@ def list_targets(node):
l = list(map(lambda x: list_targets(x[1]), node.cases))
return list_targets(node.default).union(*l)
elif isinstance(node, Fragment):
return list_targets(node.comb) | list_targets(node.sync)
l = list_targets(node.comb)
for k, v in node.sync.items():
l |= list_targets(v)
return l
else:
raise TypeError
@ -78,16 +84,17 @@ def group_by_targets(sl):
def list_inst_ios(i, ins, outs, inouts):
if isinstance(i, Fragment):
return list_inst_ios(i.instances, ins, outs, inouts)
elif isinstance(i, list):
if i:
return set.union(*(list_inst_ios(e, ins, outs, inouts) for e in i))
else:
return set()
else:
l = []
for x in i:
if ins:
l += x.ins.values()
if outs:
l += x.outs.values()
if inouts:
l += x.inouts.values()
return set(l)
return set(item.signal 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))
def list_mem_ios(m, ins, outs):
if isinstance(m, Fragment):
@ -254,6 +261,10 @@ def _lower_arrays_sl(sl):
def lower_arrays(f):
f = copy(f)
f.comb, ec1 = _lower_arrays_sl(f.comb)
f.sync, ec2 = _lower_arrays_sl(f.sync)
f.comb += ec1 + ec2
f.comb += ec1
newsync = dict()
for k, v in f.sync.items():
newsync[k], ec2 = _lower_arrays_sl(v)
f.comb += ec2
f.sync = newsync
return f

View File

@ -169,57 +169,64 @@ def _printcomb(f, ns, display_run):
r += "\n"
return r
def _printsync(f, ns, clk, rst):
def _printsync(f, ns, clock_domains):
r = ""
if f.sync:
r += "always @(posedge " + ns.get_name(clk) + ") begin\n"
r += _printnode(ns, _AT_SIGNAL, 1, insert_reset(rst, f.sync))
for k, v in f.sync.items():
r += "always @(posedge " + ns.get_name(clock_domains[k].clk) + ") begin\n"
r += _printnode(ns, _AT_SIGNAL, 1, insert_reset(clock_domains[k].rst, v))
r += "end\n\n"
return r
def _printinstances(f, ns, clk, rst):
def _printinstances(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 x.parameters:
if parameters:
r += "#(\n"
firstp = True
for p in x.parameters:
for p in parameters:
if not firstp:
r += ",\n"
firstp = False
r += "\t." + p[0] + "("
if isinstance(p[1], int) or isinstance(p[1], float) or isinstance(p[1], Constant):
r += str(p[1])
elif isinstance(p[1], str):
r += "\"" + p[1] + "\""
r += "\t." + p.name + "("
if isinstance(p.value, int) or isinstance(p.value, float) or isinstance(p.value, Constant):
r += str(p.value)
elif isinstance(p.value, str):
r += "\"" + p.value + "\""
else:
raise TypeError
r += ")"
r += "\n) "
r += ns.get_name(x)
if x.parameters: r += " "
if parameters: r += " "
r += "(\n"
ports = list(x.ins.items()) + list(x.outs.items()) + list(x.inouts.items())
if x.clkport:
ports.append((x.clkport, clk))
if x.rstport:
ports.append((x.rstport, rst))
firstp = True
for p in ports:
for p in x.items:
if isinstance(p, Instance._IO):
name_inst = p.name
name_design = ns.get_name(p.signal)
elif isinstance(p, Instance.ClockPort):
name_inst = p.name_inst
name_design = ns.get_name(clock_domains[p.domain].clk)
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." + p[0] + "(" + ns.get_name(p[1]) + ")"
r += "\t." + name_inst + "(" + name_design + ")"
if not firstp:
r += "\n"
r += ");\n\n"
return r
def _printmemories(f, ns, handler, clk):
def _printmemories(f, ns, handler, clock_domains):
r = ""
for memory in f.memories:
r += handler(memory, ns, clk)
r += handler(memory, ns, clock_domains)
return r
def _printinit(f, ios, ns):
@ -237,16 +244,17 @@ def _printinit(f, ios, ns):
return r
def convert(f, ios=set(), name="top",
clk_signal=None, rst_signal=None,
clock_domains=None,
return_ns=False,
memory_handler=verilog_mem_behavioral.handler,
display_run=False):
if clk_signal is None:
clk_signal = Signal(name_override="sys_clk")
ios.add(clk_signal)
if rst_signal is None:
rst_signal = Signal(name_override="sys_rst")
ios.add(rst_signal)
if clock_domains is None:
clock_domains = dict()
for d in f.get_clock_domains():
cd = ClockDomain(d)
clock_domains[d] = cd
ios.add(cd.clk)
ios.add(cd.rst)
f = lower_arrays(f)
@ -258,9 +266,9 @@ def convert(f, ios=set(), name="top",
r = "/* Machine-generated using Migen */\n"
r += _printheader(f, ios, name, ns)
r += _printcomb(f, ns, display_run)
r += _printsync(f, ns, clk_signal, rst_signal)
r += _printinstances(f, ns, clk_signal, rst_signal)
r += _printmemories(f, ns, memory_handler, clk_signal)
r += _printsync(f, ns, clock_domains)
r += _printinstances(f, ns, clock_domains)
r += _printmemories(f, ns, memory_handler, clock_domains)
r += _printinit(f, ios, ns)
r += "endmodule\n"

View File

@ -1,6 +1,6 @@
from migen.fhdl.structure import *
def handler(memory, ns, clk):
def handler(memory, ns, clock_domains):
r = ""
gn = ns.get_name
adrbits = bits_for(memory.depth-1)
@ -24,8 +24,8 @@ def handler(memory, ns, clk):
+ gn(data_reg) + ";\n"
data_regs[id(port)] = data_reg
r += "always @(posedge " + gn(clk) + ") begin\n"
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
@ -53,7 +53,7 @@ def handler(memory, ns, clk):
else:
r += "\tif (" + gn(port.re) + ")\n"
r += "\t" + rd.replace("\n\t", "\n\t\t")
r += "end\n\n"
r += "end\n\n"
for port in memory.ports:
if port.async_read:

View File

@ -14,9 +14,14 @@ class TopLevel:
self.top_name = top_name
self.dut_type = dut_type
self.dut_name = dut_name
self.clk_name = clk_name
self.clk_period = clk_period
self.rst_name = rst_name
self._clk_name = clk_name
self._clk_period = clk_period
self._rst_name = rst_name
cd = ClockDomain(self._clk_name, self._rst_name)
self.clock_domains = {"sys": cd}
self.ios = {cd.clk, cd.rst}
def get(self, sockaddr):
template1 = """`timescale 1ns / 1ps
@ -56,9 +61,9 @@ end
r = template1.format(top_name=self.top_name,
dut_type=self.dut_type,
dut_name=self.dut_name,
clk_name=self.clk_name,
hclk_period=str(self.clk_period/2),
rst_name=self.rst_name,
clk_name=self._clk_name,
hclk_period=str(self._clk_period/2),
rst_name=self._rst_name,
sockaddr=sockaddr)
if self.vcd_name is not None:
r += template2.format(vcd_name=self.vcd_name,
@ -78,13 +83,10 @@ class Simulator:
c_top = self.top_level.get(sockaddr)
clk_signal = Signal(name_override=self.top_level.clk_name)
rst_signal = Signal(name_override=self.top_level.rst_name)
c_fragment, self.namespace = verilog.convert(fragment,
{clk_signal, rst_signal},
ios=self.top_level.ios,
name=self.top_level.dut_type,
clk_signal=clk_signal,
rst_signal=rst_signal,
clock_domains=self.top_level.clock_domains,
return_ns=True,
**vopts)