{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Loading and Exploring Gate-Level Circuits" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example of parsing the bench data format to make simple gate-level circuits." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0000000.334 W Cuda unavailable. Falling back to pure python\n" ] } ], "source": [ "from kyupy import bench\n", "\n", "# parse a file\n", "b01 = bench.parse('tests/b01.bench')\n", "\n", "# ... or specify the circuit as string \n", "mycircuit = bench.parse('input(a,b) output(o1,o2,o3) x=buf(a) o1=not(x) o2=buf(x) o3=buf(x)')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Circuits are objects of the class `Circuit`." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b01" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mycircuit" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Circuits are containers for two types of elements: nodes and lines.\n", "* A `Node` is a named entity in a circuit (e.g. a gate, a standard cell, a named signal, or a fan-out point) that has connections to other nodes.\n", "* A `Line` is a directional 1:1 connection between two Nodes.\n", "\n", "Use the `dump()` method to get a string representation of all nodes and their connections." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "None(0,1,2,3,4)\n", "0:__fork__\"a\" >1\n", "1:__fork__\"b\" \n", "2:__fork__\"o1\" <2 \n", "3:__fork__\"o2\" <4 \n", "4:__fork__\"o3\" <6 \n", "5:buf\"x\" <1 >0\n", "6:__fork__\"x\" <0 >3 >5 >7\n", "7:not\"o1\" <3 >2\n", "8:buf\"o2\" <5 >4\n", "9:buf\"o3\" <7 >6\n" ] } ], "source": [ "print(mycircuit.dump())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The first line of the dump starts with the circuit name (\"None\" for `mycircuit`), followed by the node-IDs of all the ports (inputs and outputs) of the circuit.\n", "\n", "Each of the following lines describes one node.\n", "Each node in the circuit has a unique ID, a type, a name, and line-connections. This information is given on each line in that order.\n", "\n", "A line in the circuit has a unique ID, a driver node and a receiver node. The connections in the dump show the direction (\">\" for output, \"<\" for input) and the line-ID. For example in `mycircuit`: Node-0 has one output connected to Line-1, and this Line-1 is connected to the input of Node-5.\n", "\n", "The `interface` is the list of nodes forming the ports (inputs and outputs):" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0:__fork__\"a\" >1,\n", " 1:__fork__\"b\" ,\n", " 2:__fork__\"o1\" <2 ,\n", " 3:__fork__\"o2\" <4 ,\n", " 4:__fork__\"o3\" <6 ]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mycircuit.interface" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Nodes\n", "\n", "There are two types of nodes: __forks__ and __cells__.\n", "\n", "Forks have the special type `__fork__` while cells can be of various types (`buf`, `not`, `and`, `nor`, etc.).\n", "Forks are used to label signals with names and to connect a one cell to multiple other cells (fan-out).\n", "The names among all forks and among all cells within a circuit are unique.\n", "Thus, a fork and a cell are allowed to share the same name.\n", "\n", "Nodes in circuits can be accessed by ID or by name." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "7:not\"o1\" <3 >2" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mycircuit.nodes[7]" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6:__fork__\"x\" <0 >3 >5 >7" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mycircuit.forks['x']" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5:buf\"x\" <1 >0" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mycircuit.cells['x']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nodes have an `index` (the node ID), a `kind` (the type), a `name`, as well as `ins` (input pins) and `outs` (output pins)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(6, '__fork__', 'x', [0], [3, 5, 7])" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "n = mycircuit.nodes[6]\n", "n.index, n.kind, n.name, n.ins, n.outs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The inputs and outputs of a node are lists containing `Line` objects." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "kyupy.circuit.Line" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(n.ins[0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Lines\n", "\n", "A line is a directional connection between one driving node (`driver`) and one reading node (`reader`).\n", "\n", "A line also knows to which node pins it is connected to: `driver_pin`, `reader_pin`." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(5, 6:__fork__\"x\" <0 >3 >5 >7, 8:buf\"o2\" <5 >4, 1, 0)" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l = mycircuit.nodes[6].outs[1]\n", "l.index, l.driver, l.reader, l.driver_pin, l.reader_pin" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basic Analysis Examples\n", "### Cell type statistics" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "defaultdict(, {'DFF': 5, 'AND': 1, 'NAND': 28, 'OR': 1, 'NOT': 10})\n" ] } ], "source": [ "from collections import defaultdict\n", "\n", "counts = defaultdict(int)\n", "\n", "for n in b01.cells.values():\n", " counts[n.kind] += 1\n", "\n", "print(counts)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Tracing a scan chain" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from kyupy import verilog\n", "\n", "b14 = verilog.parse('tests/b14.v.gz')\n", "b14" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "chain length 229\n", "['Scan_Out', 'u04_opt1329', 'u04_opt1328', 'wr_reg', 'u04_opt11', 'state_reg_0_0', 'reg3_reg_28_0', 'reg3_reg_27_0', 'reg3_reg_26_0', 'reg3_reg_25_0', 'reg3_reg_24_0', 'u04_opt1123', 'reg3_reg_23_0', 'reg3_reg_22_0', 'reg3_reg_21_0', 'u04_opt1118', 'reg3_reg_20_0', 'reg3_reg_19_0', 'reg3_reg_18_0', 'reg3_reg_17_0', 'reg3_reg_16_0', 'reg3_reg_15_0', 'reg3_reg_14_0', 'reg3_reg_13_0', 'reg3_reg_12_0', 'reg3_reg_11_0', 'reg3_reg_10_0', 'reg3_reg_9_0', 'reg3_reg_8_0', 'reg3_reg_7_0', 'reg3_reg_6_0', 'reg3_reg_5_0', 'reg3_reg_4_0', 'reg3_reg_3_0', 'reg3_reg_2_0', 'reg3_reg_1_0', 'reg3_reg_0_0', 'reg2_reg_31_0', 'reg2_reg_30_0', 'reg2_reg_29_0', 'reg2_reg_28_0', 'reg2_reg_27_0', 'reg2_reg_26_0', 'reg2_reg_25_0', 'reg2_reg_24_0', 'reg2_reg_23_0', 'reg2_reg_22_0', 'reg2_reg_21_0', 'reg2_reg_20_0', 'reg2_reg_19_0', 'reg2_reg_18_0', 'reg2_reg_17_0', 'reg2_reg_16_0', 'reg2_reg_15_0', 'reg2_reg_14_0', 'reg2_reg_13_0', 'reg2_reg_12_0', 'reg2_reg_11_0', 'reg2_reg_10_0', 'reg2_reg_9_0', 'reg2_reg_8_0', 'reg2_reg_7_0', 'reg2_reg_6_0', 'reg2_reg_5_0', 'reg2_reg_4_0', 'reg2_reg_3_0', 'reg2_reg_2_0', 'reg2_reg_1_0', 'reg2_reg_0_0', 'reg1_reg_31_0', 'reg1_reg_30_0', 'reg1_reg_29_0', 'reg1_reg_28_0', 'reg1_reg_27_0', 'reg1_reg_26_0', 'reg1_reg_25_0', 'reg1_reg_24_0', 'reg1_reg_23_0', 'reg1_reg_22_0', 'reg1_reg_21_0', 'reg1_reg_20_0', 'reg1_reg_19_0', 'reg1_reg_18_0', 'reg1_reg_17_0', 'reg1_reg_16_0', 'reg1_reg_15_0', 'reg1_reg_14_0', 'reg1_reg_13_0', 'reg1_reg_12_0', 'reg1_reg_11_0', 'reg1_reg_10_0', 'reg1_reg_9_0', 'reg1_reg_8_0', 'reg1_reg_7_0', 'reg1_reg_6_0', 'reg1_reg_5_0', 'reg1_reg_4_0', 'reg1_reg_3_0', 'reg1_reg_2_0', 'reg1_reg_1_0', 'reg1_reg_0_0', 'reg0_reg_31_0', 'reg0_reg_30_0', 'reg0_reg_29_0', 'reg0_reg_28_0', 'reg0_reg_27_0', 'reg0_reg_26_0', 'reg0_reg_25_0', 'reg0_reg_24_0', 'reg0_reg_23_0', 'reg0_reg_22_0', 'reg0_reg_21_0', 'reg0_reg_20_0', 'reg0_reg_19_0', 'reg0_reg_18_0', 'reg0_reg_17_0', 'reg0_reg_16_0', 'reg0_reg_15_0', 'reg0_reg_14_0', 'reg0_reg_13_0', 'reg0_reg_12_0', 'reg0_reg_11_0', 'reg0_reg_10_0', 'reg0_reg_9_0', 'reg0_reg_8_0', 'reg0_reg_7_0', 'reg0_reg_6_0', 'reg0_reg_5_0', 'reg0_reg_4_0', 'reg0_reg_3_0', 'reg0_reg_2_0', 'reg0_reg_1_0', 'reg0_reg_0_0', 'rd_reg', 'datao_reg_31_0', 'datao_reg_30_0', 'datao_reg_29_0', 'datao_reg_28_0', 'datao_reg_27_0', 'datao_reg_26_0', 'datao_reg_25_0', 'datao_reg_24_0', 'datao_reg_23_0', 'datao_reg_22_0', 'datao_reg_21_0', 'datao_reg_20_0', 'datao_reg_19_0', 'datao_reg_18_0', 'datao_reg_17_0', 'datao_reg_16_0', 'datao_reg_15_0', 'datao_reg_14_0', 'datao_reg_13_0', 'datao_reg_12_0', 'datao_reg_11_0', 'datao_reg_10_0', 'datao_reg_9_0', 'datao_reg_8_0', 'datao_reg_7_0', 'datao_reg_6_0', 'datao_reg_5_0', 'datao_reg_4_0', 'datao_reg_3_0', 'datao_reg_2_0', 'datao_reg_1_0', 'datao_reg_0_0', 'd_reg_1_0', 'd_reg_0_0', 'addr_reg_19_0', 'addr_reg_18_0', 'addr_reg_17_0', 'addr_reg_16_0', 'addr_reg_15_0', 'addr_reg_14_0', 'addr_reg_13_0', 'addr_reg_12_0', 'addr_reg_11_0', 'addr_reg_10_0', 'addr_reg_9_0', 'addr_reg_8_0', 'addr_reg_7_0', 'addr_reg_6_0', 'addr_reg_5_0', 'addr_reg_4_0', 'addr_reg_3_0', 'addr_reg_2_0', 'addr_reg_1_0', 'addr_reg_0_0', 'u04_opt1491', 'u04_opt1492', 'u04_opt1364', 'u04_opt1411', 'IR_reg_31_0', 'IR_reg_30_0', 'IR_reg_29_0', 'u04_opt1427', 'IR_reg_28_0', 'IR_reg_27_0', 'IR_reg_26_0', 'IR_reg_25_0', 'IR_reg_24_0', 'IR_reg_23_0', 'IR_reg_22_0', 'IR_reg_21_0', 'IR_reg_20_0', 'IR_reg_19_0', 'IR_reg_18_0', 'IR_reg_17_0', 'IR_reg_16_0', 'IR_reg_15_0', 'IR_reg_14_0', 'IR_reg_13_0', 'IR_reg_12_0', 'IR_reg_11_0', 'IR_reg_10_0', 'IR_reg_9_0', 'IR_reg_8_0', 'IR_reg_7_0', 'IR_reg_6_0', 'IR_reg_5_0', 'IR_reg_4_0', 'IR_reg_3_0', 'IR_reg_2_0', 'u04_opt1347', 'IR_reg_1_0', 'U14573', 'IR_reg_0_0', 'B_reg', 'Scan_In']\n" ] } ], "source": [ "chain = []\n", "cell = b14.cells['Scan_Out']\n", "chain.append(cell)\n", "while len(cell.ins) > 0:\n", " cell = cell.ins[2 if 'SDFF' in cell.kind else 0].driver\n", " if '__fork__' not in cell.kind:\n", " chain.append(cell)\n", " \n", "print('chain length', len(chain))\n", "print([c.name for c in chain])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Loading SDFs and STILs" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "from kyupy import verilog, sdf\n", "from kyupy.saed import pin_index\n", "from kyupy import stil\n", "\n", "b14 = verilog.parse('tests/b14.v.gz')\n", "df = sdf.parse('tests/b14.sdf.gz')\n", "lt = df.annotation(b14, pin_index, interconnect=False)\n", "s = stil.parse('tests/b14.stil.gz')\n", "t = s.tests8v(b14)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[[0., 0.],\n", " [0., 0.]],\n", "\n", " [[0., 0.],\n", " [0., 0.]],\n", "\n", " [[0., 0.],\n", " [0., 0.]],\n", "\n", " ...,\n", "\n", " [[0., 0.],\n", " [0., 0.]],\n", "\n", " [[0., 0.],\n", " [0., 0.]],\n", "\n", " [[0., 0.],\n", " [0., 0.]]])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lt" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'00-RFRF01F10FFRFF1FR1F1RR010F0F1RRR-------F------------------------------------------------11110110011100110111111110111000010000001111010111001111110110010101100100001000101001101010010011010000001111110111101110110001011010100011010001111010011101001000011111011101111101010111001100100011111100000101110'" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 32 Parallel Time Simulations with Waveform Capacity 16\n", "\n", "This code will fall back to pure python if no CUDA card is available. This will be quite slow.\n", "\n", "Instanciate simulator:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "from kyupy.wave_sim_cuda import WaveSimCuda, TMAX\n", "import numpy as np\n", "\n", "wsim = WaveSimCuda(b14, lt, sims=32, wavecaps=16)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Main Simulation Loop" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "nvectors = 32 #len(t)\n", "r = np.zeros((len(wsim.interface), nvectors, 1))\n", "\n", "for offset in range(0, nvectors, wsim.sims):\n", " wsim.assign(t, offset=offset)\n", " wsim.propagate(sims=nvectors-offset)\n", " cdata = wsim.capture(time=TMAX, offset=offset)\n", " r = cdata[...,0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Output some captures data" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(306, 32, 6)" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cdata.shape" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[0., 0., 0., ..., 0., 0., 0.],\n", " [0., 0., 0., ..., 0., 0., 0.],\n", " [0., 0., 0., ..., 0., 0., 0.],\n", " ...,\n", " [1., 1., 1., ..., 1., 1., 1.],\n", " [0., 0., 0., ..., 0., 0., 0.],\n", " [0., 0., 0., ..., 1., 1., 1.]], dtype=float32)" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "r" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Check for CUDA Support\n", "\n", "Try this code to check if CUDA is set up correctly." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from numba import cuda\n", "\n", "cuda.detect()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.7.3" } }, "nbformat": 4, "nbformat_minor": 2 }