A python module for parsing, processing, and simulating gate-level circuits.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

645 lines
18 KiB

{
"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": [
"<Circuit 'tests/b01' with 92 nodes, 130 lines, 4 ports>"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"b01"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<Circuit with 10 nodes, 8 lines, 5 ports>"
]
},
"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(<class 'int'>, {'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": [
"<Circuit 'b14' with 15864 nodes, 23087 lines, 91 ports>"
]
},
"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
}