diff --git a/apycula/codegen.py b/apycula/codegen.py index 05043a8d..04f96ae5 100644 --- a/apycula/codegen.py +++ b/apycula/codegen.py @@ -37,7 +37,11 @@ def write(self, f): f.write("inout {};\n".format(port)) for wire in self.wires: - f.write("wire {};\n".format(wire)) + if isinstance(wire, tuple): + for w in wire: + f.write("wire {};\n".format(w)) + else: + f.write("wire {};\n".format(wire)) # unique assignments or not #for dest, src in self.assigns: @@ -63,7 +67,10 @@ def write(self, f): if not first: f.write(",") first = False - f.write("\n.{}({})".format(port, wire)) + if isinstance(wire, tuple): + f.write("\n.{}({{{}}})".format(port, ", ".join(wire))) + else: + f.write("\n.{}({})".format(port, wire)) f.write("\n);\n") for key, val in self.params.items(): diff --git a/apycula/tiled_fuzzer.py b/apycula/tiled_fuzzer.py index 1955353a..8393b962 100644 --- a/apycula/tiled_fuzzer.py +++ b/apycula/tiled_fuzzer.py @@ -28,8 +28,8 @@ if not gowinhome: raise Exception("GOWINHOME not set") -# device = os.getenv("DEVICE") -device = sys.argv[1] +device = os.getenv("DEVICE") +# device = sys.argv[1] params = { "GW1NS-2": { @@ -344,17 +344,23 @@ def dualmode(ttyp): # read vendor .posp log _cst_parser = re.compile(r"([^ ]+) (?:PLACE|CST)_R(\d+)C(\d+)\[([0-3])\]\[([A-Z])\]") _place_parser = re.compile(r"([^ ]+) (?:PLACE|CST)_IO([TBLR])(\d+)\[([A-Z])\]") +# inst3_SDPB_SDPB CST_BSRAM_R6[0] +_bram_parser = re.compile(r"([^ ]+) (?:PLACE|CST)_BSRAM_R(\d+)\[([0-3])\]") def read_posp(fname): with open(fname, 'r') as f: for line in f: cst = _cst_parser.match(line) place = _place_parser.match(line) + bram = _bram_parser.match(line) if cst: name, row, col, cls, lut = cst.groups() yield "cst", name, int(row), int(col), int(cls), lut elif place: name, side, num, pin = place.groups() yield "place", name, side, int(num), pin + elif bram: + name, row, idx = bram.groups() + yield "bram", name, int(row), int(idx) elif line.strip() and not line.startswith('//'): raise Exception(line) @@ -432,7 +438,7 @@ def run_pnr(mod, constr, config): pnr.write(f) subprocess.run([gowinhome + "/IDE/bin/gw_sh", tmpdir+"/run.tcl"]) - #print(tmpdir); input() + # print(tmpdir); input() try: return PnrResult( *bslib.read_bitstream(tmpdir+"/impl/pnr/top.fs"), diff --git a/bram_experiments.ipynb b/bram_experiments.ipynb new file mode 100644 index 00000000..9ba3598d --- /dev/null +++ b/bram_experiments.ipynb @@ -0,0 +1,572 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "check 19199191\n" + ] + } + ], + "source": [ + "import os\n", + "os.environ[\"GOWINHOME\"] = \"/home/pepijn/bin/gowin\"\n", + "os.environ[\"DEVICE\"] = \"GW1N-1\"\n", + "from apycula import tiled_fuzzer\n", + "from apycula import codegen\n", + "from apycula import pindef\n", + "from apycula import bslib\n", + "from apycula import chipdb\n", + "from apycula import fuse_h4x\n", + "from apycula import gowin_unpack\n", + "from apycula.wirenames import wirenames\n", + "from PIL import Image\n", + "import numpy as np\n", + "import pickle\n", + "import json\n", + "\n", + "# a semi-dual-port bram as generated by the vendor\n", + "\n", + "# SDPB memory_ins130 (\n", + "# .DI({GND,GND,GND,GND,GND,GND,GND,GND,GND,GND,GND,GND,GND,GND,GND,GND,data_in_33,data_in_31,data_in_29,data_in_27,data_in_25,data_in_23,data_in_21,data_in_19,data_in_17,data_in_15,data_in_13,data_in_11,data_in_9,data_in_7,data_in_5,data_in_3}),\n", + "# .BLKSELA({GND,GND,GND}),\n", + "# .BLKSELB({GND,GND,GND}),\n", + "# .ADA({GND,GND,wr_addr_17,wr_addr_15,wr_addr_13,wr_addr_11,wr_addr_9,wr_addr_7,wr_addr_5,wr_addr_3,GND,GND,VCC,VCC}),\n", + "# .ADB({GND,GND,rd_addr_17,rd_addr_15,rd_addr_13,rd_addr_11,rd_addr_9,rd_addr_7,rd_addr_5,rd_addr_3,GND,GND,GND,GND}),\n", + "# .CLKA(clk_3),\n", + "# .CLKB(clk_3),\n", + "# .CEA(wr_en_3),\n", + "# .CEB(rd_en_3),\n", + "# .OCE(GND),\n", + "# .RESETA(GND),\n", + "# .RESETB(GND),\n", + "# .DO({memory_6_DO31,memory_6_DO30,memory_6_DO29,memory_6_DO28,memory_6_DO27,memory_6_DO26,memory_6_DO25,memory_6_DO24,memory_6_DO23,memory_6_DO22,memory_6_DO21,memory_6_DO20,memory_6_DO19,memory_6_DO18,memory_6_DO17,memory_6_DO16,\\data_out[15]_8 ,\\data_out[14]_8 ,\\data_out[13]_8 ,\\data_out[12]_8 ,\\data_out[11]_8 ,\\data_out[10]_8 ,\\data_out[9]_8 ,\\data_out[8]_8 ,\\data_out[7]_8 ,\\data_out[6]_8 ,\\data_out[5]_8 ,\\data_out[4]_8 ,\\data_out[3]_8 ,\\data_out[2]_8 ,\\data_out[1]_8 ,\\data_out[0]_9 }) \n", + "# );\n", + "# defparam memory_ins130.BIT_WIDTH_0=16;\n", + "# defparam memory_ins130.BIT_WIDTH_1=16;\n", + "# defparam memory_ins130.READ_MODE=1'b0;\n", + "# defparam memory_ins130.RESET_MODE=\"SYNC\";\n", + "\n", + "def bram(mod, cst, row, idx, readmode=False, bits0=4, bits1=4, reset=True):\n", + " \"make a bram\"\n", + " name = tiled_fuzzer.make_name(\"SDPB\", \"SDPB\")\n", + " bram = codegen.Primitive(\"SDPB\", name)\n", + " bram.portmap['DI'] = tuple(f\"{name}_DI{i}\" for i in range(32))\n", + " bram.portmap['BLKSELA'] = tuple(f\"{name}_BLKSELA{i}\" for i in range(3))\n", + " bram.portmap['BLKSELB'] = tuple(f\"{name}_BLKSELB{i}\" for i in range(3))\n", + " bram.portmap['ADA'] = tuple(f\"{name}_ADA{i}\" for i in range(14))\n", + " bram.portmap['ADB'] = tuple(f\"{name}_ADB{i}\" for i in range(14))\n", + " bram.portmap['DO'] = tuple(f\"{name}_DO{i}\" for i in range(32))\n", + " bram.portmap['CLKA'] = name+\"_CLKA\"\n", + " bram.portmap['CLKB'] = name+\"_CLKB\"\n", + " bram.portmap['CEA'] = name+\"_CEA\"\n", + " bram.portmap['CEB'] = name+\"_CEB\"\n", + " bram.portmap['OCE'] = name+\"_OCE\"\n", + " bram.portmap['RESETA'] = name+\"_RESETA\"\n", + " bram.portmap['RESETB'] = name+\"_RESETB\"\n", + " bram.params[\"READ_MODE\"] = \"1'b0\" if readmode else \"1'b1\"\n", + " bram.params[\"BIT_WIDTH_0\"] = str(2**bits0)\n", + " bram.params[\"BIT_WIDTH_1\"] = str(2**bits1)\n", + " bram.params[\"RESET_MODE\"] = \"\\\"SYNC\\\"\" if reset else \"\\\"ASYNC\\\"\"\n", + " mod.wires.update(bram.portmap.values())\n", + " mod.primitives[name] = bram\n", + " cst.cells[name] = f\"BSRAM_R{row}[{idx}]\"\n", + " return bram.portmap\n", + "\n", + "with open(f\"{tiled_fuzzer.gowinhome}/IDE/share/device/{tiled_fuzzer.device}/{tiled_fuzzer.device}.fse\", 'rb') as f:\n", + " fse = fuse_h4x.readFse(f)\n", + " \n", + "with open(f\"apycula/{tiled_fuzzer.device}.pickle\", 'rb') as f:\n", + " db = pickle.load(f)\n", + "\n", + "with open(f\"{tiled_fuzzer.device}.json\") as f:\n", + " dat = json.load(f)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABMAAAAISAQAAAAACF44lAAABaklEQVR4nO3csU3DUBAA0IRAiIQEKUBKR8MAGYAiI2QEKOkYISvQMQYjpGQcSkqK2MiWncLWd3yx32u+czmdTv5nd/6TCUPx8XT93XcP52SZstg0ZbGLlMUYCjNG18wYXUs6Y6MQ9qkM21hYYe9YvKdycVjiNRZd2AfJVgIAAAAAAAAAAAAAAAAAwDlZ10ZnJ69c+YR6WZuW4oPmZpUrjW1q0y5bNnOayn05stvrfioXtvKqPmPbrpmi7ir3a1Ef3kWuDABk7rP1oRSdbrJ1W4w+H5bZex64+8mvbvellKaVJ9Wcm+zH267039dhmX8Wg6ussd88MH/Jrx73xZRS5df6yqvjjQEAAAAAAAAAAAAAAAAAMBgpjqr5VzmFBswY3TNjdC3pjI3CSO7YkbPB2gj76gn7go03Y9k4xGssunEMPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANPUHvqkQLHoZe2sAAAAASUVORK5CYII=", + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# pipe cleaning, can we generate a BRAM without the vendor tools yelling at us?\n", + "mod = codegen.Module()\n", + "cst = codegen.Constraints()\n", + "\n", + "# brams = [bram(mod, cst, row, col) for row, col in [(6, 1), (6, 2), (6, 0), (6, 3)]]\n", + "\n", + "bram(mod, cst, 6, 0, readmode=False, reset=False)\n", + "bram(mod, cst, 6, 1, readmode=True, reset=False)\n", + "bram(mod, cst, 6, 2, readmode=False, reset=True)\n", + "bram(mod, cst, 6, 3, readmode=True, reset=True)\n", + "# import io\n", + "# f = io.StringIO()\n", + "# mod.write(f)\n", + "# print(f.getvalue())\n", + "\n", + "res = tiled_fuzzer.run_pnr(mod, cst, {})\n", + "bslib.display(None, res.bitmap)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "18\n", + "['0:CLK0', '0:CE0', '0:CE1', '0:LSR0', '0:LSR1', '1:CLK0', '1:CE0', '1:CE1', '1:LSR0', '1:LSR1', '0:CLK0', '0:CE0', '0:CE1', '0:LSR0', '0:LSR1', '0:CE2', '0:LSR2', '2:CE0']\n", + "['0:CLK0', '1:CLK0', '0:CLK0', '0:CE2'] ['0:CE0', '1:CE0', '0:CE0', '0:LSR2'] ['0:CE1', '1:CE1', '0:CE1', '2:CE0'] ['0:LSR0', '1:LSR0', '0:LSR0'] ['0:LSR1', '1:LSR1', '0:LSR1']\n", + "['0:CLK0', '0:CE0', '0:CE1', '0:LSR0', '0:LSR1']\n", + "['0:CE2', '0:LSR2', '2:CE0']\n", + "114 104 10\n", + "['1:C4', '1:C5', '1:C6', '1:C7', '1:C0', '1:C1', '0:C0', '0:C1', '0:C2', '0:C3', '0:C4', '0:C5', '1:C2', '1:C3', '1:C4', '1:C5', '1:C6', '1:C7', '1:C0', '1:C1', '0:C0', '0:C1', '0:C2', '0:C3', '0:C4', '0:C5', '1:C2', '1:C3', '0:D0', '0:D1', '0:D2', '0:D3', '0:D4', '0:D5', '0:D6', '0:D7', '0:B6', '0:B7', '1:B0', '1:D0', '1:B1', '1:D1', '1:B2', '1:D2', '1:B3', '1:D3', '0:D0', '0:D1', '0:D2', '0:D3', '0:D4', '0:D5', '0:D6', '0:D7', '0:B6', '0:B7', '1:B0', '1:D0', '1:B1', '1:D1', '1:B2', '1:D2', '1:B3', '1:D3', '1:B4', '1:D4', '1:B5', '1:D5', '1:B6', '1:D6', '1:B7', '1:D7', '2:B0', '2:B1', '2:B2', '2:B3', '2:B4', '2:B5', '2:B6', '2:B7', '2:D6', '2:D7', '2:A0', '2:A1', '2:A2', '2:A3', '1:A0', '1:A1', '0:A0', '0:A1', '0:A2', '0:A3', '0:A4', '0:A5', '1:A2', '1:A3', '1:B4', '1:D4', '1:B5', '1:D5', '1:B6', '1:D6', '1:B7', '1:D7', '2:B0', '2:B1', '2:B2', '2:B3', '2:B4', '2:B5', '2:B6', '2:B7', '2:D6', '2:D7']\n", + "50\n" + ] + } + ], + "source": [ + "# these are the dat file entries related to Bsram.\n", + "# in the case of IOB these were a trivial portmap.\n", + "inputs = [wirenames[n] for n in dat[\"BsramIn\"]]\n", + "outputs = [wirenames[n] for n in dat[\"BsramOut\"]]\n", + "inputsdlt = dat[\"BsramInDlt\"]\n", + "outputsdlt = dat[\"BsramOutDlt\"]\n", + "\n", + "inputs = [f\"{w}:{t}\" for t, w in zip(inputs, inputsdlt)]\n", + "outputs = [f\"{w}:{t}\" for t, w in zip(outputs, outputsdlt)]\n", + "# these appear to be control signals of some sort. Weird that they repeat.\n", + "ctl = inputs[:18]\n", + "# Maybe which of the 3 tiles the wire is in\n", + "# Every BRAM seems to take up 3 tiles, so the numbers make sense\n", + "print(len(ctl))\n", + "print(ctl)\n", + "# these seems to kinda line up\n", + "# But still two CLK0 in tile 0, which doesn't make a lot of sense\n", + "print(ctl[0::5], ctl[1::5], ctl[2::5], ctl[3::5], ctl[4::5])\n", + "print(ctl[:5]) # this seems to repeat 3 times\n", + "print(ctl[-3:]) # these 3 are special\n", + "# It'd make sense if\n", + "# CLKA/CLKB => CLK0\n", + "# RESETA/RESETB => LSR0/LSR1\n", + "# CEA/CEB/OCE => CE0/CE1\n", + "# BLKSELA/BLKSELB??? (3 bits each)\n", + "\n", + "# these appear to be the \"normal\" inputs, I'm guessing the address and data lines\n", + "# .DI .ADA .ADB .DO\n", + "# .D[I0] = 32 bits\n", + "# .AD[AB] = 14 bits\n", + "# not sure how this makes sense\n", + "no = 2*32+2*14+4*3 # inputs\n", + "addr = inputs[18:]\n", + "l = len(addr)\n", + "# how many inputs are there? Does this make sense with the inputs we know about?\n", + "print(l, no, l - no)\n", + "# Hmmm the numbers don't really seem to add up\n", + "print(addr)\n", + "# hmmm how many duplicates are there?\n", + "print(len(addr)-len(set(addr)))\n", + "# well that's also not a logical number\n", + "# I'm guessing some random ports just need to be connected to all 3 tiles?\n", + "# Maybe I'll just need to fuzz which wire seems to go where.\n", + "# Hook up one wire, unpack and inspect the routing muxes, see what matches what.\n", + "# ECP5 is fairly similar as usual: http://yosyshq.net/prjtrellis-db/ECP5/tilehtml/MIB_EBR0.html" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "72\n", + "['0:F0', '0:F1', '0:F2', '0:F3', '0:F4', '0:F5', '1:F0', '1:F1', '1:F2', '1:F3', '1:F4', '1:F5', '2:F0', '2:F1', '2:F2', '2:F3', '2:F4', '2:F5', '0:Q0', '0:Q1', '0:Q2', '0:Q3', '0:Q4', '0:Q5', '1:Q0', '1:Q1', '1:Q2', '1:Q3', '1:Q4', '1:Q5', '2:Q0', '2:Q1', '2:Q2', '2:Q3', '2:Q4', '2:Q5', '0:F0', '0:F1', '0:F2', '0:F3', '0:F4', '0:F5', '1:F0', '1:F1', '1:F2', '1:F3', '1:F4', '1:F5', '2:F0', '2:F1', '2:F2', '2:F3', '2:F4', '2:F5', '0:Q0', '0:Q1', '0:Q2', '0:Q3', '0:Q4', '0:Q5', '1:Q0', '1:Q1', '1:Q2', '1:Q3', '1:Q4', '1:Q5', '2:Q0', '2:Q1', '2:Q2', '2:Q3', '2:Q4', '2:Q5']\n" + ] + } + ], + "source": [ + "print(len(outputs))\n", + "print(outputs)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[(0, 0, 38), (0, 3, 24), (0, 6, 10), (1, 2, 18), (1, 5, 4), (2, 1, 12), (3, 0, 6)]\n" + ] + } + ], + "source": [ + "from itertools import product\n", + "\n", + "def coinsproblem(bounds, target):\n", + " rv = []\n", + " for x in product(*(range(target + 1) for y in bounds)):\n", + " subtotal = sum([ai * bi for ai, bi in zip(x, bounds)])\n", + " if subtotal == target:\n", + " rv.append(x)\n", + " rv.sort()\n", + " return rv\n", + "\n", + "# it seems there is no reasonable combination of address, data, and blksel that adds up to 114\n", + "print(coinsproblem([32, 14, 3], 114))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5 1 39\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPAAAABoAQAAAADnG0ARAAAARUlEQVR4nGNgGAWjYBQMf/AfmyATfj2UScPBBxoYTqzdAwk+YBUd/v4eBaNgFIyCUUAzwM/PwMBAl7oEahMy+PCf5nYDAKOaBSmwq0P5AAAAAElFTkSuQmCC", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5 2 40\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPAAAABoAQAAAADnG0ARAAAAQUlEQVR4nO3WwQ0AIAhD0eoC7L8lTqATiDGGcPC/a0N7RcJfZhT2+PYtliWWn7a9cBsAAOBC2yYmjaK/xdzNc7cXBd4GDIu6qXcAAAAASUVORK5CYII=", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5 4 39\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPAAAABoAQAAAADnG0ARAAAAQUlEQVR4nGNgGAWjYBQMf/AfmyATfj2UScPBBxoYTqzdAwk+YBUd/v4eBaNgFIyCUUAzwM/PwMAwUHXJh/80txsAldUFC4vC8Y8AAAAASUVORK5CYII=", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5 5 40\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPAAAABoAQAAAADnG0ARAAAAQUlEQVR4nO3WwQ0AIAhD0eoC7L8lTqATiDGGcPC/a0N7RcJfZhT2+PYtliWWn7a9cBsAAOBC2yYmjaK/xdzNc7cXBd4GDIu6qXcAAAAASUVORK5CYII=", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5 13 39\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPAAAABoAQAAAADnG0ARAAAARUlEQVR4nGNgGAWjYBQMf/AfmyATfj2UScPBBxoYTqzdAwk+YBUd/v4eBaNgFIyCUUAzwM/PwMBAl7oEahMy+PCf5nYDAKOaBSmwq0P5AAAAAElFTkSuQmCC", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5 14 40\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPAAAABoAQAAAADnG0ARAAAAQUlEQVR4nO3WwQ0AIAhD0eoC7L8lTqATiDGGcPC/a0N7RcJfZhT2+PYtliWWn7a9cBsAAOBC2yYmjaK/xVzmudsLqt8FHNnogpwAAAAASUVORK5CYII=", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5 16 39\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPAAAABoAQAAAADnG0ARAAAAQUlEQVR4nGNgGAWjYBQMf/AfmyATfj2UScPBBxoYTqzdAwk+YBUd/v4eBaNgFIyCUUAzwM/PwMAwUHXJh/80txsAldUFC4vC8Y8AAAAASUVORK5CYII=", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5 17 40\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPAAAABoAQAAAADnG0ARAAAAQUlEQVR4nO3WwQ0AIAhD0eoC7L8lTqATiDGGcPC/a0N7RcJfZhT2+PYtliWWn7a9cBsAAOBC2yYmjaK/xVzmudsLqt8FHNnogpwAAAAASUVORK5CYII=", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "tiles = fuse_h4x.tile_bitmap(fse, res.bitmap)\n", + "tiles.keys()\n", + "\n", + "for (row, col, ttyp), tile in tiles.items():\n", + " im = bslib.display(None, tile)\n", + " im_scaled = im.resize((im.width*4, im.height*4), Image.NEAREST)\n", + " if row == 5 and ttyp < 50:\n", + " print(row, col, ttyp)\n", + " display(im_scaled)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(5, 1)\n", + "{'E210': 'VSS'}\n", + "(5, 2)\n", + "{'LSR1': 'E211'}\n" + ] + }, + { + "data": { + "text/plain": [ + "{'VCC': set(),\n", + " 'LB31': {(4, 3), (6, 0)},\n", + " 'W212': {(4, 3), (6, 1)},\n", + " 'N272': {(4, 3), (6, 2)},\n", + " 'X05': {(4, 2), (6, 4)},\n", + " 'X06': {(4, 2), (4, 3), (6, 0), (6, 4)},\n", + " 'X07': {(4, 2), (4, 3), (6, 1), (6, 4)},\n", + " 'X08': {(4, 2), (4, 3), (6, 2), (6, 4)},\n", + " 'N271': {(4, 2), (4, 3), (6, 1), (7, 0)},\n", + " 'S271': {(4, 2), (4, 3), (5, 1), (6, 2)},\n", + " 'E211': {(4, 2), (4, 3), (5, 1), (6, 0)},\n", + " 'E271': {(4, 2), (4, 3), (5, 1), (6, 1)},\n", + " 'W211': {(4, 2), (4, 3), (6, 0), (7, 0)},\n", + " 'S272': {(4, 2), (4, 3), (6, 2), (7, 2)},\n", + " 'E212': {(4, 2), (4, 3), (6, 0), (7, 2)},\n", + " 'E272': {(4, 2), (4, 3), (6, 1), (7, 2)},\n", + " 'LB01': {(4, 2), (5, 1)},\n", + " 'LB11': {(4, 2), (7, 2)},\n", + " 'LB21': {(4, 2), (7, 0)},\n", + " 'LB71': {(4, 2), (4, 3), (6, 2), (7, 0)}}" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# pretty sure these upper bits are just routing, which we can parse\n", + "# this seems just an elaborate way to set LSR1 to VSS=0?\n", + "print(gowin_unpack.parse_tile_(db, 5, 1, tiles[(5, 1, 39)], default=False)[1])\n", + "print(gowin_unpack.parse_tile_(db, 5, 2, tiles[(5, 2, 40)], default=False)[1])\n", + "# well that's because LSR1 doesn't have VSS as an input itself, so okay\n", + "db.grid[5][2].pips[\"LSR1\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPAAAABoAQAAAADnG0ARAAAAJUlEQVR4nO3LoQ0AAAjAMMID/P8tCgkG29plEQAAAKNqCXl/v9wb0QAlgVxy+gAAAABJRU5ErkJggg==", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPAAAABoAQAAAADnG0ARAAAAJElEQVR4nO3KMQ0AMAzAsGj8wRbCGPTpa79JAQAArKZ6+3LLH2j8APf3EudcAAAAAElFTkSuQmCC", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# so these two bits are responsible for read mode\n", + "t = tiles[(5, 1, 39)] ^ tiles[(5, 4, 39)]\n", + "im = bslib.display(None, t)\n", + "im_scaled = im.resize((im.width*4, im.height*4), Image.NEAREST)\n", + "display(im_scaled)\n", + "\n", + "# and this one bit is for the reset mode\n", + "t = tiles[(5, 2, 40)] ^ tiles[(5, 14, 40)]\n", + "im = bslib.display(None, t)\n", + "im_scaled = im.resize((im.width*4, im.height*4), Image.NEAREST)\n", + "display(im_scaled)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABMAAAAISAQAAAAACF44lAAABcElEQVR4nO3cP1LCQBQH4EUUqZTCwhkLGw/AASw4gkfQG3gEr+BNOAKlx7G0tCBhgiwzktmQB/m+JmGz/OZN8vKnSVLiXHw+XX/1XcMpmZUMG5UMuygZxrnQY3RNj9G1oj02CGHPyrCFhRV2j8U7K6frRbzCogt7IjmUAAAAAAAAAAAAAAAAAABwSubZ0fHRk3deoZ5lp5V4ofmw5J3CFtlply2LOU5yX/Yc7Xk/yY1DeZWf8dKumKbukvs1zQ9/RE4GACr1U9Ase+Mdbd14n9eL8Xs9cPtdr92stqY0/Sf5z7ZFSumh2v62mXaXUhot12GT++Yfqh/jn3pg8lqvPa6aU6rklElOy5RJBgAAAAAAAAAAAAAAAADgTJX4VM3GzldoQI/RPT1G14r22CAMZI/t+TZYG2EvPWEvsPF6rGqHeIVFN4zmBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAQ/0C2T0QM2DmXuUAAAAASUVORK5CYII=", + "text/plain": [ + "" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mod = codegen.Module()\n", + "cst = codegen.Constraints()\n", + "\n", + "# let's run a few bit widths to see what happens\n", + "bram(mod, cst, 6, 0, bits0=0)\n", + "bram(mod, cst, 6, 1, bits0=1)\n", + "bram(mod, cst, 6, 2, bits0=2)\n", + "bram(mod, cst, 6, 2, bits0=3)\n", + "\n", + "res = tiled_fuzzer.run_pnr(mod, cst, {})\n", + "tiles = fuse_h4x.tile_bitmap(fse, res.bitmap)\n", + "bslib.display(None, res.bitmap)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPAAAABoAQAAAADnG0ARAAAAJ0lEQVR4nO3KMREAIBDAsB7+xSLhHbAwwJCsbQEAAP/bVev83OWXBuEUAPcReOF/AAAAAElFTkSuQmCC", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "t = tiles[(5, 1, 39)] ^ tiles[(5, 13, 39)]\n", + "im = bslib.display(None, t)\n", + "im_scaled = im.resize((im.width*4, im.height*4), Image.NEAREST)\n", + "display(im_scaled)" + ] + } + ], + "metadata": { + "interpreter": { + "hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a" + }, + "kernelspec": { + "display_name": "Python 3.9.7 64-bit", + "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.7" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +}