Yosys inference of memories

This example demonstrates direct inference of a dual port (simplex) memory description into a FPGA hard memory block (here: Lattice ECP5 DP16KD primitive). It requires a recent (>= v0.12) release of yosys using the improved memory mapping.

In [1]:
import sys
sys.path.insert(0, '../../')
In [2]:
from myirl.emulation.myhdl import *
from myirl.test.test_array import r1w1, SigArray

Simple read and write port memory

This implementation uses bypass logic when a write is occuring during a read from the same address.

In [3]:
@block
def r1w1(
        clk : ClkSignal,
        we  : Signal,
        addr_r: Signal,
        addr_w: Signal,
        din: Signal,
        dout: Signal.Output,
        ram : SigArray,
        MODE = False, # Conditional compilation flag w/o type annotation
        DWIDTH=16, AWIDTH=10,
        TRANSPARENCY = False
    ) -> IRL:

    print("CALLED MEMORY INSTANCE", DWIDTH)
    
    if TRANSPARENCY:
        @always(clk.posedge)
        def mem_rw_transparent():
            if we and addr_w == addr_r:
                dout.next = din  #Forward
            else:
                dout.next = ram[addr_r][DWIDTH:]

            if we:
                ram[addr_w].next = din
    else:
        @always(clk.posedge)
        def mem_rw():
            dout.next = ram[addr_r][DWIDTH:]
            
            if we:
                ram[addr_w].next = din        
        
    return instances()
In [4]:
def memtest(MODE = 0, STYLE = 1, data_w=16, addr_w=6, mem = r1w1, TRANSPARENT = True):
    c = ClkSignal(name = 'clk')
    c.init = True
    wren = Signal(bool(), name = 'we')
    ra, wa = [ Signal(intbv()[addr_w:]) for n in ['addr_write', 'addr_read'] ]
    a, q = [ Signal(intbv()[data_w:]) for n in ['a', 'q'] ]

    ram_data = SigArray([ intbv(v)[data_w:] for v in range(2 ** addr_w)],
        name='ram_sig', init=True)

    inst = mem(clk=c, we=wren, addr_r=ra, addr_w=wa, din=a, dout=q, MODE=False, ram = ram_data,
        AWIDTH=addr_w, DWIDTH=data_w, TRANSPARENCY = TRANSPARENT)

    return inst
In [ ]:
 

Mapping to hardware

In [5]:
from myirl.targets import pyosys
In [6]:
DATA_WIDTH = 64

Elaborate memory unit and emit CXXRTL code:

In [7]:
def convert(dw, aw = 7):

    tgt = pyosys.RTLIL("memtest%d" % dw)

    MEM = r1w1

    tb = memtest(data_w=dw, mem = MEM, addr_w = aw, TRANSPARENT = True)
    d = tb.elab(tgt, elab_all = True)
    d = d[0]
    d.run("hierarchy -check")
    d.run("stat", capture = None)
    # d.run("write_rtlil mem8.il")
    d.run("debug memory -nomap; debug opt")
    
    return d
In [8]:
d = convert(DATA_WIDTH, 7)
CALLED MEMORY INSTANCE 64
Creating process 'r1w1/mem_rw_transparent' with sensitivity (clk'rising,)
 Adding module with name `r1w1` 
 DEBUG: SKIP ARRAYTYPE `ram` : <class 'myirl.lists.SigArray'> 
     DEBUG SLICE READ MEMORY to dout AWIDTH:7 DWIDTH:64
 [Component 'meminit/meminit'] blackbox not returning instances 
DEBUG ADD ROM 7:64
 PARAM PRIORITY --> 48 
 PARAM WORDS --> 128 
 PARAM ABITS --> 7 
 PARAM WIDTH --> 64 
 PARAM MEMID --> mem_ram_sig 
 [Component 'memrd/memrd'] blackbox not returning instances 
 PARAM CLK_ENABLE --> False 
 PARAM CLK_POLARITY --> True 
 PARAM TRANSPARENT --> False 
 PARAM ABITS --> 7 
 PARAM WIDTH --> 64 
 PARAM MEMID --> mem_ram_sig 
     DEBUG SLICE WRITE MEMORY to ram_sig AWIDTH:7 DWIDTH:64
 [Component 'memwr/memwr'] blackbox not returning instances 
 PARAM CLK_ENABLE --> True 
 PARAM CLK_POLARITY --> True 
 PARAM PRIORITY --> 48 
 PARAM ABITS --> 7 
 PARAM WIDTH --> 64 
 PARAM MEMID --> mem_ram_sig 
DEBUG TOP LEVEL WRITE MEM ram_sig
 FINALIZE implementation `r1w1` of `r1w1` 

-- Running command `tee -q hierarchy -top \r1w1' --

-- Running command `tee -q hierarchy -check' --

-- Running command `stat' --

3. Printing statistics.

=== r1w1 ===

   Number of wires:                 17
   Number of wire bits:            658
   Number of public wires:           7
   Number of public wire bits:     208
   Number of memories:               1
   Number of memory bits:         8192
   Number of processes:              0
   Number of cells:                  7
     $and                            1
     $dff                            1
     $eq                             1
     $meminit                        1
     $memrd                          1
     $memwr                          1
     $mux                            1


-- Running command `tee -q debug memory -nomap; debug opt' --

5. Executing OPT pass (performing simple optimizations).

5.1. Executing OPT_EXPR pass (perform const folding).
Optimizing module r1w1.

5.2. Executing OPT_MERGE pass (detect identical cells).
Finding identical cells in module `\r1w1'.
Removed a total of 0 cells.

5.3. Executing OPT_MUXTREE pass (detect dead branches in mux trees).
Running muxtree optimizer on module \r1w1..
  Creating internal representation of mux trees.
  No muxes found in this module.
Removed 0 multiplexer ports.

5.4. Executing OPT_REDUCE pass (consolidate $*mux and $reduce_* inputs).
  Optimizing cells in module \r1w1.
Performed a total of 0 changes.

5.5. Executing OPT_MERGE pass (detect identical cells).
Finding identical cells in module `\r1w1'.
Removed a total of 0 cells.

5.6. Executing OPT_DFF pass (perform DFF optimizations).

5.7. Executing OPT_CLEAN pass (remove unused cells and wires).
Finding unused cells or wires in module \r1w1..

5.8. Executing OPT_EXPR pass (perform const folding).
Optimizing module r1w1.

5.9. Finished OPT passes. (There is nothing left to do.)

Testing hardware generation

Note: Post map simulation may require external memory models of blackbox Vendor Primitives.

In [9]:
TECHMAP = '/usr/share/yosys'

def synth_ecp5(d):
    # Read blackbox cells for awareness of DP16KD:
    d.run("read_verilog -lib -specify %s/ecp5/cells_sim.v %s/ecp5/cells_bb.v" % (TECHMAP, TECHMAP))

    # First try DP16KD mapping:
    d.run("memory_bram -rules %s/ecp5/brams.txt" % TECHMAP)
    d.run("techmap -map %s/ecp5/brams_map.v" % TECHMAP)

    # Remaining (addr_w <= 8 bit) to LUT RAM:
    d.run("memory_bram -rules %s/ecp5/lutrams.txt" % TECHMAP)
    d.run("techmap -map %s/ecp5/lutrams_map.v" % TECHMAP)
    d.run("opt_clean")
    
def synth_gatemate(d):
    # Read blackbox cells for awareness of DP16KD:
    d.run("read_verilog -lib -specify %s/gatemate/cells_sim.v %s/gatemate/cells_bb.v" % (TECHMAP, TECHMAP))

    d.run("memory_bram -rules %s/gatemate/brams.txt" % TECHMAP)
    d.run("techmap -map %s/gatemate/brams_map.v" % TECHMAP)

    d.run("opt")
    
def synth_efinix(d):
    # Read blackbox cells for awareness of DP16KD:
    d.run("read_verilog -lib -specify %s/efinix/cells_sim.v %s/efinix/cells_map.v" % (TECHMAP, TECHMAP))

    d.run("memory_bram -rules %s/efinix/brams.txt" % TECHMAP)
    d.run("techmap -map %s/efinix/brams_map.v" % TECHMAP)

    d.run("opt")    
    
d.run("ls", capture = None)

synth_ecp5(d)
d.run("stat", capture = None)

d.run("write_rtlil mapped.il")

d.display_rtl(selection = '*', fmt = 'dot')
-- Running command `ls' --

1 modules:
  r1w1

-- Running command `tee -q read_verilog -lib -specify /usr/share/yosys/ecp5/cells_sim.v /usr/share/yosys/ecp5/cells_bb.v' --

-- Running command `tee -q memory_bram -rules /usr/share/yosys/ecp5/brams.txt' --

-- Running command `tee -q techmap -map /usr/share/yosys/ecp5/brams_map.v' --

-- Running command `tee -q memory_bram -rules /usr/share/yosys/ecp5/lutrams.txt' --

-- Running command `tee -q techmap -map /usr/share/yosys/ecp5/lutrams_map.v' --

-- Running command `tee -q opt_clean' --

-- Running command `stat' --

13. Printing statistics.

=== r1w1 ===

   Number of wires:                 12
   Number of wire bits:            347
   Number of public wires:           6
   Number of public wire bits:     144
   Number of memories:               0
   Number of memory bits:            0
   Number of processes:              0
   Number of cells:                  7
     $and                            1
     $dff                            1
     $dffe                           1
     $eq                             1
     $mux                            1
     PDPW16KD                        2


-- Running command `tee -q write_rtlil mapped.il' --

-- Running command `show -format dot -prefix memtest64 *' --

15. Generating Graphviz representation of design.
Writing dot description to `memtest64.dot'.
Dumping module r1w1 to page 1.
In [10]:
from yosys import display
display.display_dot("memtest%d" % DATA_WIDTH)
Out[10]:
r1w1 r1w1 n7 addr_r c21 A B $299 $eq Y n7:e->c21:w x3 5:5 - 0:0 n7:e->x3:w x4 6:6 - 0:0 n7:e->x4:w x10 0:0 - 0:0 n7:e->x10:w x11 1:1 - 0:0 n7:e->x11:w x12 2:2 - 0:0 n7:e->x12:w x13 3:3 - 0:0 n7:e->x13:w x14 4:4 - 0:0 n7:e->x14:w x102 5:5 - 0:0 n7:e->x102:w x103 6:6 - 0:0 n7:e->x103:w x109 0:0 - 0:0 n7:e->x109:w x110 1:1 - 0:0 n7:e->x110:w x111 2:2 - 0:0 n7:e->x111:w x112 3:3 - 0:0 n7:e->x112:w x113 4:4 - 0:0 n7:e->x113:w n8 addr_w n8:e->c21:w x15 0:0 - 0:0 n8:e->x15:w x16 1:1 - 0:0 n8:e->x16:w x17 2:2 - 0:0 n8:e->x17:w x18 3:3 - 0:0 n8:e->x18:w x19 4:4 - 0:0 n8:e->x19:w x20 5:5 - 0:0 n8:e->x20:w x21 6:6 - 0:0 n8:e->x21:w x114 0:0 - 0:0 n8:e->x114:w x115 1:1 - 0:0 n8:e->x115:w x116 2:2 - 0:0 n8:e->x116:w x117 3:3 - 0:0 n8:e->x117:w x118 4:4 - 0:0 n8:e->x118:w x119 5:5 - 0:0 n8:e->x119:w x120 6:6 - 0:0 n8:e->x120:w n9 clk c17 CLK D EN $298 $dffe Q n9:e->c17:w c23 CLK D $305 $dff Q n9:e->c23:w c131 ADR0 ADR1 ADR10 ADR11 ADR12 ADR13 ADR2 ADR3 ADR4 ADR5 ADR6 ADR7 ADR8 ADR9 ADW0 ADW1 ADW2 ADW3 ADW4 ADW5 ADW6 ADW7 ADW8 BE0 BE1 BE2 BE3 CER CEW CLKR CLKW DI0 DI1 DI10 DI11 DI12 DI13 DI14 DI15 DI16 DI17 DI18 DI19 DI2 DI20 DI21 DI22 DI23 DI24 DI25 DI26 DI27 DI28 DI29 DI3 DI30 DI31 DI32 DI33 DI34 DI35 DI4 DI5 DI6 DI7 DI8 DI9 OCER RST $mem_ram_sig.0.0.0 PDPW16KD DO0 DO1 DO10 DO11 DO12 DO13 DO14 DO15 DO16 DO17 DO18 DO19 DO2 DO20 DO21 DO22 DO23 DO24 DO25 DO26 DO27 DO28 DO29 DO3 DO30 DO31 DO32 DO33 DO34 DO35 DO4 DO5 DO6 DO7 DO8 DO9 n9:e->c131:w n9:e->c131:w c132 ADR0 ADR1 ADR10 ADR11 ADR12 ADR13 ADR2 ADR3 ADR4 ADR5 ADR6 ADR7 ADR8 ADR9 ADW0 ADW1 ADW2 ADW3 ADW4 ADW5 ADW6 ADW7 ADW8 BE0 BE1 BE2 BE3 CER CEW CLKR CLKW DI0 DI1 DI10 DI11 DI12 DI13 DI14 DI15 DI16 DI17 DI18 DI19 DI2 DI20 DI21 DI22 DI23 DI24 DI25 DI26 DI27 DI28 DI29 DI3 DI30 DI31 DI32 DI33 DI34 DI35 DI4 DI5 DI6 DI7 DI8 DI9 OCER RST $mem_ram_sig.1.0.0 PDPW16KD DO0 DO1 DO10 DO11 DO12 DO13 DO14 DO15 DO16 DO17 DO18 DO19 DO2 DO20 DO21 DO22 DO23 DO24 DO25 DO26 DO27 DO28 DO29 DO3 DO30 DO31 DO32 DO33 DO34 DO35 DO4 DO5 DO6 DO7 DO8 DO9 n9:e->c132:w n9:e->c132:w n10 din n10:e->c17:w x26 0:0 - 0:0 n10:e->x26:w x27 1:1 - 0:0 n10:e->x27:w x28 10:10 - 0:0 n10:e->x28:w x29 11:11 - 0:0 n10:e->x29:w x30 12:12 - 0:0 n10:e->x30:w x31 13:13 - 0:0 n10:e->x31:w x32 14:14 - 0:0 n10:e->x32:w x33 15:15 - 0:0 n10:e->x33:w x34 16:16 - 0:0 n10:e->x34:w x35 17:17 - 0:0 n10:e->x35:w x36 18:18 - 0:0 n10:e->x36:w x37 19:19 - 0:0 n10:e->x37:w x38 2:2 - 0:0 n10:e->x38:w x39 20:20 - 0:0 n10:e->x39:w x40 21:21 - 0:0 n10:e->x40:w x41 22:22 - 0:0 n10:e->x41:w x42 23:23 - 0:0 n10:e->x42:w x43 24:24 - 0:0 n10:e->x43:w x44 25:25 - 0:0 n10:e->x44:w x45 26:26 - 0:0 n10:e->x45:w x46 27:27 - 0:0 n10:e->x46:w x47 28:28 - 0:0 n10:e->x47:w x48 29:29 - 0:0 n10:e->x48:w x49 3:3 - 0:0 n10:e->x49:w x50 30:30 - 0:0 n10:e->x50:w x51 31:31 - 0:0 n10:e->x51:w x52 32:32 - 0:0 n10:e->x52:w x53 33:33 - 0:0 n10:e->x53:w x54 34:34 - 0:0 n10:e->x54:w x55 35:35 - 0:0 n10:e->x55:w x56 4:4 - 0:0 n10:e->x56:w x57 5:5 - 0:0 n10:e->x57:w x58 6:6 - 0:0 n10:e->x58:w x59 7:7 - 0:0 n10:e->x59:w x60 8:8 - 0:0 n10:e->x60:w x61 9:9 - 0:0 n10:e->x61:w x125 36:36 - 0:0 n10:e->x125:w x126 37:37 - 0:0 n10:e->x126:w x127 46:46 - 0:0 n10:e->x127:w x128 47:47 - 0:0 n10:e->x128:w x129 48:48 - 0:0 n10:e->x129:w x130 49:49 - 0:0 n10:e->x130:w x131 50:50 - 0:0 n10:e->x131:w x132 51:51 - 0:0 n10:e->x132:w x133 52:52 - 0:0 n10:e->x133:w x134 53:53 - 0:0 n10:e->x134:w x135 54:54 - 0:0 n10:e->x135:w x136 55:55 - 0:0 n10:e->x136:w x137 38:38 - 0:0 n10:e->x137:w x138 56:56 - 0:0 n10:e->x138:w x139 57:57 - 0:0 n10:e->x139:w x140 58:58 - 0:0 n10:e->x140:w x141 59:59 - 0:0 n10:e->x141:w x142 60:60 - 0:0 n10:e->x142:w x143 61:61 - 0:0 n10:e->x143:w x144 62:62 - 0:0 n10:e->x144:w x145 63:63 - 0:0 n10:e->x145:w x148 39:39 - 0:0 n10:e->x148:w x155 40:40 - 0:0 n10:e->x155:w x156 41:41 - 0:0 n10:e->x156:w x157 42:42 - 0:0 n10:e->x157:w x158 43:43 - 0:0 n10:e->x158:w x159 44:44 - 0:0 n10:e->x159:w x160 45:45 - 0:0 n10:e->x160:w n11 dout n12 we c22 A B $302 $and Y n12:e->c22:w n12:e->c131:w n12:e->c131:w n12:e->c131:w n12:e->c131:w n12:e->c132:w n12:e->c132:w n12:e->c132:w n12:e->c132:w v0 1'1 v0:e->c17:w c25 A B S $306 $mux Y c17:e->c25:w c21:e->c22:w c22:e->c23:w c23:e->c25:w c25:e->n11:w v1 1'0 v1:e->c131:w v2 1'0 v2:e->c131:w v5 1'0 v5:e->c131:w v6 1'0 v6:e->c131:w v7 1'0 v7:e->c131:w v8 1'0 v8:e->c131:w v9 1'0 v9:e->c131:w v22 1'0 v22:e->c131:w v23 1'0 v23:e->c131:w v24 1'1 v24:e->c131:w v25 1'1 v25:e->c131:w v98 1'1 v98:e->c131:w v99 1'0 v99:e->c131:w x62 0:0 - 18:18 c131:e->x62:w x63 0:0 - 19:19 c131:e->x63:w x64 0:0 - 28:28 c131:e->x64:w x65 0:0 - 29:29 c131:e->x65:w x66 0:0 - 30:30 c131:e->x66:w x67 0:0 - 31:31 c131:e->x67:w x68 0:0 - 32:32 c131:e->x68:w x69 0:0 - 33:33 c131:e->x69:w x70 0:0 - 34:34 c131:e->x70:w x71 0:0 - 35:35 c131:e->x71:w x72 0:0 - 0:0 c131:e->x72:w x73 0:0 - 1:1 c131:e->x73:w x74 0:0 - 20:20 c131:e->x74:w x75 0:0 - 2:2 c131:e->x75:w x76 0:0 - 3:3 c131:e->x76:w x77 0:0 - 4:4 c131:e->x77:w x78 0:0 - 5:5 c131:e->x78:w x79 0:0 - 6:6 c131:e->x79:w x80 0:0 - 7:7 c131:e->x80:w x81 0:0 - 8:8 c131:e->x81:w x82 0:0 - 9:9 c131:e->x82:w x83 0:0 - 10:10 c131:e->x83:w x84 0:0 - 11:11 c131:e->x84:w x85 0:0 - 21:21 c131:e->x85:w x86 0:0 - 12:12 c131:e->x86:w x87 0:0 - 13:13 c131:e->x87:w x88 0:0 - 14:14 c131:e->x88:w x89 0:0 - 15:15 c131:e->x89:w x90 0:0 - 16:16 c131:e->x90:w x91 0:0 - 17:17 c131:e->x91:w x92 0:0 - 22:22 c131:e->x92:w x93 0:0 - 23:23 c131:e->x93:w x94 0:0 - 24:24 c131:e->x94:w x95 0:0 - 25:25 c131:e->x95:w x96 0:0 - 26:26 c131:e->x96:w x97 0:0 - 27:27 c131:e->x97:w x3:e->c131:w x4:e->c131:w x10:e->c131:w x11:e->c131:w x12:e->c131:w x13:e->c131:w x14:e->c131:w x15:e->c131:w x16:e->c131:w x17:e->c131:w x18:e->c131:w x19:e->c131:w x20:e->c131:w x21:e->c131:w x26:e->c131:w x27:e->c131:w x28:e->c131:w x29:e->c131:w x30:e->c131:w x31:e->c131:w x32:e->c131:w x33:e->c131:w x34:e->c131:w x35:e->c131:w x36:e->c131:w x37:e->c131:w x38:e->c131:w x39:e->c131:w x40:e->c131:w x41:e->c131:w x42:e->c131:w x43:e->c131:w x44:e->c131:w x45:e->c131:w x46:e->c131:w x47:e->c131:w x48:e->c131:w x49:e->c131:w x50:e->c131:w x51:e->c131:w x52:e->c131:w x53:e->c131:w x54:e->c131:w x55:e->c131:w x56:e->c131:w x57:e->c131:w x58:e->c131:w x59:e->c131:w x60:e->c131:w x61:e->c131:w n2 x62:e->n2:w x63:e->n2:w x64:e->n2:w x65:e->n2:w x66:e->n2:w x67:e->n2:w x68:e->n2:w x69:e->n2:w x70:e->n2:w x71:e->n2:w x72:e->n2:w x73:e->n2:w x74:e->n2:w x75:e->n2:w x76:e->n2:w x77:e->n2:w x78:e->n2:w x79:e->n2:w x80:e->n2:w x81:e->n2:w x82:e->n2:w x83:e->n2:w x84:e->n2:w x85:e->n2:w x86:e->n2:w x87:e->n2:w x88:e->n2:w x89:e->n2:w x90:e->n2:w x91:e->n2:w x92:e->n2:w x93:e->n2:w x94:e->n2:w x95:e->n2:w x96:e->n2:w x97:e->n2:w v100 1'0 v100:e->c132:w v101 1'0 v101:e->c132:w v104 1'0 v104:e->c132:w v105 1'0 v105:e->c132:w v106 1'0 v106:e->c132:w v107 1'0 v107:e->c132:w v108 1'0 v108:e->c132:w v121 1'0 v121:e->c132:w v122 1'0 v122:e->c132:w v123 1'1 v123:e->c132:w v124 1'1 v124:e->c132:w v146 1'x v146:e->c132:w v147 1'x v147:e->c132:w v149 1'x v149:e->c132:w v150 1'x v150:e->c132:w v151 1'x v151:e->c132:w v152 1'x v152:e->c132:w v153 1'x v153:e->c132:w v154 1'x v154:e->c132:w v197 1'1 v197:e->c132:w v198 1'0 v198:e->c132:w x161 0:0 - 54:54 c132:e->x161:w x162 0:0 - 55:55 c132:e->x162:w x163 0:0 - 64:64 c132:e->x163:w x164 0:0 - 65:65 c132:e->x164:w x165 0:0 - 66:66 c132:e->x165:w x166 0:0 - 67:67 c132:e->x166:w x167 0:0 - 68:68 c132:e->x167:w x168 0:0 - 69:69 c132:e->x168:w x169 0:0 - 70:70 c132:e->x169:w x170 0:0 - 71:71 c132:e->x170:w x171 0:0 - 36:36 c132:e->x171:w x172 0:0 - 37:37 c132:e->x172:w x173 0:0 - 56:56 c132:e->x173:w x174 0:0 - 38:38 c132:e->x174:w x175 0:0 - 39:39 c132:e->x175:w x176 0:0 - 40:40 c132:e->x176:w x177 0:0 - 41:41 c132:e->x177:w x178 0:0 - 42:42 c132:e->x178:w x179 0:0 - 43:43 c132:e->x179:w x180 0:0 - 44:44 c132:e->x180:w x181 0:0 - 45:45 c132:e->x181:w x182 0:0 - 46:46 c132:e->x182:w x183 0:0 - 47:47 c132:e->x183:w x184 0:0 - 57:57 c132:e->x184:w x185 0:0 - 48:48 c132:e->x185:w x186 0:0 - 49:49 c132:e->x186:w x187 0:0 - 50:50 c132:e->x187:w x188 0:0 - 51:51 c132:e->x188:w x189 0:0 - 52:52 c132:e->x189:w x190 0:0 - 53:53 c132:e->x190:w x191 0:0 - 58:58 c132:e->x191:w x192 0:0 - 59:59 c132:e->x192:w x193 0:0 - 60:60 c132:e->x193:w x194 0:0 - 61:61 c132:e->x194:w x195 0:0 - 62:62 c132:e->x195:w x196 0:0 - 63:63 c132:e->x196:w x102:e->c132:w x103:e->c132:w x109:e->c132:w x110:e->c132:w x111:e->c132:w x112:e->c132:w x113:e->c132:w x114:e->c132:w x115:e->c132:w x116:e->c132:w x117:e->c132:w x118:e->c132:w x119:e->c132:w x120:e->c132:w x125:e->c132:w x126:e->c132:w x127:e->c132:w x128:e->c132:w x129:e->c132:w x130:e->c132:w x131:e->c132:w x132:e->c132:w x133:e->c132:w x134:e->c132:w x135:e->c132:w x136:e->c132:w x137:e->c132:w x138:e->c132:w x139:e->c132:w x140:e->c132:w x141:e->c132:w x142:e->c132:w x143:e->c132:w x144:e->c132:w x145:e->c132:w x148:e->c132:w x155:e->c132:w x156:e->c132:w x157:e->c132:w x158:e->c132:w x159:e->c132:w x160:e->c132:w x161:e->n2:w x162:e->n2:w n4 $307 x163:e->n4:w x164:e->n4:w x165:e->n4:w x166:e->n4:w x167:e->n4:w x168:e->n4:w x169:e->n4:w x170:e->n4:w x171:e->n2:w x172:e->n2:w x173:e->n2:w x174:e->n2:w x175:e->n2:w x176:e->n2:w x177:e->n2:w x178:e->n2:w x179:e->n2:w x180:e->n2:w x181:e->n2:w x182:e->n2:w x183:e->n2:w x184:e->n2:w x185:e->n2:w x186:e->n2:w x187:e->n2:w x188:e->n2:w x189:e->n2:w x190:e->n2:w x191:e->n2:w x192:e->n2:w x193:e->n2:w x194:e->n2:w x195:e->n2:w x196:e->n2:w x199 63:0 - 63:0 x199:e->n4:w n2:e->c25:w n2:e->x199:w \n
In [11]:
class GateMateTarget(pyosys.RTLIL):
    def __init__(self, *args):
        super().__init__(*args)
        print("Selecting GateMate target")
        self.debug = True
        
    def finalize(self, top):
        print("GATEMATE FINALIZE")
        tname = top.name
        design = self._design
        design.run("hierarchy -top %s" % tname)
        synth_gatemate(design)
        design.run('stat', capture = None)
        # self.write_cxxrtl(top)
In [12]:
import simulation
from yosys.simulator import CXXRTL


@simulation.sim.testbench(CXXRTL, time_unit = 'ns', target_class = GateMateTarget)
def tb_memtest(MODE = 0, STYLE = 1, data_w=16, addr_w=7, mem = r1w1):
    
    ClkSignal = simulation.ClkSignal
    Signal = simulation.Signal

    c = ClkSignal(name = 'clk')
    c.init = True
    
    M = (1 << (data_w - 1))

    wren = Signal(bool(), name = 'we')
    ra, wa = [ Signal(intbv()[addr_w:]) for n in ['addr_write', 'addr_read'] ]
    a, q = [ Signal(intbv()[data_w:]) for n in ['a', 'q'] ]

    ram_sig = SigArray([intbv(M | v)[data_w:] for v in range(2 ** addr_w)],
        name='ram_sig', init=True)

    # print(ram_sig[0].size())

    inst = mem(clk=c,
        we=wren,
        addr_r=ra, addr_w=wa, din=a, dout=q, MODE=False, ram = ram_sig,
        AWIDTH=addr_w, DWIDTH=data_w,
        TRANSPARENCY = True)

    @simulation.always(simulation.delay(2))
    def clkgen():
        c.next = ~c

    def write(addr, data):
        print("WRITE", addr, data)
        yield c.negedge
        wa.next = addr
        a.next = data
        wren.next = True
        yield c.negedge
        wren.next = False

    def write_verify(addr, data, value):
        print("WRITE VERIFY", addr)
        yield c.negedge
        wa.next = addr
        a.next = data
        wren.next = True
        yield c.negedge
        # print("DEBUG Q", bin(int(q)))
        assert int(q) == value
        wren.next = False

    @simulation.sequence
    def stim():
        ra.next = 0x20
        wa.next = 0x00

        # Write and verify that we're not bypassing:
        # i.e. the value is expected to be the initial one
        yield from write_verify(0x00, 0xaa, M | 0x20)
        ra.next = 0x00
        yield c.negedge
        # Now make sure we're getting the written value
        assert int(q) == 0xaa

        # ra == wa, verify transparency bypass:
        ra.next = 0x40
        yield from write_verify(0x40, 0x55, 0x55)
        yield c.negedge
        ra.next = 0x00
        yield c.negedge
        assert int(q) == 0xaa
        ra.next = 0x40
        yield c.negedge
        assert int(q) == 0x55
        ra.next = 0x1a
        yield c.negedge
        assert int(q) == M | 0x1a # Initial

        print("SIM DONE")

    return simulation.instances()
In [13]:
r1w1.ctx.components
Out[13]:
['r1w1_s1_s1_s7_s7_s64_s64_s128_0_64_7_1']
In [14]:
t = tb_memtest(data_w = 12)
 Module top_r1w1: Existing instance r1w1, rename to r1w1_1 
CALLED MEMORY INSTANCE 12
Creating process 'r1w1/mem_rw_transparent' with sensitivity (clk'rising,)
DEBUG: Skip non-simulation type <class 'myirl.emulation.myhdl.wrapped_wrapper'>
DEBUG: Skip non-simulation type <class 'type'>
DEBUG: Skip non-simulation type <class 'myirl.lists.SigArray'>
DEBUG: Skip non-simulation type <class 'function'>
DEBUG: Skip non-simulation type <class 'type'>
DEBUG: Skip non-simulation type <class 'function'>
In [15]:
t.run(100)
t.design.run("write_rtlil memtest.il")
Selecting GateMate target
DEBUG DUMMY GET s_72ae
 Adding module with name `r1w1_1` 
 DEBUG: SKIP ARRAYTYPE `ram` : <class 'myirl.lists.SigArray'> 
     DEBUG SLICE READ MEMORY to dout AWIDTH:7 DWIDTH:12
DEBUG ADD ROM 7:12
 PARAM PRIORITY --> 48 
 PARAM WORDS --> 128 
 PARAM ABITS --> 7 
 PARAM WIDTH --> 12 
 PARAM MEMID --> mem_ram_sig 
 PARAM CLK_ENABLE --> False 
 PARAM CLK_POLARITY --> True 
 PARAM TRANSPARENT --> False 
 PARAM ABITS --> 7 
 PARAM WIDTH --> 12 
 PARAM MEMID --> mem_ram_sig 
     DEBUG SLICE WRITE MEMORY to ram_sig AWIDTH:7 DWIDTH:12
 PARAM CLK_ENABLE --> True 
 PARAM CLK_POLARITY --> True 
 PARAM PRIORITY --> 48 
 PARAM ABITS --> 7 
 PARAM WIDTH --> 12 
 PARAM MEMID --> mem_ram_sig 
DEBUG TOP LEVEL WRITE MEM ram_sig
GATEMATE FINALIZE

-- Running command `tee -q hierarchy -top r1w1_1' --

-- Running command `tee -q read_verilog -lib -specify /usr/share/yosys/gatemate/cells_sim.v /usr/share/yosys/gatemate/cells_bb.v' --

-- Running command `tee -q memory_bram -rules /usr/share/yosys/gatemate/brams.txt' --

-- Running command `tee -q techmap -map /usr/share/yosys/gatemate/brams_map.v' --

-- Running command `tee -q opt' --

-- Running command `stat' --

22. Printing statistics.
Compiling /tmp/myirl_top_r1w1_jvmlr8n_/r1w1_1_1516.pyx because it changed.
[1/1] Cythonizing /tmp/myirl_top_r1w1_jvmlr8n_/r1w1_1_1516.pyx
running build_ext
building 'r1w1_1_1516' extension
creating build/temp.linux-x86_64-3.9/tmp/myirl_top_r1w1_jvmlr8n_
x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -ffile-prefix-map=/build/python3.9-RNBry6/python3.9-3.9.2=. -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -g -ffile-prefix-map=/build/python3.9-RNBry6/python3.9-3.9.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -DCOSIM_NAMESPACE=r1w1_1_1516 -I../../myirl/../ -I/tmp/myirl_top_r1w1_jvmlr8n_/ -I/usr/share/yosys/include -I/usr/include/python3.9 -c /tmp/myirl_top_r1w1_jvmlr8n_/r1w1_1_1516.cpp -o build/temp.linux-x86_64-3.9/tmp/myirl_top_r1w1_jvmlr8n_/r1w1_1_1516.o
x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -ffile-prefix-map=/build/python3.9-RNBry6/python3.9-3.9.2=. -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -g -ffile-prefix-map=/build/python3.9-RNBry6/python3.9-3.9.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -DCOSIM_NAMESPACE=r1w1_1_1516 -I../../myirl/../ -I/tmp/myirl_top_r1w1_jvmlr8n_/ -I/usr/share/yosys/include -I/usr/include/python3.9 -c /tmp/myirl_top_r1w1_jvmlr8n_/r1w1_1_1516_rtl.cpp -o build/temp.linux-x86_64-3.9/tmp/myirl_top_r1w1_jvmlr8n_/r1w1_1_1516_rtl.o
x86_64-linux-gnu-g++ -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-z,relro -g -fwrapv -O2 -Wl,-z,relro -g -fwrapv -O2 -g -ffile-prefix-map=/build/python3.9-RNBry6/python3.9-3.9.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 build/temp.linux-x86_64-3.9/tmp/myirl_top_r1w1_jvmlr8n_/r1w1_1_1516.o build/temp.linux-x86_64-3.9/tmp/myirl_top_r1w1_jvmlr8n_/r1w1_1_1516_rtl.o -o build/lib.linux-x86_64-3.9/r1w1_1_1516.cpython-39-x86_64-linux-gnu.so
copying build/lib.linux-x86_64-3.9/r1w1_1_1516.cpython-39-x86_64-linux-gnu.so -> 
Open for writing: tb_memtest.vcd
 CXXRTL context: SKIP INTERFACE ITEM `ram` 
 CXXRTL context: SKIP INTERFACE ITEM `MODE` 
 CXXRTL context: SKIP INTERFACE ITEM `DWIDTH` 
 CXXRTL context: SKIP INTERFACE ITEM `AWIDTH` 
 CXXRTL context: SKIP INTERFACE ITEM `TRANSPARENCY` 
WRITE VERIFY 0
WRITE VERIFY 64
SIM DONE
DEBUG STOP PROCESS stim

Duplex read, single write

Attention: The pyosys API may crash the notebook without warning (terminate the kernel) when the yosys-abc utility is not present. May be the case in the Binder setup.

In [16]:
# ! [ `which yosys-abc` ] || sudo apt-get install yosys-ghdl
In [17]:
@block
def r2w1_gated(
        clk : ClkSignal,
        re	: Signal,
        we	: Signal,
        addr_r0: Signal,
        addr_r1: Signal,
        addr_w: Signal,
        din: Signal,
        dout0: Signal.Output,
        dout1: Signal.Output,
        ram_data : list,
        MODE = False, # Conditional compilation flag w/o type annotation
        DWIDTH=16, AWIDTH=10
    ) -> IRL:

    ram = SigArray(ram_data, name='ram_sig', init=True)

    @always(clk.posedge)
    def mem_r2w():
        dout1.next = ram[addr_r1]
        if re:
            dout0.next = ram[addr_r0]
        if we:
            ram[addr_w].next = din

    return instances()
In [18]:
@simulation.sim.testbench(CXXRTL, time_unit = 'ns', target_class = GateMateTarget)
def tb_memtest2(MODE = 0, STYLE = 1, data_w=16, addr_w=6, mem = r2w1_gated):
    c = simulation.ClkSignal(name = 'clk')
    c.init = True
    rden = simulation.Signal(bool(), name = 're')
    wren = simulation.Signal(bool(), name = 'we')
    ra, rb, wa = [ simulation.Signal(intbv()[addr_w:]) for _ in range(3) ]
    a, q0, q1 = [ simulation.Signal(intbv()[data_w:]) for n in ['a', 'q0', 'q1'] ]

    ram_data = [ intbv(v)[data_w:] for v in range(2 ** addr_w)]

    inst = mem(clk=c,
        re=rden,
        we=wren,
        addr_r0=ra,
        addr_r1=rb,
        addr_w=wa, din=a,
        dout0=q0, dout1=q1,
        MODE=False, ram_data = ram_data,
        AWIDTH=addr_w, DWIDTH=data_w)

    @simulation.always(simulation.delay(2))
    def clkgen():
        c.next = ~c

    @simulation.sequence
    def stim():
        rb.next = 0xfa
        ra.next = 0xfa
        wa.next = 0x20
        wren.next = False
        yield simulation.delay(5)
        yield c.negedge
        assert int(q1) == 0xfa
        assert int(q0) != 0xfa
        rden.next = True
        yield c.negedge
        ra.next = 0xaa
        rden.next = False

        wren.next = True
        a.next = 0x44
        yield c.negedge
        wren.next = False
        yield c.negedge
        assert int(q0) == 0xfa
        yield c.negedge
        rb.next = 0x20
        print(int(q0), int(q1))
        yield c.negedge
        print(int(q0), int(q1))
        assert int(q1) == 0x44

        print("SIM DONE")

    return simulation.instances()
In [19]:
dw = 16

MEM = r2w1_gated

tb = tb_memtest2(data_w=dw, mem = MEM, addr_w = 11)
tb._force_compile = True
tb.debug()
# tb.run(200)
Creating process 'r2w1_gated/mem_r2w' with sensitivity (clk'rising,)
DEBUG: Skip non-simulation type <class 'myirl.emulation.myhdl.wrapped_wrapper'>
DEBUG: Skip non-simulation type <class 'list'>
Selecting GateMate target
DEBUG DUMMY GET s_bb42
 Adding module with name `r2w1_gated` 
 DEBUG: SKIP NON-SIGNAL ARGUMENT `ram_data` : <class 'list'> 
 DEBUG SLICE READ MEMORY to dout1 AWIDTH:11 DWIDTH:16
     DEBUG SLICE READ MEMORY to dout0 AWIDTH:11 DWIDTH:16
     DEBUG SLICE WRITE MEMORY to ram_sig AWIDTH:11 DWIDTH:16
DEBUG ADD ROM 11:16
 PARAM PRIORITY --> 48 
 PARAM WORDS --> 2048 
 PARAM ABITS --> 11 
 PARAM WIDTH --> 16 
 PARAM MEMID --> mem_ram_sig 
 PARAM CLK_ENABLE --> True 
 PARAM CLK_POLARITY --> True 
 PARAM TRANSPARENT --> False 
 PARAM ABITS --> 11 
 PARAM WIDTH --> 16 
 PARAM MEMID --> mem_ram_sig 
DEBUG TOP LEVEL READ MEM dout1
 PARAM CLK_ENABLE --> True 
 PARAM CLK_POLARITY --> True 
 PARAM TRANSPARENT --> False 
 PARAM ABITS --> 11 
 PARAM WIDTH --> 16 
 PARAM MEMID --> mem_ram_sig 
DEBUG TOP LEVEL READ MEM dout0
 PARAM CLK_ENABLE --> True 
 PARAM CLK_POLARITY --> True 
 PARAM PRIORITY --> 48 
 PARAM ABITS --> 11 
 PARAM WIDTH --> 16 
 PARAM MEMID --> mem_ram_sig 
DEBUG TOP LEVEL WRITE MEM ram_sig
GATEMATE FINALIZE

=== r1w1_1 ===

   Number of wires:                 10
   Number of wire bits:             66
   Number of public wires:           6
   Number of public wire bits:      40
   Number of memories:               1
   Number of memory bits:         1536
   Number of processes:              0
   Number of cells:                  7
     $and                            1
     $dff                            1
     $eq                             1
     $meminit                        1
     $memrd                          1
     $memwr                          1
     $mux                            1


-- Running command `tee -q write_cxxrtl -namespace r1w1_1_1516 -print-wire-types -header /tmp/myirl_top_r1w1_jvmlr8n_/r1w1_1_1516_rtl.cpp' --

-- Running command `tee -q write_rtlil memtest.il' --

-- Running command `tee -q hierarchy -top r2w1_gated' --

-- Running command `tee -q read_verilog -lib -specify /usr/share/yosys/gatemate/cells_sim.v /usr/share/yosys/gatemate/cells_bb.v' --

-- Running command `tee -q memory_bram -rules /usr/share/yosys/gatemate/brams.txt' --

-- Running command `tee -q techmap -map /usr/share/yosys/gatemate/brams_map.v' --

-- Running command `tee -q opt' --

-- Running command `stat' --

31. Printing statistics.

=== r2w1_gated ===

   Number of wires:                 23
   Number of wire bits:            292
   Number of public wires:           9
   Number of public wire bits:      84
   Number of memories:               0
   Number of memory bits:            0
   Number of processes:              0
   Number of cells:                  2
     CC_BRAM_40K                     2


-- Running command `tee -q debug memory -nomap' --

-- Running command `show -format dot -prefix r2w1_gated *' --

33. Generating Graphviz representation of design.
Writing dot description to `r2w1_gated.dot'.
Dumping module r2w1_gated to page 1.
In [20]:
tb.design.run("write_rtlil r2w1.il", capture = None)
-- Running command `write_rtlil r2w1.il' --

34. Executing RTLIL backend.