diff --git a/examples/memory.py b/examples/memory.py new file mode 100644 index 000000000..e8f4531e6 --- /dev/null +++ b/examples/memory.py @@ -0,0 +1,21 @@ +from migen.fhdl.structure import * +from migen.fhdl import verilog + +d = 100 +d_b = bits_for(d-1) +w = 32 + +a1 = Signal(BV(d_b)) +d1 = Signal(BV(w)) +we1 = Signal(BV(4)) +dw1 = Signal(BV(w)) +p1 = MemoryPort(a1, d1, we1, dw1, we_granularity=8, mode=WRITE_FIRST) + +a2 = Signal(BV(d_b)) +d2 = Signal(BV(w)) +p2 = MemoryPort(a2, d2) + +mem = Memory(w, d, p1, p2, init=[5, 18, 32]) +f = Fragment(memories=[mem]) +v = verilog.convert(f, ios={a1, d1, we1, dw1, a2, d2}) +print(v) diff --git a/migen/fhdl/structure.py b/migen/fhdl/structure.py index b52f4539b..c953834d1 100644 --- a/migen/fhdl/structure.py +++ b/migen/fhdl/structure.py @@ -228,8 +228,11 @@ class Instance: def __hash__(self): return id(self) +(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): + def __init__(self, adr, dat_r, we=None, dat_w=None, + async_read=False, re=None, we_granularity=0, mode=READ_FIRST): self.adr = adr self.dat_r = dat_r self.we = we @@ -237,6 +240,7 @@ class MemoryPort: self.async_read = async_read self.re = re self.we_granularity = we_granularity + self.mode = mode class Memory: def __init__(self, width, depth, *ports, init=None): diff --git a/migen/fhdl/verilog.py b/migen/fhdl/verilog.py index 4c7bc4342..f169b508f 100644 --- a/migen/fhdl/verilog.py +++ b/migen/fhdl/verilog.py @@ -205,10 +205,10 @@ def _printinstances(f, ns, clk, rst): r += ");\n\n" return r -def _printmemories(f, ns, handler, clk, rst): +def _printmemories(f, ns, handler, clk): r = "" for memory in f.memories: - r += handler(memory, ns, clk, rst) + r += handler(memory, ns, clk) return r def convert(f, ios=set(), name="top", @@ -233,7 +233,7 @@ def convert(f, ios=set(), name="top", r += _printcomb(f, ns) r += _printsync(f, ns, clk_signal, rst_signal) r += _printinstances(f, ns, clk_signal, rst_signal) - r += _printmemories(f, ns, memory_handler, clk_signal, rst_signal) + r += _printmemories(f, ns, memory_handler, clk_signal) r += "endmodule\n" if return_ns: diff --git a/migen/fhdl/verilog_mem_behavioral.py b/migen/fhdl/verilog_mem_behavioral.py index 1a8206725..31dddfa24 100644 --- a/migen/fhdl/verilog_mem_behavioral.py +++ b/migen/fhdl/verilog_mem_behavioral.py @@ -1,2 +1,70 @@ -def handler(memory, ns, clk, rst): - return "/* TODO: implement memory */\n" +from migen.fhdl.structure import * + +def handler(memory, ns, clk): + r = "" + gn = ns.get_name + adrbits = bits_for(memory.depth-1) + + storage = Signal(name_override="mem") + r += "reg [" + str(memory.width-1) + ":0] " \ + + gn(storage) \ + + "[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 + + r += "always @(posedge " + gn(clk) + ") begin\n" + for port in memory.ports: + 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(storage) + "[" + gn(port.adr) + "]" + sl + " <= " + gn(port.dat_w) + sl + ";\n" + else: + r += "\tif (" + gn(port.we) + ")\n" + r += "\t\t" + gn(storage) + "[" + gn(port.adr) + "] <= " + gn(port.dat_w) + ";\n" + if not port.async_read: + if port.mode == WRITE_FIRST and port.we is not None: + r += "\t" + gn(adr_regs[id(port)]) + " <= " + gn(port.adr) + ";\n" + else: + bassign = gn(data_regs[id(port)]) + " <= " + gn(storage) + "[" + gn(port.adr) + "];\n" + if port.mode == READ_FIRST or port.we is None: + r += "\t" + bassign + elif port.mode == NO_CHANGE: + r += "\tif (!" + gn(port.we) + ")\n" + r += "\t\t" + bassign + r += "end\n\n" + + for port in memory.ports: + if port.async_read: + r += "assign " + gn(port.dat_r) + " = " + gn(storage) + "[" + gn(port.adr) + "];\n" + else: + if port.mode == WRITE_FIRST and port.we is not None: + r += "assign " + gn(port.dat_r) + " = " + gn(storage) + "[" + 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(storage) + "[" + str(i) + "] <= " + str(memory.width) + "'d" + str(c) + ";\n" + r += "end\n\n" + + return r