{ "cells": [ { "cell_type": "markdown", "id": "6d0b2a72-c65b-49cd-a4b8-c69d4bf260c3", "metadata": {}, "source": [ "# Yosys inference of memories\n", "\n", "This example demonstrates direct inference of a dual port (simplex) memory description into a FPGA hard memory block (here: Lattice ECP5 DP16KD primitive).\n", "It requires a recent (>= v0.12) release of yosys. Proper TDP inference may only be covered with a patched version.\n", "\n", "**Not applicable to binder demo**" ] }, { "cell_type": "code", "execution_count": 2, "id": "bdf2ad89-5861-4c93-938a-4f412aad1639", "metadata": {}, "outputs": [], "source": [ "from myirl.emulation.myhdl import *\n", "from myirl.test.test_array import r1w1, SigArray" ] }, { "cell_type": "markdown", "id": "5211999a-42a9-48ce-b0dc-2b914a53051c", "metadata": {}, "source": [ "## Simple read and write port memory\n", "\n", "This implementation uses bypass logic when a write is occuring during a read from the same address." ] }, { "cell_type": "code", "execution_count": 3, "id": "07333c2c-a76d-4f76-a566-b8024b28c66e", "metadata": {}, "outputs": [], "source": [ "@block\n", "def r1w1(\n", " clk : ClkSignal,\n", " we : Signal,\n", " addr_r: Signal,\n", " addr_w: Signal,\n", " din: Signal,\n", " dout: Signal.Output,\n", " ram : SigArray,\n", " MODE = False, # Conditional compilation flag w/o type annotation\n", " DWIDTH=16, AWIDTH=10,\n", " TRANSPARENCY = False\n", " ) -> IRL:\n", "\n", " print(\"CALLED MEMORY INSTANCE\", DWIDTH)\n", " \n", " if TRANSPARENCY:\n", " @always(clk.posedge)\n", " def mem_rw_transparent():\n", " if we and addr_w == addr_r:\n", " dout.next = din #Forward\n", " else:\n", " dout.next = ram[addr_r][DWIDTH:]\n", "\n", " if we:\n", " ram[addr_w].next = din\n", " else:\n", " @always(clk.posedge)\n", " def mem_rw():\n", " dout.next = ram[addr_r][DWIDTH:]\n", " \n", " if we:\n", " ram[addr_w].next = din \n", " \n", " return instances()\n" ] }, { "cell_type": "code", "execution_count": 4, "id": "59b9b9b3-5d70-4c65-8f23-0b215578bb6d", "metadata": {}, "outputs": [], "source": [ "def memtest(MODE = 0, STYLE = 1, data_w=16, addr_w=6, mem = r1w1, TRANSPARENT = True):\n", " c = ClkSignal(name = 'clk')\n", " c.init = True\n", " wren = Signal(bool(), name = 'we')\n", " ra, wa = [ Signal(intbv()[addr_w:]) for n in ['addr_write', 'addr_read'] ]\n", " a, q = [ Signal(intbv()[data_w:]) for n in ['a', 'q'] ]\n", "\n", " ram_data = SigArray([ intbv(v)[data_w:] for v in range(2 ** addr_w)],\n", " name='ram_sig', init=True)\n", "\n", " inst = mem(clk=c, we=wren, addr_r=ra, addr_w=wa, din=a, dout=q, MODE=False, ram = ram_data,\n", " AWIDTH=addr_w, DWIDTH=data_w, TRANSPARENCY = TRANSPARENT)\n", "\n", " return inst" ] }, { "cell_type": "code", "execution_count": null, "id": "e89ab554-780e-4135-9b63-7c42d3e59b1d", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "84f0e9a4-c1b8-4a16-9cb3-2d9a5eca90ff", "metadata": {}, "source": [ "## Mapping to hardware\n", "\n", "**Note** myIRL inference does *not yet* detect built-in transparency, (redundant) FFs will be inferred." ] }, { "cell_type": "code", "execution_count": 5, "id": "76ac7892-4770-4572-9b81-e223b30f44ae", "metadata": {}, "outputs": [], "source": [ "from myirl.targets import pyosys" ] }, { "cell_type": "code", "execution_count": 6, "id": "d66a9a6e-5a44-4d65-8727-6914593c587f", "metadata": {}, "outputs": [], "source": [ "DATA_WIDTH = 32" ] }, { "cell_type": "markdown", "id": "c9ad20ea-155e-4435-8159-41e511879e96", "metadata": {}, "source": [ "Elaborate memory unit and emit CXXRTL code:" ] }, { "cell_type": "code", "execution_count": 7, "id": "a6a11195-13f9-46eb-8666-be3a0795c77b", "metadata": {}, "outputs": [], "source": [ "def convert(dw, aw = 7):\n", "\n", " tgt = pyosys.RTLIL(\"memtest%d\" % dw)\n", "\n", " MEM = r1w1\n", "\n", " tb = memtest(data_w=dw, mem = MEM, addr_w = aw, TRANSPARENT = True)\n", " d = tb.elab(tgt, elab_all = True)\n", " d = d[0]\n", " d.run(\"hierarchy -check\")\n", " d.run(\"stat\", capture = None)\n", " d.run(\"write_rtlil mem8.il\")\n", " d.run(\"debug memory -nomap; debug opt\")\n", " \n", " return d" ] }, { "cell_type": "code", "execution_count": 8, "id": "2b1503a5-a4bc-4d91-9fa6-3593fdc4eb1a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "FALLBACK: UNHANDLED ROOT CLASS , create new context\n", "CALLED MEMORY INSTANCE 32\n", "\u001b[32m Adding module with name `r1w1` \u001b[0m\n", " DEBUG: SKIP ARRAYTYPE `ram` : \n", " DEBUG SLICE READ MEMORY to dout AWIDTH:7 DWIDTH:32\n", "\u001b[7;35m [_blackbox_method 'meminit/meminit'] blackbox not returning instances \u001b[0m\n", "DEBUG ADD ROM 7:32\n", "\u001b[7;34m PARAM PRIORITY --> 48 \u001b[0m\n", "\u001b[7;34m PARAM WORDS --> 128 \u001b[0m\n", "\u001b[7;34m PARAM ABITS --> 7 \u001b[0m\n", "\u001b[7;34m PARAM WIDTH --> 32 \u001b[0m\n", "\u001b[7;34m PARAM MEMID --> $mem_ram_sig \u001b[0m\n", "\u001b[7;35m [_blackbox_method 'memrd/memrd'] blackbox not returning instances \u001b[0m\n", "\u001b[7;34m PARAM CLK_ENABLE --> False \u001b[0m\n", "\u001b[7;34m PARAM CLK_POLARITY --> True \u001b[0m\n", "\u001b[7;34m PARAM TRANSPARENT --> False \u001b[0m\n", "\u001b[7;34m PARAM ABITS --> 7 \u001b[0m\n", "\u001b[7;34m PARAM WIDTH --> 32 \u001b[0m\n", "\u001b[7;34m PARAM MEMID --> $mem_ram_sig \u001b[0m\n", " DEBUG SLICE WRITE MEMORY to ram_sig AWIDTH:7 DWIDTH:32\n", "\u001b[7;35m [_blackbox_method 'memwr/memwr'] blackbox not returning instances \u001b[0m\n", "\u001b[7;34m PARAM CLK_ENABLE --> True \u001b[0m\n", "\u001b[7;34m PARAM CLK_POLARITY --> True \u001b[0m\n", "\u001b[7;34m PARAM PRIORITY --> 48 \u001b[0m\n", "\u001b[7;34m PARAM ABITS --> 7 \u001b[0m\n", "\u001b[7;34m PARAM WIDTH --> 32 \u001b[0m\n", "\u001b[7;34m PARAM MEMID --> $mem_ram_sig \u001b[0m\n", "DEBUG TOP LEVEL WRITE MEM ram_sig\n", "\u001b[7;34m FINALIZE implementation `r1w1` of `r1w1` \u001b[0m\n", "\n", "-- Running command `tee -q hierarchy -top \\r1w1' --\n", "\n", "-- Running command `tee -q hierarchy -check' --\n", "\n", "-- Running command `stat' --\n", "\n", "3. Printing statistics.\n", "\n", "=== r1w1 ===\n", "\n", " Number of wires: 17\n", " Number of wire bits: 338\n", " Number of public wires: 7\n", " Number of public wire bits: 112\n", " Number of memories: 1\n", " Number of memory bits: 4096\n", " Number of processes: 0\n", " Number of cells: 7\n", " $and 1\n", " $dff 1\n", " $eq 1\n", " $meminit 1\n", " $memrd 1\n", " $memwr 1\n", " $mux 1\n", "\n", "\n", "-- Running command `tee -q write_rtlil mem8.il' --\n", "\n", "-- Running command `tee -q debug memory -nomap; debug opt' --\n", "\n", "6. Executing OPT pass (performing simple optimizations).\n", "\n", "6.1. Executing OPT_EXPR pass (perform const folding).\n", "Optimizing module r1w1.\n", "\n", "6.2. Executing OPT_MERGE pass (detect identical cells).\n", "Finding identical cells in module `\\r1w1'.\n", "Removed a total of 0 cells.\n", "\n", "6.3. Executing OPT_MUXTREE pass (detect dead branches in mux trees).\n", "Running muxtree optimizer on module \\r1w1..\n", " Creating internal representation of mux trees.\n", " No muxes found in this module.\n", "Removed 0 multiplexer ports.\n", "\n", "6.4. Executing OPT_REDUCE pass (consolidate $*mux and $reduce_* inputs).\n", " Optimizing cells in module \\r1w1.\n", "Performed a total of 0 changes.\n", "\n", "6.5. Executing OPT_MERGE pass (detect identical cells).\n", "Finding identical cells in module `\\r1w1'.\n", "Removed a total of 0 cells.\n", "\n", "6.6. Executing OPT_DFF pass (perform DFF optimizations).\n", "\n", "6.7. Executing OPT_CLEAN pass (remove unused cells and wires).\n", "Finding unused cells or wires in module \\r1w1..\n", "\n", "6.8. Executing OPT_EXPR pass (perform const folding).\n", "Optimizing module r1w1.\n", "\n", "6.9. Finished OPT passes. (There is nothing left to do.)\n" ] } ], "source": [ "d = convert(DATA_WIDTH, 7)" ] }, { "cell_type": "markdown", "id": "e29d7ee2-7003-4352-baa9-47245ac428e4", "metadata": {}, "source": [ "## Testing hardware generation\n", "\n", "Note: Post map simulation may require external memory models of blackbox Vendor Primitives." ] }, { "cell_type": "code", "execution_count": 9, "id": "9556f719-072e-4ef7-a633-e3029ec36b1f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "-- Running command `ls' --\n", "\n", "1 modules:\n", " r1w1\n", "\n", "-- Running command `tee -q read_verilog -lib -specify /usr/share/yosys/gatemate/cells_sim.v /usr/share/yosys/gatemate/cells_bb.v' --\n", "\n", "-- Running command `tee -q memory_libmap -lib /usr/share/yosys/gatemate/brams.txt' --\n", "\n", "-- Running command `tee -q techmap -map /usr/share/yosys/gatemate/brams_map.v' --\n", "\n", "-- Running command `tee -q opt' --\n", "\n", "-- Running command `stat' --\n", "\n", "12. Printing statistics.\n", "\n", "=== r1w1 ===\n", "\n", " Number of wires: 12\n", " Number of wire bits: 187\n", " Number of public wires: 6\n", " Number of public wire bits: 80\n", " Number of memories: 0\n", " Number of memory bits: 0\n", " Number of processes: 0\n", " Number of cells: 6\n", " $and 1\n", " $dff 2\n", " $eq 1\n", " $mux 1\n", " CC_BRAM_20K 1\n", "\n", "\n", "-- Running command `tee -q write_rtlil mapped.il' --\n", "\n", "-- Running command `show -format dot -prefix memtest32 *' --\n", "\n", "14. Generating Graphviz representation of design.\n", "Writing dot description to `memtest32.dot'.\n", "Dumping module r1w1 to page 1.\n" ] } ], "source": [ "TECHMAP = '/usr/share/yosys'\n", "\n", "def synth_ecp5(d, libmap = True):\n", " # Read blackbox cells for awareness of DP16KD:\n", " d.run(\"read_verilog -lib -specify %s/ecp5/cells_sim.v %s/ecp5/cells_bb.v\" % (TECHMAP, TECHMAP))\n", "\n", " if libmap: # New libmap procedure\n", " d.run(\"memory_libmap -lib %s/ecp5/brams.txt\" % TECHMAP) \n", " else:\n", " # First try DP16KD mapping:\n", " d.run(\"memory_bram -rules %s/ecp5/brams.txt\" % TECHMAP)\n", " \n", " d.run(\"techmap -map %s/ecp5/brams_map.v\" % TECHMAP)\n", "\n", " # Remaining (addr_w <= 8 bit) to LUT RAM:\n", " if libmap:\n", " d.run(\"memory_libmap -lib %s/ecp5/lutrams.txt\" % TECHMAP)\n", " else:\n", " d.run(\"memory_bram -rules %s/ecp5/lutrams.txt\" % TECHMAP)\n", " \n", " d.run(\"techmap -map %s/ecp5/lutrams_map.v\" % TECHMAP)\n", " d.run(\"opt_clean\")\n", " \n", "def synth_gatemate(d, libmap = True):\n", " d.run(\"read_verilog -lib -specify %s/gatemate/cells_sim.v %s/gatemate/cells_bb.v\" % (TECHMAP, TECHMAP))\n", "\n", " if libmap: # New libmap procedure\n", " d.run(\"memory_libmap -lib %s/gatemate/brams.txt\" % TECHMAP) \n", " else:\n", " d.run(\"memory_bram -rules %s/gatemate/brams.txt\" % TECHMAP)\n", " d.run(\"techmap -map %s/gatemate/brams_map.v\" % TECHMAP)\n", "\n", " d.run(\"opt\")\n", " \n", "d.run(\"ls\", capture = None)\n", "\n", "synth_gatemate(d)\n", "d.run(\"stat\", capture = None)\n", "\n", "d.run(\"write_rtlil mapped.il\")\n", "\n", "d.display_rtl(selection = '*', fmt = 'dot')" ] }, { "cell_type": "code", "execution_count": 10, "id": "39da7529-9cbe-4085-87f1-4811bcb1dcfb", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n", " \n", " \n", " \n", " \n", "\n", "r1w1\n", "\n", "r1w1\n", "\n", "\n", "n7\n", "\n", "addr_r\n", "\n", "\n", "\n", "c20\n", "\n", "A\n", "\n", "B\n", "\n", "$52\n", "$eq\n", "\n", "Y\n", "\n", "\n", "\n", "n7:e->c20:w\n", "\n", "\n", "\n", "\n", "\n", "x5\n", "\n", "0 -> 15:14\n", "\n", "6:0 - 13:7\n", "\n", "0 -> 6:0\n", "\n", "\n", "\n", "n7:e->x5:w\n", "\n", "\n", "\n", "\n", "\n", "n8\n", "\n", "addr_w\n", "\n", "\n", "\n", "n8:e->c20:w\n", "\n", "\n", "\n", "\n", "\n", "x0\n", "\n", "0 -> 15:14\n", "\n", "6:0 - 13:7\n", "\n", "0 -> 6:0\n", "\n", "\n", "\n", "n8:e->x0:w\n", "\n", "\n", "\n", "\n", "\n", "n9\n", "\n", "clk\n", "\n", "\n", "\n", "c16\n", "\n", "CLK\n", "\n", "D\n", "\n", "$51\n", "$dff\n", "\n", "Q\n", "\n", "\n", "\n", "n9:e->c16:w\n", "\n", "\n", "\n", "\n", "\n", "c22\n", "\n", "CLK\n", "\n", "D\n", "\n", "$58\n", "$dff\n", "\n", "Q\n", "\n", "\n", "\n", "n9:e->c22:w\n", "\n", "\n", "\n", "\n", "\n", "c39\n", "\n", "A_ADDR\n", "\n", "A_BM\n", "\n", "A_CLK\n", "\n", "A_DI\n", "\n", "A_EN\n", "\n", "A_WE\n", "\n", "B_ADDR\n", "\n", "B_BM\n", "\n", "B_CLK\n", "\n", "B_DI\n", "\n", "B_EN\n", "\n", "B_WE\n", "\n", "$mem_ram_sig.0.0\n", "CC_BRAM_20K\n", "\n", "A_DO\n", "\n", "B_DO\n", "\n", "\n", "\n", "n9:e->c39:w\n", "\n", "\n", "\n", "\n", "\n", "n9:e->c39:w\n", "\n", "\n", "\n", "\n", "\n", "n10\n", "\n", "din\n", "\n", "\n", "\n", "n10:e->c16:w\n", "\n", "\n", "\n", "\n", "\n", "x2\n", "\n", "19:0 - 19:0\n", "\n", "\n", "\n", "n10:e->x2:w\n", "\n", "\n", "\n", "\n", "\n", "x7\n", "\n", "X -> 19:12\n", "\n", "31:20 - 11:0\n", "\n", "\n", "\n", "n10:e->x7:w\n", "\n", "\n", "\n", "\n", "\n", "n11\n", "\n", "dout\n", "\n", "\n", "\n", "n12\n", "\n", "we\n", "\n", "\n", "\n", "c21\n", "\n", "A\n", "\n", "B\n", "\n", "$55\n", "$and\n", "\n", "Y\n", "\n", "\n", "\n", "n12:e->c21:w\n", "\n", "\n", "\n", "\n", "\n", "n12:e->c39:w\n", "\n", "\n", "\n", "\n", "\n", "x1\n", "\n", "20x 0:0 - 19:0\n", "\n", "\n", "\n", "n12:e->x1:w\n", "\n", "\n", "\n", "\n", "\n", "x6\n", "\n", "0 -> 19:12\n", "\n", "12x 0:0 - 11:0\n", "\n", "\n", "\n", "n12:e->x6:w\n", "\n", "\n", "\n", "\n", "\n", "c24\n", "\n", "A\n", "\n", "B\n", "\n", "S\n", "\n", "$59\n", "$mux\n", "\n", "Y\n", "\n", "\n", "\n", "c16:e->c24:w\n", "\n", "\n", "\n", "\n", "\n", "c20:e->c21:w\n", "\n", "\n", "\n", "\n", "\n", "c21:e->c22:w\n", "\n", "\n", "\n", "\n", "\n", "c22:e->c24:w\n", "\n", "\n", "\n", "\n", "\n", "c24:e->n11:w\n", "\n", "\n", "\n", "\n", "\n", "v4\n", "\n", "1'1\n", "\n", "\n", "\n", "v4:e->c39:w\n", "\n", "\n", "\n", "\n", "\n", "v9\n", "\n", "1'1\n", "\n", "\n", "\n", "v9:e->c39:w\n", "\n", "\n", "\n", "\n", "\n", "v10\n", "\n", "1'0\n", "\n", "\n", "\n", "v10:e->c39:w\n", "\n", "\n", "\n", "\n", "\n", "x3\n", "\n", "19:0 - 19:0\n", "\n", "\n", "\n", "c39:e->x3:w\n", "\n", "\n", "\n", "\n", "\n", "\n", "x8\n", "\n", "19:12 - 39:32\n", "\n", "11:0 - 31:20\n", "\n", "\n", "\n", "c39:e->x8:w\n", "\n", "\n", "\n", "\n", "\n", "\n", "x0:e->c39:w\n", "\n", "\n", "\n", "\n", "\n", "\n", "x1:e->c39:w\n", "\n", "\n", "\n", "\n", "\n", "\n", "x2:e->c39:w\n", "\n", "\n", "\n", "\n", "\n", "\n", "n2\n", "\n", "\n", "\n", "\n", "x3:e->n2:w\n", "\n", "\n", "\n", "\n", "\n", "x5:e->c39:w\n", "\n", "\n", "\n", "\n", "\n", "\n", "x6:e->c39:w\n", "\n", "\n", "\n", "\n", "\n", "\n", "x7:e->c39:w\n", "\n", "\n", "\n", "\n", "\n", "\n", "x8:e->n2:w\n", "\n", "\n", "\n", "\n", "\n", "n4\n", "\n", "$60\n", "\n", "\n", "\n", "x8:e->n4:w\n", "\n", "\n", "\n", "\n", "\n", "x11\n", "\n", "31:0 - 31:0\n", "\n", "\n", "\n", "x11:e->n4:w\n", "\n", "\n", "\n", "\n", "\n", "n2:e->c24:w\n", "\n", "\n", "\n", "\n", "\n", "n2:e->x11:w\n", "\n", "\n", "\n", "\n", "\n", "\\n\n", "\n", "\n", "\n", "\n", "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from yosys import display\n", "display.display_dot(\"memtest%d\" % DATA_WIDTH)" ] }, { "cell_type": "code", "execution_count": 11, "id": "424093b1-9c91-49b2-b525-33a0939dc641", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "-- Running command `ls; check' --\n", "\n", "15. Executing CHECK pass (checking for obvious problems).\n", "Found and reported 0 problems.\n", "\n", "-- Running command `hierarchy -check' --\n", "\n", "16. Executing HIERARCHY pass (managing design hierarchy).\n", "\n", "-- Running command `write_verilog test1_mapped.v' --\n", "\n", "17. Executing Verilog backend.\n", "\n", "17.1. Executing BMUXMAP pass.\n", "\n", "17.2. Executing DEMUXMAP pass.\n" ] } ], "source": [ "d.write_verilog(\"test1\")" ] }, { "cell_type": "markdown", "id": "5cf85270-c521-4460-b6ae-14dbc92f564a", "metadata": {}, "source": [ "Define a few custom targets:" ] }, { "cell_type": "code", "execution_count": 12, "id": "bcf8521e-7c7e-43a3-98bf-7b628e8e7f60", "metadata": {}, "outputs": [], "source": [ "class CustomTarget(pyosys.RTLIL):\n", " def __init__(self, *args):\n", " super().__init__(*args)\n", " print(\"Selecting %s\" % self.name)\n", " self.debug = True\n", " \n", " def finalize(self, top, objs = None):\n", " print(\"FINALIZE\")\n", " tname = top.name\n", " design = self._design\n", " design.run(\"hierarchy -top %s\" % tname)\n", " self.synth(design)\n", " design.run('stat', capture = None)\n", " # self.write_cxxrtl(top)\n", " return [ design ]\n", "\n", "class GateMateTarget(CustomTarget):\n", " name = \"GateMate\"\n", " \n", " def synth(self, design):\n", " return synth_gatemate(design)\n", "\n", "class ECP5Target(CustomTarget):\n", " name = \"LatticeECP5\"\n", " \n", " def synth(self, design):\n", " design.run(\"read_verilog ../library/tech/lattice/ecp5u/DP16KD.v\")\n", " return synth_ecp5(design) " ] }, { "cell_type": "markdown", "id": "ab796c97-2e63-4f39-9c92-3b976c8dc996", "metadata": {}, "source": [ "Then run post-map simulation on one of them.\n", "\n", "**Note**: For the ECP5 target, you need a *synthesizeable* variant of the `DP16KD.v` entity, or co-simulate using iverilog (currently not integrated into the pyrite simulator API). Let's try the GateMateTarget for now (which includes primitive whitebox models)." ] }, { "cell_type": "code", "execution_count": 13, "id": "291334d1-3f61-4e99-a7c9-70eedd754d1a", "metadata": {}, "outputs": [], "source": [ "import simulation\n", "from yosys.simulator import CXXRTL\n", "\n", "@simulation.sim.testbench(CXXRTL, time_unit = 'ns', target_class = GateMateTarget)\n", "def tb_memtest(MODE = 0, STYLE = 1, data_w=16, addr_w=7, mem = r1w1):\n", " \n", " ClkSignal = simulation.ClkSignal\n", " Signal = simulation.Signal\n", "\n", " c = ClkSignal(name = 'clk')\n", " c.init = True\n", " \n", " M = (1 << (data_w - 1))\n", "\n", " wren = Signal(bool(), name = 'we')\n", " ra, wa = [ Signal(intbv()[addr_w:]) for n in ['addr_write', 'addr_read'] ]\n", " a, q = [ Signal(intbv()[data_w:]) for n in ['a', 'q'] ]\n", "\n", " ram_sig = SigArray([intbv(M | v)[data_w:] for v in range(2 ** addr_w)],\n", " name='ram_sig', init=True)\n", "\n", " # print(ram_sig[0].size())\n", "\n", " inst = mem(clk=c,\n", " we=wren,\n", " addr_r=ra, addr_w=wa, din=a, dout=q, MODE=False, ram = ram_sig,\n", " AWIDTH=addr_w, DWIDTH=data_w,\n", " TRANSPARENCY = True)\n", "\n", " @simulation.always(simulation.delay(2))\n", " def clkgen():\n", " c.next = ~c\n", "\n", " def write(addr, data):\n", " print(\"WRITE\", addr, data)\n", " yield c.negedge\n", " wa.next = addr\n", " a.next = data\n", " wren.next = True\n", " yield c.negedge\n", " wren.next = False\n", "\n", " def write_verify(addr, data, value):\n", " print(\"WRITE VERIFY\", addr)\n", " yield c.negedge\n", " wa.next = addr\n", " a.next = data\n", " wren.next = True\n", " yield c.negedge\n", " # print(\"DEBUG Q\", bin(int(q)))\n", " assert int(q) == value\n", " wren.next = False\n", "\n", " @simulation.sequence\n", " def stim():\n", " ra.next = 0x20\n", " wa.next = 0x00\n", "\n", " # Write and verify that we're not bypassing:\n", " # i.e. the value is expected to be the initial one\n", " yield from write_verify(0x00, 0xaa, M | 0x20)\n", " ra.next = 0x00\n", " yield c.negedge\n", " # Now make sure we're getting the written value\n", " assert int(q) == 0xaa\n", "\n", " # ra == wa, verify transparency bypass:\n", " ra.next = 0x40\n", " yield from write_verify(0x40, 0x55, 0x55)\n", " yield c.negedge\n", " ra.next = 0x00\n", " yield c.negedge\n", " assert int(q) == 0xaa\n", " ra.next = 0x40\n", " yield c.negedge\n", " assert int(q) == 0x55\n", " ra.next = 0x1a\n", " yield c.negedge\n", " assert int(q) == M | 0x1a # Initial\n", "\n", " print(\"SIM DONE\")\n", "\n", " return simulation.instances()\n" ] }, { "cell_type": "code", "execution_count": 14, "id": "07794cf3-cc46-4ac4-8345-02ed2d26adc4", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['r1w1_s1_s1_s7_s7_s32_s32_s128_0_32_7_1']" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "r1w1.ctx.components" ] }, { "cell_type": "code", "execution_count": 15, "id": "9e5a271d-e9ba-4398-a4ce-55f1d33c3cf4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "FALLBACK: UNHANDLED ROOT CLASS , create new context\n", "\u001b[32m Module r1w1: Existing instance r1w1, rename to r1w1_1 \u001b[0m\n", "CALLED MEMORY INSTANCE 10\n", "DEBUG: Skip non-simulation type \n", "DEBUG: Skip non-simulation type \n", "DEBUG: Skip non-simulation type \n", "DEBUG: Skip non-simulation type \n", "DEBUG: Skip non-simulation type \n", "DEBUG: Skip non-simulation type \n" ] } ], "source": [ "t = tb_memtest(data_w = 10)" ] }, { "cell_type": "code", "execution_count": 16, "id": "845b6d71-645a-46d5-a46f-c83a339cf776", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Selecting GateMate\n", "\u001b[32m Adding module with name `r1w1_1` \u001b[0m\n", " DEBUG: SKIP ARRAYTYPE `ram` : \n", " DEBUG SLICE READ MEMORY to dout AWIDTH:7 DWIDTH:10\n", "DEBUG ADD ROM 7:10\n", "\u001b[7;34m PARAM PRIORITY --> 48 \u001b[0m\n", "\u001b[7;34m PARAM WORDS --> 128 \u001b[0m\n", "\u001b[7;34m PARAM ABITS --> 7 \u001b[0m\n", "\u001b[7;34m PARAM WIDTH --> 10 \u001b[0m\n", "\u001b[7;34m PARAM MEMID --> $mem_ram_sig \u001b[0m\n", "\u001b[7;34m PARAM CLK_ENABLE --> False \u001b[0m\n", "\u001b[7;34m PARAM CLK_POLARITY --> True \u001b[0m\n", "\u001b[7;34m PARAM TRANSPARENT --> False \u001b[0m\n", "\u001b[7;34m PARAM ABITS --> 7 \u001b[0m\n", "\u001b[7;34m PARAM WIDTH --> 10 \u001b[0m\n", "\u001b[7;34m PARAM MEMID --> $mem_ram_sig \u001b[0m\n", " DEBUG SLICE WRITE MEMORY to ram_sig AWIDTH:7 DWIDTH:10\n", "\u001b[7;34m PARAM CLK_ENABLE --> True \u001b[0m\n", "\u001b[7;34m PARAM CLK_POLARITY --> True \u001b[0m\n", "\u001b[7;34m PARAM PRIORITY --> 48 \u001b[0m\n", "\u001b[7;34m PARAM ABITS --> 7 \u001b[0m\n", "\u001b[7;34m PARAM WIDTH --> 10 \u001b[0m\n", "\u001b[7;34m PARAM MEMID --> $mem_ram_sig \u001b[0m\n", "DEBUG TOP LEVEL WRITE MEM ram_sig\n", "FINALIZE\n", "Dumping module `\\r1w1'.\n", "\n", "-- Running command `tee -q hierarchy -top r1w1_1' --\n", "\n", "-- Running command `tee -q read_verilog -lib -specify /usr/share/yosys/gatemate/cells_sim.v /usr/share/yosys/gatemate/cells_bb.v' --\n", "\n", "-- Running command `tee -q memory_libmap -lib /usr/share/yosys/gatemate/brams.txt' --\n", "\n", "-- Running command `tee -q techmap -map /usr/share/yosys/gatemate/brams_map.v' --\n", "\n", "-- Running command `tee -q opt' --\n", "\n", "-- Running command `stat' --\n", "\n", "24. Printing statistics.\n", "\n", "=== r1w1_1 ===\n", "\n", " Number of wires: 10\n", " Number of wire bits: 58\n", " Number of public wires: 6\n", " Number of public wire bits: 36\n", " Number of memories: 1\n", " Number of memory bits: 1280\n", " Number of processes: 0\n", " Number of cells: 7\n", " $and 1\n", " $dff 1\n", " $eq 1\n", " $meminit 1\n", " $memrd 1\n", " $memwr 1\n", " $mux 1\n", "\n", "\n", "-- Running command `tee -q debug memory -nomap' --\n", "\n", "-- Running command `write_rtlil top.il' --\n", "\n", "26. Executing RTLIL backend.\n", "Output filename: top.il\n", "\n", "-- Running command `show -format dot -prefix r1w1_1 *' --\n", "\n", "27. Generating Graphviz representation of design.\n", "Writing dot description to `r1w1_1.dot'.\n", "Dumping module r1w1_1 to page 1.\n", "Tolerate exception: Module with name `r1w1_1` already existing\n", "Compiling /tmp/myirl_r1w1_hzoi45pn/r1w1_1_1516.pyx because it changed.\n", "[1/1] Cythonizing /tmp/myirl_r1w1_hzoi45pn/r1w1_1_1516.pyx\n", "running build_ext\n", "building 'r1w1_1_1516' extension\n", "creating build/temp.linux-x86_64-3.9/tmp/myirl_r1w1_hzoi45pn\n", "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_r1w1_hzoi45pn/ -I/usr/share/yosys/include -I/usr/include/python3.9 -c /tmp/myirl_r1w1_hzoi45pn/r1w1_1_1516.cpp -o build/temp.linux-x86_64-3.9/tmp/myirl_r1w1_hzoi45pn/r1w1_1_1516.o\n", "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_r1w1_hzoi45pn/ -I/usr/share/yosys/include -I/usr/include/python3.9 -c /tmp/myirl_r1w1_hzoi45pn/r1w1_1_1516_rtl.cpp -o build/temp.linux-x86_64-3.9/tmp/myirl_r1w1_hzoi45pn/r1w1_1_1516_rtl.o\n", "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_r1w1_hzoi45pn/r1w1_1_1516.o build/temp.linux-x86_64-3.9/tmp/myirl_r1w1_hzoi45pn/r1w1_1_1516_rtl.o -o build/lib.linux-x86_64-3.9/r1w1_1_1516.cpython-39-x86_64-linux-gnu.so\n", "copying build/lib.linux-x86_64-3.9/r1w1_1_1516.cpython-39-x86_64-linux-gnu.so -> \n", "Open for writing: tb_memtest.vcd\n", "\u001b[7;35m CXXRTL context: SKIP INTERFACE ITEM `ram` \u001b[0m\n", "\u001b[7;35m CXXRTL context: SKIP INTERFACE ITEM `MODE` \u001b[0m\n", "\u001b[7;35m CXXRTL context: SKIP INTERFACE ITEM `DWIDTH` \u001b[0m\n", "\u001b[7;35m CXXRTL context: SKIP INTERFACE ITEM `AWIDTH` \u001b[0m\n", "\u001b[7;35m CXXRTL context: SKIP INTERFACE ITEM `TRANSPARENCY` \u001b[0m\n", "WRITE VERIFY 0\n", "WRITE VERIFY 64\n", "SIM DONE\n", "DEBUG STOP PROCESS stim\n" ] } ], "source": [ "t.debug()\n", "t.run(100)\n", "# t.design.run(\"write_rtlil memtest.il\")" ] }, { "cell_type": "markdown", "id": "eab18935-198d-4913-abaf-fef452893867", "metadata": {}, "source": [ "# Duplex read, single write\n", "\n", "This test is now part of the cyrite library TDPRAM " ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.2" } }, "nbformat": 4, "nbformat_minor": 5 }