{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "ASc0nYpw6D40"
},
"source": [
"# PyCircPl - Python Logic Circuit Programming Language \n",
"\n",
"\n",
"\n",
"* \n",
"Link to GITHUB repository\n",
"\n",
"* \n",
"Link to the the Google Colaboratory notebook\n",
"\n",
"\n",
" * The Google Colaboratory notebook has the advantage\n",
" that you can run PyCircPl code from it without having to\n",
" install PyCircPl or even Python on your local system.\n",
" * You first need to copy it to your google drive (or github repository)\n",
" * You can also dowload it to your local device and open it as\n",
" a Jupyter notebook (if you have it installed with your Python)."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "re0JUU526D47"
},
"source": [
"## Installing the PyCircPl package\n",
"* The **PyCircPl** package can be installed on your local system by running the following command from the command line\n",
"```\n",
"pip install pycircpl\n",
"```\n",
"* Or you may try running one of the following commands from this notebook.\n",
"* If you are running it from a Jupyter notebook on your local system, then it will be installed on your device. "
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"id": "H8Trabf46D47",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "1050f692-4399-498f-a6c0-15a9e5f27582"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n",
"Collecting pycircpl\n",
" Using cached pycircpl-1.1-py3-none-any.whl\n",
"Installing collected packages: pycircpl\n",
"Successfully installed pycircpl-1.1\n"
]
}
],
"source": [
"# To install from this notebook, uncomment the next line and run this cell.\n",
"%pip install pycircpl\n",
"# This should also work:\n",
"# !pip install --upgrade pycircpl\n",
"\n",
"# After installation, you have to restart this notebook.\n",
"# Make sure to comment the %pip or !pip lines above to avoid reinstall each time you run this notebook.\n",
"\n",
"# To uninstall the package use:\n",
"#%pip uninstall pycircpl\n",
"# or\n",
"# !pip uninstall pycircpl"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "5hIXG9SE6D48"
},
"source": [
"* **After installation, you may need to restart this notebook.**"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "rlDvlU9I6D48"
},
"source": [
"## Loading the PyCircPl package\n",
"* After installing the **PyCircPl** package, you need to import\n",
" it. \n",
"* The following command imports **PyCircPl** to your Python interpreter."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"id": "ZaIr21bT6D49"
},
"outputs": [],
"source": [
"from pycircpl import *"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "kD35YCtJ6D4-"
},
"source": [
"## Introduction\n",
"\n",
"* **PyCircPl** is a simple Python package for simulating\n",
"Logic Circuits specifically designed for educational use in introductory computation and digital logic college courses.\n",
"* As such, it was primarily tuned for simplicity, readability\n",
" convenience, and fast learning curve.\n",
" * Less for speed or industrial production.\n",
"* It is a lightweight package especially designed for\n",
" small to medium scale circuits, such as those that are studied\n",
" in introductory academic courses on the theory of computation\n",
" and electronic digital design.\n",
"* Its main characteristic is that a digital circuit or a boolean\n",
" formula can be easily defined by a series of simple Python commands,\n",
" rather than an external static language.\n",
"* So, the only requirement is basic knowledge of the\n",
" Python programming language, with a little programming skill.\n",
"* Experienced Python programmers can probably benefit a lot\n",
" more from this package.\n",
"* It can be a useful companion for theoretical courses on\n",
" computation models and languages who wish also to engage\n",
" the students with some programming experience and skills.\n",
" * It is planned to be used in such a course by the author\n",
" (Hebrew book at http://samyzaf.com/afl.pdf).\n",
" * It enables students to easily model and experiment with\n",
" * Typical logic circuit design\n",
" * Logic Circuit or Boolean formula Validation\n",
" * Logic Circuit Testing\n",
" * Logic problem solving\n",
"* It does provide an opportunity for students to develop\n",
" and practice some programming skills while covering\n",
" the theoretical computation course.\n",
"* In this tutorial, we will cover:\n",
" 1. Basic usage of PyCircPl for simulating\n",
" Logic Circuits or Boolean formulas.\n",
" 2. A short survey of the commands and tools of the **PyCircPl** package.\n",
" 3. Advanced usage of PyCirc for experienced Python\n",
" programmers (TODO)."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "qSfarxQ-6D4_"
},
"source": [
"## Example 1: Simulating the circuit FOO\n",
"* We start with a very simple logic circuit which we call **\"FOO\"**\n",
" whose **PyCirc Diagram** is given below\n",
" * Inputs gates: $x_1$, $x_2$, $x_3$\n",
" * Output gates: $y_1$, $y_2$\n",
" * Logic formula: $(y_1, y_2) = (x_1 \\land x_2 , \\ \\neg x_3)$\n",
" * See https://www.samyzaf.com/pycirc/pycirc.html for detailed\n",
" information on PyCirc diagrams. \n",
"\n",
" \n",
"\n",
"* Here is the **PyCircPl code** for modeling this circuit:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"id": "TxVm9Pf-6D5B"
},
"outputs": [],
"source": [
"def FOO(x1, x2, x3):\n",
" g1 = AND(x1, x2)\n",
" g2 = NOT(x3)\n",
" y1 = g1\n",
" y2 = g2\n",
" return y1, y2"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "kU-kvZpn6D5B"
},
"source": [
"* Notic that this is a **pure Python code**!\n",
" * So you need to **run** its cell in order to execute it.\n",
"\n",
"* A circuit definition starts with the stabdard Python keyword `def`\n",
" which is used to define a Python function.\n",
"* The function name is identical to the circuit name `FOO`.\n",
"* The function argument list is identical to the circuit boolean\n",
" input list `x1`, `x2`, `x3`.\n",
"* The function output list (in the last `return` statement) is\n",
" identical to the circuit output list.\n",
" \n",
"* Note that we could make the definition shorter by removing the\n",
" two intermediate variable `g1` and `g2`, but their presence\n",
" keeps a resemblance with the circuit diagram.\n",
"\n",
"* We ephasize again: the above definition of **FOO** is\n",
" a **pure Python function**!\n",
"* This means that you can use in any othe Python code and\n",
" in other programs/scripts for building new circuit functions.\n",
"\n",
"* Here is a simple example which computes the circuit for the input\n",
"```Python\n",
"x1 = 1\n",
"x2 = 1\n",
"x3 = 0\n",
"```"
]
},
{
"cell_type": "code",
"source": [
"y1,y2 = FOO(1,1,0)\n",
"print(f\"y1={y1}\")\n",
"print(f\"y2={y2}\")"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "6KCfVXDzvGqj",
"outputId": "5454e763-b74c-4975-ad47-578ac81cfc98"
},
"execution_count": 4,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"y1=1\n",
"y2=1\n"
]
}
]
},
{
"cell_type": "markdown",
"source": [
"Here is a more sophisticated example for Pyhton programmers for\n",
"generating the **Truth Table** of `FOO`.\n",
"That is, all possible outputs."
],
"metadata": {
"id": "bWQWOaJ54g-o"
}
},
{
"cell_type": "code",
"source": [
"for x1 in [0,1]:\n",
" for x2 in [0,1]:\n",
" for x3 in [0,1]:\n",
" y1,y2 = FOO(x1,x2,x3)\n",
" print(f\"FOO({x1},{x2},{x3}) = {y1}, {y2}\")"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "MbA3AgKw4fb4",
"outputId": "e6e00c0c-f396-42db-a9f8-5599927e34d0"
},
"execution_count": 5,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"FOO(0,0,0) = 0, 1\n",
"FOO(0,0,1) = 0, 0\n",
"FOO(0,1,0) = 0, 1\n",
"FOO(0,1,1) = 0, 0\n",
"FOO(1,0,0) = 0, 1\n",
"FOO(1,0,1) = 0, 0\n",
"FOO(1,1,0) = 1, 1\n",
"FOO(1,1,1) = 1, 0\n"
]
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "KPAdr0VY6D5C"
},
"source": [
"* After successful design of a circuit function such as **FOO**,\n",
" it can be placed as a single file a python code file and loaded\n",
" as usual with the Python `import` command.\n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "oHjloVC56D5C"
},
"source": [
"* You may want to copy the function library that we use in this\n",
" notebook to your local pc.\n",
"* Here is a link to the Python file that contains all functions\n",
" that we use in this notebook:\n",
" * [Click to download functions.py](https://samyzaf.com/pycirc/functions.py)\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "80ERuNF06D5D"
},
"source": [
"## Example 2: Simulating the circuit FRED\n",
"* Here is an example of cell called **FRED** which uses an instance of the cell **FOO** as one of its building blocks.\n",
"* Note that this cell is using a gate of type `FOO` whose function\n",
" we defined in Example 1 above.\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "B5eHBew46D5E"
},
"source": [
"\n",
"\n",
"\n",
" \n",
"\n"
]
},
{
"cell_type": "markdown",
"source": [
"* It is easy to write its corresponding function.\n",
"* Note that the function `FOO` is used in the function `FRED`."
],
"metadata": {
"id": "98xqznYqBT1B"
}
},
{
"cell_type": "code",
"source": [
"def FRED(x1, x2):\n",
" g0 = 0\n",
" y1,y2 = FOO(x1,x2,g0)\n",
" return y1,y2"
],
"metadata": {
"id": "Vb0U-NC-BTDq"
},
"execution_count": 6,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "Ko9IcHhT6D5E"
},
"source": [
"## Example 3: The circuit HAM\n",
"* The follwing cell **HAM** contains two gates of type **FOO**\n",
" and two gates of type **XOR3**.\n",
"* The **XOR3** cell is a typical **xor** cell with 3 input\n",
" gates.\n",
"* It also contains one gate of type **NOT**.\n",
"\n",
" "
]
},
{
"cell_type": "markdown",
"source": [
"* Here is a **PyCircPl code** for modeling this cell.\n",
"* Notice lines 2 and 3 of the code that use the function `FOO`."
],
"metadata": {
"id": "TmMuARGzI9VV"
}
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"id": "gFwgNmlj6D5F"
},
"outputs": [],
"source": [
"# CELL: HAM\n",
"# This cell is using the FOO cell which we defined earlier\n",
"# \"XOR\" is a basic function in PyCircPl\n",
"\n",
"def HAM(x1,x2,x3,x4):\n",
" g1_y1, g1_y2 = FOO(x1,x3,x2)\n",
" g2_y1, g2_y2 = FOO(x3,x4,x4)\n",
" g3_y = XOR(g1_y2, g1_y1, g2_y2)\n",
" g4_y = NOT(g1_y2)\n",
" g5_y = XOR(g1_y2, g2_y1, g2_y2)\n",
" y1 = g3_y\n",
" y2 = g4_y\n",
" y3 = g5_y\n",
" return y1, y2, y3"
]
},
{
"cell_type": "markdown",
"source": [
"* Here is a simple code for generating the truth table of `HAM`.\n",
"* We use the `product` utility from the `itertools` module (which is\n",
" automatically loaded by pycircpl) to generate all the possible\n",
" combinations of 4 boolean values."
],
"metadata": {
"id": "Kli6pX9TQPnu"
}
},
{
"cell_type": "code",
"source": [
"for x1,x2,x3,x4 in product([0,1], repeat=4):\n",
" y1,y2,y3 = HAM(x1,x2,x3,x4)\n",
" print(f\"HAM({x1}, {x2}, {x3}, {x4}) = {y1}, {y2}, {y3}\")"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "GNAOYA5rPprs",
"outputId": "7861d041-0138-4139-c79e-c18e32bc50be"
},
"execution_count": 11,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"HAM(0, 0, 0, 0) = 0, 0, 0\n",
"HAM(0, 0, 0, 1) = 1, 0, 1\n",
"HAM(0, 0, 1, 0) = 0, 0, 0\n",
"HAM(0, 0, 1, 1) = 1, 0, 0\n",
"HAM(0, 1, 0, 0) = 1, 1, 1\n",
"HAM(0, 1, 0, 1) = 0, 1, 0\n",
"HAM(0, 1, 1, 0) = 1, 1, 1\n",
"HAM(0, 1, 1, 1) = 0, 1, 1\n",
"HAM(1, 0, 0, 0) = 0, 0, 0\n",
"HAM(1, 0, 0, 1) = 1, 0, 1\n",
"HAM(1, 0, 1, 0) = 0, 0, 0\n",
"HAM(1, 0, 1, 1) = 0, 0, 0\n",
"HAM(1, 1, 0, 0) = 1, 1, 1\n",
"HAM(1, 1, 0, 1) = 0, 1, 0\n",
"HAM(1, 1, 1, 0) = 0, 1, 1\n",
"HAM(1, 1, 1, 1) = 1, 1, 1\n"
]
}
]
},
{
"cell_type": "markdown",
"source": [
"## Example 4: Simulating 1-bits counter circuit\n",
"* The following circuit (given simple digraph represantation) counts\n",
" the number of 1-bits of its input list.\n",
"\n",
""
],
"metadata": {
"id": "wx5alQ_geuZy"
}
},
{
"cell_type": "markdown",
"source": [
"* This is the correponging Python function:"
],
"metadata": {
"id": "TpJk_TCJjI_t"
}
},
{
"cell_type": "code",
"source": [
"def COUNT3(x1, x2, x3):\n",
" g1 = AND(x1, x2)\n",
" g3 = XOR(x1, x2)\n",
" g2 = AND(x3, g3)\n",
" g4 = XOR(x3, g3)\n",
" g5 = OR(g1, g2)\n",
" y1 = g5\n",
" y2 = g4\n",
" return y1, y2\n"
],
"metadata": {
"id": "S8oXfISFi2Q8"
},
"execution_count": 8,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"* Converting the graph diagram to the corresponding Python code\n",
" is an easy task.\n",
"* Each non-input gate `g1`, `g3`, `g2`, `g4`, `g5`, `y1`, `y2`,\n",
" is converted to its corresponding Python statement by simply\n",
" applying its logical operator on its inputs.\n",
"* Note that gate order is critical! You have to go from low to high depth.\n",
"* For example, gate variable `g3` must be defined befor `g2` since\n",
" it is an input to `g2`!"
],
"metadata": {
"id": "m82iw5f6E5KK"
}
},
{
"cell_type": "markdown",
"source": [
"* For example, here is what happens we apply `COUNT3` on the input list\n",
"```\n",
"x1 = 1 ; x2=0 ; x3 = 1\n",
"```"
],
"metadata": {
"id": "b6Ck-hzEFsfa"
}
},
{
"cell_type": "code",
"source": [
"COUNT3(1,0,1)"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "6ryKhBpOpr7n",
"outputId": "2cb4700f-876d-4456-99b3-1aa608060fa4"
},
"execution_count": 9,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"(1, 0)"
]
},
"metadata": {},
"execution_count": 9
}
]
},
{
"cell_type": "markdown",
"source": [
"* The number of 1-bits in the input `(1,0,1)` is 2 which in binary\n",
" form is `(1,0)` as the above calculation shows.\n",
"* It is easy to verify all possible outcomes of this circuit function\n",
" with the following code:"
],
"metadata": {
"id": "NOvdF2bZqO05"
}
},
{
"cell_type": "code",
"source": [
"for x1,x2,x3 in product([0,1], repeat=3):\n",
" y1,y2 = COUNT3(x1,x2,x3)\n",
" print(f\"COUNT3({x1},{x2},{x3}) = ({y1}, {y2})\")"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "4Pw3Kb5qq1CD",
"outputId": "9050925f-e2d3-4c85-cbcf-92ef62fad790"
},
"execution_count": 10,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"COUNT3(0,0,0) = (0, 0)\n",
"COUNT3(0,0,1) = (0, 1)\n",
"COUNT3(0,1,0) = (0, 1)\n",
"COUNT3(0,1,1) = (1, 0)\n",
"COUNT3(1,0,0) = (0, 1)\n",
"COUNT3(1,0,1) = (1, 0)\n",
"COUNT3(1,1,0) = (1, 0)\n",
"COUNT3(1,1,1) = (1, 1)\n"
]
}
]
},
{
"cell_type": "markdown",
"source": [
"* Note that the same applies if we are given a boolean formula of\n",
" this logical circuit\n",
"$$\n",
"\\begin{array}{rcl}\n",
"y_1 &=& (x_1 \\wedge x_2) \\vee ((x_1 \\oplus x_2) \\wedge x_3)\n",
"\\\\\n",
"y_2 &=& (x_1 \\oplus x_2) \\oplus x_3\n",
"\\end{array}\n",
"$$\n",
"instead of its digraph representation.\n",
"* In most cases, the digraph diagram is more intuitive, and easier\n",
" to work with than the algebraic formula."
],
"metadata": {
"id": "qHmlHv6XjoV8"
}
},
{
"cell_type": "markdown",
"metadata": {
"id": "kNi7FIqG6D5K"
},
"source": [
"## Example 5: Simulating a 4x1 Multiplexer\n",
"* Multiplxers are important circuit elements in electronic design.\n",
"* Here is a simple **PyCirc Diagram** for\n",
" a 4x1 Multiplexer circuit (aka MUX2)\n",
" \n",
" "
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"id": "yxBa2uco6D5K"
},
"outputs": [],
"source": [
"# Function for MUX2\n",
"# input: x3, x2, x1, x0, s2, s1\n",
"# output: y\n",
"\n",
"def MUX2(x0,x1,x2,x3,s1,s2):\n",
" g1_y = NOT(s1)\n",
" g2_y = NOT(s2)\n",
" g3_y = AND(g1_y, x0, g2_y)\n",
" g4_y = AND(g1_y, x1, s2)\n",
" g5_y = AND(s1, x2, g2_y)\n",
" g6_y = AND(s1, x3, s2)\n",
" y = OR(g3_y, g4_y, g5_y, g6_y)\n",
" return y\n"
]
},
{
"cell_type": "code",
"source": [
"for x0,x1,x2,x3,s1,s2 in product([0,1], repeat=6):\n",
" y = MUX2(x0,x1,x2,x3,s1,s2)\n",
" print(f\"MUX2({x0}, {x1}, {x2}, {x3}, {s1}, {s2}) = {y}\")"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "SFrrGtm1fnhc",
"outputId": "86035b1a-d0a4-4d81-b8be-3c038a6e2fac"
},
"execution_count": 27,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"MUX2(0, 0, 0, 0, 0, 0) = 0\n",
"MUX2(0, 0, 0, 0, 0, 1) = 0\n",
"MUX2(0, 0, 0, 0, 1, 0) = 0\n",
"MUX2(0, 0, 0, 0, 1, 1) = 0\n",
"MUX2(0, 0, 0, 1, 0, 0) = 0\n",
"MUX2(0, 0, 0, 1, 0, 1) = 0\n",
"MUX2(0, 0, 0, 1, 1, 0) = 0\n",
"MUX2(0, 0, 0, 1, 1, 1) = 1\n",
"MUX2(0, 0, 1, 0, 0, 0) = 0\n",
"MUX2(0, 0, 1, 0, 0, 1) = 0\n",
"MUX2(0, 0, 1, 0, 1, 0) = 1\n",
"MUX2(0, 0, 1, 0, 1, 1) = 0\n",
"MUX2(0, 0, 1, 1, 0, 0) = 0\n",
"MUX2(0, 0, 1, 1, 0, 1) = 0\n",
"MUX2(0, 0, 1, 1, 1, 0) = 1\n",
"MUX2(0, 0, 1, 1, 1, 1) = 1\n",
"MUX2(0, 1, 0, 0, 0, 0) = 0\n",
"MUX2(0, 1, 0, 0, 0, 1) = 1\n",
"MUX2(0, 1, 0, 0, 1, 0) = 0\n",
"MUX2(0, 1, 0, 0, 1, 1) = 0\n",
"MUX2(0, 1, 0, 1, 0, 0) = 0\n",
"MUX2(0, 1, 0, 1, 0, 1) = 1\n",
"MUX2(0, 1, 0, 1, 1, 0) = 0\n",
"MUX2(0, 1, 0, 1, 1, 1) = 1\n",
"MUX2(0, 1, 1, 0, 0, 0) = 0\n",
"MUX2(0, 1, 1, 0, 0, 1) = 1\n",
"MUX2(0, 1, 1, 0, 1, 0) = 1\n",
"MUX2(0, 1, 1, 0, 1, 1) = 0\n",
"MUX2(0, 1, 1, 1, 0, 0) = 0\n",
"MUX2(0, 1, 1, 1, 0, 1) = 1\n",
"MUX2(0, 1, 1, 1, 1, 0) = 1\n",
"MUX2(0, 1, 1, 1, 1, 1) = 1\n",
"MUX2(1, 0, 0, 0, 0, 0) = 1\n",
"MUX2(1, 0, 0, 0, 0, 1) = 0\n",
"MUX2(1, 0, 0, 0, 1, 0) = 0\n",
"MUX2(1, 0, 0, 0, 1, 1) = 0\n",
"MUX2(1, 0, 0, 1, 0, 0) = 1\n",
"MUX2(1, 0, 0, 1, 0, 1) = 0\n",
"MUX2(1, 0, 0, 1, 1, 0) = 0\n",
"MUX2(1, 0, 0, 1, 1, 1) = 1\n",
"MUX2(1, 0, 1, 0, 0, 0) = 1\n",
"MUX2(1, 0, 1, 0, 0, 1) = 0\n",
"MUX2(1, 0, 1, 0, 1, 0) = 1\n",
"MUX2(1, 0, 1, 0, 1, 1) = 0\n",
"MUX2(1, 0, 1, 1, 0, 0) = 1\n",
"MUX2(1, 0, 1, 1, 0, 1) = 0\n",
"MUX2(1, 0, 1, 1, 1, 0) = 1\n",
"MUX2(1, 0, 1, 1, 1, 1) = 1\n",
"MUX2(1, 1, 0, 0, 0, 0) = 1\n",
"MUX2(1, 1, 0, 0, 0, 1) = 1\n",
"MUX2(1, 1, 0, 0, 1, 0) = 0\n",
"MUX2(1, 1, 0, 0, 1, 1) = 0\n",
"MUX2(1, 1, 0, 1, 0, 0) = 1\n",
"MUX2(1, 1, 0, 1, 0, 1) = 1\n",
"MUX2(1, 1, 0, 1, 1, 0) = 0\n",
"MUX2(1, 1, 0, 1, 1, 1) = 1\n",
"MUX2(1, 1, 1, 0, 0, 0) = 1\n",
"MUX2(1, 1, 1, 0, 0, 1) = 1\n",
"MUX2(1, 1, 1, 0, 1, 0) = 1\n",
"MUX2(1, 1, 1, 0, 1, 1) = 0\n",
"MUX2(1, 1, 1, 1, 0, 0) = 1\n",
"MUX2(1, 1, 1, 1, 0, 1) = 1\n",
"MUX2(1, 1, 1, 1, 1, 0) = 1\n",
"MUX2(1, 1, 1, 1, 1, 1) = 1\n"
]
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "lH0of2Ny6D5K"
},
"source": [
"* This is long. Took 35 lines of code to define this circuit.\n",
"* With **compressed notation** it takes only 15 lines!\n",
"* In addition, **compressed notation** can help us understand\n",
" better the circuit structure, as it is displayed in one paragraph.\n",
"* Remember that this is a clean Python code, so you can use\n",
" Python comments, and other Python commands."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "luXJPXBy6D5U"
},
"source": [
"## Example 6: Simulating a 8x1 Multiplexer circuit\n",
"* Now we build a function for a 8x1 Multiplexer circuit (aka **MUX3**)\n",
"* Note that the 8x1 Multiplexer diagram is using\n",
" our **MUX2** circuit as one of its building blocks\n",
" (two instance of MUX2 are needed).\n",
"* We also need one instance of 2x1 Multiplexer (aka **MUX1**),\n",
" which we leave to the student as an easy exercise.\n",
"\n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "IMN7UrHa6D5U"
},
"source": [
"* As you can see from the diagram we now have 8 inputs bits:\n",
" x0, x1, x2, x3, x4, x5, x6, x7, \n",
" and one output bit: y.\n",
"* We only need 3 logic gates: g1, g2, and g3.\n",
" * g1 and g2 are two instances of MUX2,\n",
" * g3 is an instance of MUX1.\n",
"* Here is the code for creating a PyCirc MUX3 object.\n",
" * Notice that this time we are using compressed\n",
" notation technique for creating the 11 input gates in one line!\n",
" * The compressed notation can be used everywhere in PyCirc and\n",
" saves a lot of typing!\n",
" * Note that this is the python code. Within a circuit file\n",
" you must remove the openning Define and closing EndDef commands!"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"id": "KkIIjyn36D5U"
},
"outputs": [],
"source": [
"def MUX1(x0,x1,s1):\n",
" y1 = NOT(s1)\n",
" y2 = AND(x0, y1)\n",
" y3 = AND(x1, s1)\n",
" y = OR(y2, y3)\n",
" return y\n",
"\n",
"def MUX3(x0,x1,x2,x3,x4,x5,x6,x7,s1,s2,s3):\n",
" g1_y = MUX2(x0,x1,x2,x3,s2,s3)\n",
" g2_y = MUX2(x4,x5,x6,x7,s2,s3)\n",
" g3_y = MUX1(g1_y,g2_y,s1)\n",
" y = g3_y\n",
" return y"
]
},
{
"cell_type": "code",
"source": [
"MUX3(0,0,0,0,0,1,0,0, 1,0,1)"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "rWU2a7T99LQI",
"outputId": "2e33a4f0-660b-4429-83f9-163fe29982dd"
},
"execution_count": 25,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"1"
]
},
"metadata": {},
"execution_count": 25
}
]
},
{
"cell_type": "code",
"source": [
"for x0,x1,x2,x3,x4,x5,x6,x7,s1,s2,s3 in product([0,1], repeat=11):\n",
" if random()<0.95:\n",
" continue\n",
" y = MUX3(x0,x1,x2,x3,x4,x5,x6,x7,s1,s2,s3)\n",
" print(f\"MUX2({x0}, {x1}, {x2}, {x3}, {x4}, {x5}, {x6}, {x7}, {s1}, {s2}, {s3}) = {y}\")"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "iwsDqWX25NgO",
"outputId": "0c7c0644-bf5e-461d-942f-c1c5e88cedb4"
},
"execution_count": 16,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"MUX2(0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1) = 0\n",
"MUX2(0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0) = 0\n",
"MUX2(0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1) = 0\n",
"MUX2(0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1) = 1\n",
"MUX2(0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1) = 1\n",
"MUX2(0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0) = 0\n",
"MUX2(0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0) = 0\n",
"MUX2(0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1) = 0\n",
"MUX2(0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1) = 0\n",
"MUX2(0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0) = 1\n",
"MUX2(0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1) = 0\n",
"MUX2(0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1) = 1\n",
"MUX2(0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0) = 0\n",
"MUX2(0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1) = 0\n",
"MUX2(0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1) = 0\n",
"MUX2(0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1) = 0\n",
"MUX2(0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0) = 1\n",
"MUX2(0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0) = 0\n",
"MUX2(0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1) = 1\n",
"MUX2(0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1) = 1\n",
"MUX2(0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0) = 1\n",
"MUX2(0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1) = 0\n",
"MUX2(0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0) = 0\n",
"MUX2(0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0) = 0\n",
"MUX2(0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1) = 0\n",
"MUX2(0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0) = 0\n",
"MUX2(0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0) = 0\n",
"MUX2(0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1) = 1\n",
"MUX2(0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0) = 0\n",
"MUX2(0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0) = 0\n",
"MUX2(0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1) = 1\n",
"MUX2(0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0) = 0\n",
"MUX2(0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0) = 1\n",
"MUX2(0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0) = 0\n",
"MUX2(0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0) = 0\n",
"MUX2(0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1) = 1\n",
"MUX2(0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0) = 0\n",
"MUX2(0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0) = 1\n",
"MUX2(0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1) = 0\n",
"MUX2(0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0) = 1\n",
"MUX2(0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0) = 1\n",
"MUX2(0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1) = 1\n",
"MUX2(0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1) = 1\n",
"MUX2(0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0) = 1\n",
"MUX2(0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1) = 1\n",
"MUX2(0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1) = 1\n",
"MUX2(0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1) = 0\n",
"MUX2(0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0) = 1\n",
"MUX2(1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0) = 0\n",
"MUX2(1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0) = 1\n",
"MUX2(1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0) = 0\n",
"MUX2(1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0) = 1\n",
"MUX2(1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1) = 1\n",
"MUX2(1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1) = 0\n",
"MUX2(1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1) = 1\n",
"MUX2(1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1) = 0\n",
"MUX2(1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1) = 1\n",
"MUX2(1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1) = 1\n",
"MUX2(1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0) = 0\n",
"MUX2(1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0) = 0\n",
"MUX2(1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1) = 0\n",
"MUX2(1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1) = 0\n",
"MUX2(1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1) = 1\n",
"MUX2(1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0) = 1\n",
"MUX2(1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1) = 0\n",
"MUX2(1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0) = 0\n",
"MUX2(1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0) = 1\n",
"MUX2(1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1) = 0\n",
"MUX2(1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1) = 1\n",
"MUX2(1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0) = 1\n",
"MUX2(1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0) = 0\n",
"MUX2(1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1) = 1\n",
"MUX2(1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0) = 0\n",
"MUX2(1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1) = 0\n",
"MUX2(1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1) = 1\n",
"MUX2(1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1) = 0\n",
"MUX2(1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0) = 1\n",
"MUX2(1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0) = 1\n",
"MUX2(1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1) = 0\n",
"MUX2(1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1) = 1\n",
"MUX2(1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0) = 1\n",
"MUX2(1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0) = 1\n",
"MUX2(1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1) = 1\n",
"MUX2(1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1) = 0\n",
"MUX2(1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1) = 1\n",
"MUX2(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1) = 0\n",
"MUX2(1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0) = 1\n",
"MUX2(1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0) = 1\n",
"MUX2(1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0) = 1\n"
]
}
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "7-v4biNt6D5U",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "a948b71f-ffbe-4c2f-ef7f-9a9159a1a0b0"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"gate id=81: name=x0, type=inp, value=(None), depth=0\n",
"gate id=82: name=x1, type=inp, value=(None), depth=0\n",
"gate id=83: name=x2, type=inp, value=(None), depth=0\n",
"gate id=84: name=x3, type=inp, value=(None), depth=0\n",
"gate id=85: name=x4, type=inp, value=(None), depth=0\n",
"gate id=86: name=x5, type=inp, value=(None), depth=0\n",
"gate id=87: name=x6, type=inp, value=(None), depth=0\n",
"gate id=88: name=x7, type=inp, value=(None), depth=0\n",
"gate id=89: name=s1, type=inp, value=(None), depth=0\n",
"gate id=90: name=s2, type=inp, value=(None), depth=0\n",
"gate id=91: name=s3, type=inp, value=(None), depth=0\n",
"gate id=92: name=y, type=out, value=(None), depth=3\n",
"gate id=93: name=g1, type=mux2, value=(y=None), depth=1\n",
"gate id=94: name=g2, type=mux2, value=(y=None), depth=1\n",
"gate id=95: name=g3, type=mux1, value=(y=None), depth=2\n"
]
}
],
"source": [
"mux3 = PyCirc[\"mux3\"]\n",
"\n",
"for g in mux3.gates:\n",
" print(g)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "bfIHfruc6D5V",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "155e7c59-a47a-4f40-92f6-28d93e53cb11"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"x0 = None\n",
"x1 = None\n",
"x2 = None\n",
"x3 = None\n",
"x4 = None\n",
"x5 = None\n",
"x6 = None\n",
"x7 = None\n",
"s1 = None\n",
"s2 = None\n",
"s3 = None\n",
"y = None\n",
"g1 = y=None\n",
"g2 = y=None\n",
"g3 = y=None\n"
]
}
],
"source": [
"mux3 = PyCirc[\"mux3\"]\n",
"\n",
"for g in mux3.gates:\n",
" print(\"%s = %s\" % (g.name, g.get()))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true,
"id": "X-RQfMHU6D5V",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "03785921-8fff-4186-8445-ce7d88947b57"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"wire id=102:\n",
" source=gate id=81: name=x0, type=inp, value=(None), depth=0\n",
" target=gate id=93: name=g1, type=mux2, value=(y=None), depth=1\n",
" source=None\n",
" target=x0\n",
"wire id=103:\n",
" source=gate id=82: name=x1, type=inp, value=(None), depth=0\n",
" target=gate id=93: name=g1, type=mux2, value=(y=None), depth=1\n",
" source=None\n",
" target=x1\n",
"wire id=104:\n",
" source=gate id=83: name=x2, type=inp, value=(None), depth=0\n",
" target=gate id=93: name=g1, type=mux2, value=(y=None), depth=1\n",
" source=None\n",
" target=x2\n",
"wire id=105:\n",
" source=gate id=84: name=x3, type=inp, value=(None), depth=0\n",
" target=gate id=93: name=g1, type=mux2, value=(y=None), depth=1\n",
" source=None\n",
" target=x3\n",
"wire id=106:\n",
" source=gate id=85: name=x4, type=inp, value=(None), depth=0\n",
" target=gate id=94: name=g2, type=mux2, value=(y=None), depth=1\n",
" source=None\n",
" target=x0\n",
"wire id=107:\n",
" source=gate id=86: name=x5, type=inp, value=(None), depth=0\n",
" target=gate id=94: name=g2, type=mux2, value=(y=None), depth=1\n",
" source=None\n",
" target=x1\n",
"wire id=108:\n",
" source=gate id=87: name=x6, type=inp, value=(None), depth=0\n",
" target=gate id=94: name=g2, type=mux2, value=(y=None), depth=1\n",
" source=None\n",
" target=x2\n",
"wire id=109:\n",
" source=gate id=88: name=x7, type=inp, value=(None), depth=0\n",
" target=gate id=94: name=g2, type=mux2, value=(y=None), depth=1\n",
" source=None\n",
" target=x3\n",
"wire id=110:\n",
" source=gate id=90: name=s2, type=inp, value=(None), depth=0\n",
" target=gate id=93: name=g1, type=mux2, value=(y=None), depth=1\n",
" source=None\n",
" target=s1\n",
"wire id=111:\n",
" source=gate id=90: name=s2, type=inp, value=(None), depth=0\n",
" target=gate id=94: name=g2, type=mux2, value=(y=None), depth=1\n",
" source=None\n",
" target=s1\n",
"wire id=112:\n",
" source=gate id=91: name=s3, type=inp, value=(None), depth=0\n",
" target=gate id=93: name=g1, type=mux2, value=(y=None), depth=1\n",
" source=None\n",
" target=s2\n",
"wire id=113:\n",
" source=gate id=91: name=s3, type=inp, value=(None), depth=0\n",
" target=gate id=94: name=g2, type=mux2, value=(y=None), depth=1\n",
" source=None\n",
" target=s2\n",
"wire id=114:\n",
" source=gate id=89: name=s1, type=inp, value=(None), depth=0\n",
" target=gate id=95: name=g3, type=mux1, value=(y=None), depth=2\n",
" source=None\n",
" target=s1\n",
"wire id=115:\n",
" source=gate id=93: name=g1, type=mux2, value=(y=None), depth=1\n",
" target=gate id=95: name=g3, type=mux1, value=(y=None), depth=2\n",
" source=y\n",
" target=x0\n",
"wire id=116:\n",
" source=gate id=94: name=g2, type=mux2, value=(y=None), depth=1\n",
" target=gate id=95: name=g3, type=mux1, value=(y=None), depth=2\n",
" source=y\n",
" target=x1\n",
"wire id=117:\n",
" source=gate id=95: name=g3, type=mux1, value=(y=None), depth=2\n",
" target=gate id=92: name=y, type=out, value=(None), depth=3\n",
" source=y\n",
" target=None\n"
]
}
],
"source": [
"for w in mux3.wires:\n",
" print(w)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "HdGaY1RJ6D5V"
},
"source": [
"* This is quite verbose and not too helpful except for debugging.\n",
"* We can extract a more focused output with code like this."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ehGxPdiO6D5W"
},
"source": [
"## 3-bits Adder Design\n",
"* Here is a simple design for 3 bits adder with carry in (cin) and\n",
" carry out (cout) bits\n",
" \n",
" \n",
" "
]
},
{
"cell_type": "markdown",
"source": [
"* This circuit acceps three types of input\n",
" * two binary numbers: $(a_2,a_1,a_0)$, $(b_2,b_1,b_0)$\n",
" * a carry in bit: `cin`.\n",
"* Its output $(y_2,y_1,y_0)$ is the binary sum of the two numbers\n",
" (with the carry added).\n",
"* In case of addition overflow,\n",
" we need a carry out (cout) output bit as well.\n",
"* The following **PyCirc** code is the **PyCirc** model for the **ADDER3** cell."
],
"metadata": {
"id": "6BuYU8rW6We2"
}
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "UHbu5JV86D5W",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "3cd74b3a-9c6c-4833-ef67-c93a27c9fa70"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Cell = adder3: Validity check: OK.\n"
]
},
{
"output_type": "execute_result",
"data": {
"text/plain": [
""
]
},
"metadata": {},
"execution_count": 59
}
],
"source": [
"# ADDER3\n",
"# Input: a2, a1, a0, b2, b1, b0, cin\n",
"# Output: y2, y1, y0, cout\n",
"\n",
"Define(\"adder3\")\n",
"GATE(\"a2\", type=\"inp\")\n",
"GATE(\"a1\", type=\"inp\")\n",
"GATE(\"a0\", type=\"inp\")\n",
"\n",
"GATE(\"b2\", type=\"inp\")\n",
"GATE(\"b1\", type=\"inp\")\n",
"GATE(\"b0\", type=\"inp\")\n",
"\n",
"GATE(\"cin\", type=\"inp\")\n",
"\n",
"GATE(\"y2\", type=\"out\")\n",
"GATE(\"y1\", type=\"out\")\n",
"GATE(\"y0\", type=\"out\")\n",
"\n",
"GATE(\"cout\", type=\"out\")\n",
"\n",
"GATE(\"g1\", type=\"xor2\")\n",
"GATE(\"g2\", type=\"xor2\")\n",
"GATE(\"g3\", type=\"xor2\")\n",
"GATE(\"g4\", type=\"mux1\")\n",
"GATE(\"g5\", type=\"mux1\")\n",
"GATE(\"g6\", type=\"mux1\")\n",
"GATE(\"g7\", type=\"xor2\")\n",
"GATE(\"g8\", type=\"xor2\")\n",
"GATE(\"g9\", type=\"xor2\")\n",
"\n",
"WIRE(\"a2\", \"g3/x2\")\n",
"WIRE(\"a2\", \"g6/x0\")\n",
"WIRE(\"a1\", \"g2/x2\")\n",
"WIRE(\"a0\", \"g1/x2\")\n",
"WIRE(\"a0\", \"g4/x0\")\n",
"WIRE(\"b2\", \"g3/x1\")\n",
"WIRE(\"b1\", \"g2/x1\")\n",
"WIRE(\"b1\", \"g5/x0\")\n",
"WIRE(\"b0\", \"g4/x1\")\n",
"WIRE(\"b0\", \"g9/x2\")\n",
"WIRE(\"cin\", \"g1/x1\")\n",
"WIRE(\"g1/y\", \"g4/s1\")\n",
"WIRE(\"g1/y\", \"g9/x1\")\n",
"WIRE(\"g2/y\", \"g5/s1\")\n",
"WIRE(\"g2/y\", \"g8/x2\")\n",
"WIRE(\"g3/y\", \"g6/s1\")\n",
"WIRE(\"g3/y\", \"g7/x2\")\n",
"WIRE(\"g4/y\", \"g5/x1\")\n",
"WIRE(\"g4/y\", \"g8/x1\")\n",
"WIRE(\"g5/y\", \"g6/x1\")\n",
"WIRE(\"g5/y\", \"g7/x1\")\n",
"WIRE(\"g6/y\", \"cout\")\n",
"WIRE(\"g7/y\", \"y2\")\n",
"WIRE(\"g8/y\", \"y1\")\n",
"WIRE(\"g9/y\", \"y0\")\n",
"EndDef()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "52spLRpQ6D5W"
},
"source": [
"* This is the compressed version of this code.\n",
"* The number of lines was reduced by half! (from 46 to 23)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "N8BPSOfj6D5W",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "1d56de5d-453a-4f84-a3f2-efade75e5b77"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Cell = adder3: Validity check: OK.\n"
]
},
{
"output_type": "execute_result",
"data": {
"text/plain": [
""
]
},
"metadata": {},
"execution_count": 60
}
],
"source": [
"# ADDER3, compressed version\n",
"# Input: a2, a1, a0, b2, b1, b0, cin\n",
"# Output: y2, y1, y0, cout\n",
"\n",
"Define(\"adder3\")\n",
"GATE(\"a<2:0>\", type=\"inp\")\n",
"GATE(\"b<2:0>\", type=\"inp\")\n",
"GATE(\"cin\", type=\"inp\")\n",
"GATE(\"y<2:0>\", type=\"out\")\n",
"GATE(\"cout\", type=\"out\")\n",
"\n",
"GATE(\"g<1:3,7:9>\", type=\"xor2\")\n",
"GATE(\"g<4:6>\", type=\"mux1\")\n",
"\n",
"WIRE(\"a2\", \"g3/x2; g6/x0\")\n",
"WIRE(\"a1\", \"g2/x2\")\n",
"WIRE(\"a0\", \"g1/x2; g4/x0\")\n",
"WIRE(\"b2\", \"g3/x1\")\n",
"WIRE(\"b1\", \"g2/x1; g5/x0\")\n",
"WIRE(\"b0\", \"g4/x1; g9/x2\")\n",
"WIRE(\"cin\", \"g1/x1\")\n",
"WIRE(\"g1/y\", \"g4/s1; g9/x1\")\n",
"WIRE(\"g2/y\", \"g5/s1; g8/x2\")\n",
"WIRE(\"g3/y\", \"g6/s1; g7/x2\")\n",
"WIRE(\"g4/y\", \"g5/x1; g8/x1\")\n",
"WIRE(\"g5/y\", \"g6/x1; g7/x1\")\n",
"WIRE(\"g6/y\", \"cout\")\n",
"WIRE(\"g<7:9>/y\", \"y<2:0>\")\n",
"EndDef()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "JhzPL6CN6D5X"
},
"outputs": [],
"source": [
"adder3 = PyCirc[\"adder3\"]"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "HMY9I8pY6D5X"
},
"source": [
"* Lets test our adder by verifying that\n",
"```\n",
"011+011=110\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "yQ3RQYD16D5X",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "c06781e8-2304-427d-8ec7-438878c0c1ba"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"011 + 011 = 110 : cin=0 cout=0\n"
]
}
],
"source": [
"bits = \"011\" + \"011\" + \"0\"\n",
"a = Assign(\"a<2:0>; b<2:0>; cin\", bits)\n",
"o = adder3(a)\n",
"cin = a[\"cin\"]\n",
"cout = o[\"cout\"]\n",
"A = a.bits(\"a<2:0>\")\n",
"B = a.bits(\"b<2:0>\")\n",
"Y = o.bits(\"y<2:0>\")\n",
"print(\"%s + %s = %s : cin=%s cout=%s\" % (A,B,Y,cin,cout))"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "K78dzlbc6D5X"
},
"source": [
"## ADDER9 - 9-bits Adder Design\n",
"* Here is a simple **PyCirc Design Diagram** for the standard 9-bits adder with a carry in (cin) and carry out (cout) bits.\n",
"* It uses 3 gates g1, g2, g3, of type **ADDER3** which are chained by their cout/cin pins.\n",
"* **Input:** `a<8:0> + b<8:0> + cin`\n",
"* **Output:** `y<8:0> + cout`\n",
" \n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "kSwpeV6Q6D5Y"
},
"source": [
"* Here is a compressed **PyCirc** code for **ADDER9**:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "CjizQoMi6D5Y",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "fbff19f0-9743-4424-cb96-65da6db18248"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Cell = adder9: Validity check: OK.\n"
]
},
{
"output_type": "execute_result",
"data": {
"text/plain": [
""
]
},
"metadata": {},
"execution_count": 63
}
],
"source": [
"# ADDER9\n",
"# Input: a8, a7, a6, a5, a4, a3, a2, a1, a0, b8, b7, b6, b5, b4, b3, b2, b1, b0, cin\n",
"# Output: y8, y7, y6, y5, y4, y3, y2, y1, y0, cout\n",
"\n",
"need(\"adder3\")\n",
"\n",
"Define(\"adder9\")\n",
"GATE(\"a<8:0>;b<8:0>\", type=\"inp\")\n",
"GATE(\"cin\", type=\"inp\")\n",
"GATE(\"y<8:0>\", type=\"out\")\n",
"GATE(\"cout\", type=\"out\")\n",
"GATE(\"g1\", type=\"adder3\") # First ADDER3 gate\n",
"GATE(\"g2\", type=\"adder3\") # Second ADDER3 gate\n",
"GATE(\"g3\", type=\"adder3\") # Third ADDER3 gate\n",
"\n",
"WIRE(\"a<0:2>\", \"g1/a<0:2>\"),\n",
"WIRE(\"a<3:5>\", \"g2/a<0:2>\"),\n",
"WIRE(\"a<6:8>\", \"g3/a<0:2>\"),\n",
"WIRE(\"b<0:2>\", \"g1/b<0:2>\"),\n",
"WIRE(\"b<3:5>\", \"g2/b<0:2>\"),\n",
"WIRE(\"b<6:8>\", \"g3/b<0:2>\"),\n",
"WIRE(\"cin\", \"g1/cin\"),\n",
"WIRE(\"g1/cout\", \"g2/cin\"),\n",
"WIRE(\"g2/cout\", \"g3/cin\"),\n",
"WIRE(\"g3/cout\", \"cout\"),\n",
"WIRE(\"g1/y<0:2>\", \"y<0:2>\"),\n",
"WIRE(\"g2/y<0:2>\", \"y<3:5>\"),\n",
"WIRE(\"g3/y<0:2>\", \"y<6:8>\"),\n",
"EndDef()\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "CIJBQJwE6D5Y"
},
"source": [
"* The `full_run` utility can be used for traversing all input/output pairs.\n",
"* Interactively.\n",
"* To stop: press \"q\"."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "OeDsrurC6D5Y",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "c30bc797-5c8d-42b4-dd66-6f05e27775c7"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Input:\n",
"a8=0, a7=0, a6=0, a5=0, a4=0, a3=0, a2=0, a1=0, a0=0, b8=0, b7=0, b6=0, b5=0, b4=0, b3=0, b2=0, b1=0, b0=0, cin=0\n",
"Output:\n",
"y8=0, y7=0, y6=0, y5=0, y4=0, y3=0, y2=0, y1=0, y0=0, cout=0\n",
"Press to continue or 'q' to quit\n",
"Next? \n",
"Input:\n",
"a8=0, a7=0, a6=0, a5=0, a4=0, a3=0, a2=0, a1=0, a0=0, b8=0, b7=0, b6=0, b5=0, b4=0, b3=0, b2=0, b1=0, b0=0, cin=1\n",
"Output:\n",
"y8=0, y7=0, y6=0, y5=0, y4=0, y3=0, y2=0, y1=0, y0=1, cout=0\n",
"Press to continue or 'q' to quit\n",
"Next? \n",
"Input:\n",
"a8=0, a7=0, a6=0, a5=0, a4=0, a3=0, a2=0, a1=0, a0=0, b8=0, b7=0, b6=0, b5=0, b4=0, b3=0, b2=0, b1=0, b0=1, cin=0\n",
"Output:\n",
"y8=0, y7=0, y6=0, y5=0, y4=0, y3=0, y2=0, y1=0, y0=1, cout=0\n",
"Press to continue or 'q' to quit\n",
"Next? q\n"
]
}
],
"source": [
"adder9 = PyCirc[\"adder9\"]\n",
"\n",
"full_run(adder9)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "7iYCv68p6D5Y"
},
"source": [
"* However this is not readable and takes forever!\n",
"* Number of inputs is 17 bits, so the loop has $2^{17} = 131072$ cycles!\n",
"* We will better off running only random assignments, and verify them manually.\n",
"* The **pycirc** package has the following utility for creating a random assignment.\n",
"```python\n",
"def random_assignment(names):\n",
" names = expand(names)\n",
" a = Assign(names)\n",
" for x in names:\n",
" a[x] = randint(0,1)\n",
" return a\n",
"```\n",
"* Here are 5 random samples on our **ADDER3** input"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "WAEitdUu6D5Z",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "e560eb94-f043-4c5f-abfd-76a165e7d531"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"000000001 000110011 0\n",
"000110000 010110001 1\n",
"111011011 100000010 0\n",
"111000011 001100110 1\n",
"011111111 111000001 1\n"
]
}
],
"source": [
"names = \"a<8:0>; b<8:0>; cin\"\n",
"for i in range(5):\n",
" a = random_assignment(names)\n",
" A = a.bits(\"a<8:0>\")\n",
" B = a.bits(\"b<8:0>\")\n",
" print(A, B, a[\"cin\"])"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "K8LVp5kO6D5Z"
},
"source": [
"* Now we can generate random inputs for **ADDER9**, get the output, and verify its correctness."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "IgBi6JWd6D5Z",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "24c54944-567f-4ca0-a096-8cb502cc6187"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"--------------------------------------------------------------------------------\n",
"Input: 111001010 + 000010011 + 1\n",
"Output: 111011110 + 0\n",
"Verify sum: 0b111011101\n",
"Press to continue or q to stop: \n",
"--------------------------------------------------------------------------------\n",
"Input: 110110111 + 011010010 + 1\n",
"Output: 010001010 + 1\n",
"Verify sum: 0b1010001001\n",
"Press to continue or q to stop: \n",
"--------------------------------------------------------------------------------\n",
"Input: 000101011 + 000111000 + 0\n",
"Output: 001100011 + 0\n",
"Verify sum: 0b1100011\n",
"Press to continue or q to stop: q\n"
]
}
],
"source": [
"names = \"a<8:0>; b<8:0>; cin\"\n",
"while True:\n",
" a = random_assignment(names)\n",
" A = a.bits(\"a<8:0>\")\n",
" B = a.bits(\"b<8:0>\")\n",
" cin = a[\"cin\"]\n",
" print(80*\"-\")\n",
" print(\"Input: %s + %s + %s\" % (A, B, cin))\n",
" o = adder9(a)\n",
" Y = o.bits(\"y<8:0>\")\n",
" cout = o[\"cout\"]\n",
" print(\"Output: %s + %s\" % (Y, cout))\n",
" print(\"Verify sum: %s\" % (bin(int(A,2) + int(B,2)),))\n",
" inpstr = input(\"Press to continue or q to stop: \")\n",
" if \"q\" == inpstr:\n",
" break"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "uDASOOgx6D5Z"
},
"source": [
"## Full Adder\n",
"* A full adder is a the same thing except that it does not have carry bits.\n",
"* It simply adds its two input bits and outputs the sum.\n",
"* In general, an **n-bits full adder** has $2n$ inputs bits \"a<0:n-1>\" + \"\" and $n+1$ output bits \"y<0:n>\".\n",
"* We will use our **ADDER3** cell to build a full **2-bits adder**\n",
" * by injecting a zero constant to its **cin** input,\n",
" * and discarding its **cout** output bit.\n",
"* We will also use this opportunity to present a different style for creating a PyCirc cell."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "rKPdCmYc6D5Z",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "49901ade-8386-4a32-8642-951d8edc5609"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"ATTENTION: some outputs are dangling! ad3 (adder3) : {'cout'}\n",
"Cell = full_adder2: Validity check: OK.\n"
]
},
{
"output_type": "execute_result",
"data": {
"text/plain": [
""
]
},
"metadata": {},
"execution_count": 67
}
],
"source": [
"# CELL: FULL ADDER 2 \n",
"\n",
"# We need adder3\n",
"need(\"adder3\")\n",
"\n",
"# Here we present a different style for defining a logic circuit\n",
"\n",
"gates = (\n",
" GATE(\"a1\", type=\"inp\")\n",
"+ GATE(\"a0\", type=\"inp\")\n",
"+ GATE(\"b1\", type=\"inp\")\n",
"+ GATE(\"b0\", type=\"inp\") \n",
"+ GATE(\"ad3\", type=\"adder3\")\n",
"+ GATE(\"y2\", type=\"out\")\n",
"+ GATE(\"y1\", type=\"out\")\n",
"+ GATE(\"y0\", type=\"out\")\n",
"+ GATE(\"g0\", type=\"zero\")\n",
")\n",
"\n",
"wires = [\n",
" Wire(\"a0\", \"ad3/a0\"),\n",
" Wire(\"a1\", \"ad3/a1\"),\n",
" Wire(\"b0\", \"ad3/b0\"),\n",
" Wire(\"b1\", \"ad3/b1\"),\n",
" Wire(\"g0\", \"ad3/a2\"),\n",
" Wire(\"g0\", \"ad3/b2\"),\n",
" Wire(\"g0\", \"ad3/cin\"),\n",
" Wire(\"ad3/y0\", \"y0\"),\n",
" Wire(\"ad3/y1\", \"y1\"),\n",
" Wire(\"ad3/y2\", \"y2\"),\n",
"]\n",
"\n",
"fa2 = PyCirc(\"full_adder2\", gates, wires)\n",
"pycircLib.add_circ(fa2)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ykD6iyEv6D5a"
},
"source": [
"* Notice that in this case, we do not have \n",
" a **Define(), EndDef()** calls!\n",
"* We simply define a list of gates and a list of wires,\n",
" and later use the class **PyCirc** to create the cell.\n",
"* The wires are created by the low level `Wire` class instead\n",
" of the higher level `WIRE` function.\n",
" * The `Wire` class is suited for generating a single wire\n",
" object while `WIERE` generates multiple wires and supports\n",
" compressed names. \n",
"* An output pin which is not connected to any other pin is\n",
" called a **dangling pin**.\n",
"* Notice that our 2-bits full adder **FA2** has a dangling pin.\n",
"* The carry out bit (**cout**) of the gate **ad3** is dangling.\n",
"* Also notice the **constant gate** `g0` which fixes the carry in (**cin**) to a constant 0 value.\n",
"* A \"dangling output\" allert means that an output is not\n",
" connected to anything.\n",
" * This is OK if you intended it as we did in this example.\n",
" * To achieve a full adder we had to discard the `cout` pin of ADDER3.\n",
"\n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "isWRgyVZ6D5a"
},
"source": [
"## Boolean Operators\n",
"* The **PyCirc** package contains a **logops** module which\n",
" defines a small set of boolean functions.\n",
"* These functions are also called **boolean operators** since\n",
" * they act on a variable number of boolean values.\n",
" * return a boolean value.\n",
"* These operators are needed for designing **black box cells**\n",
" that play an important role in the **VLSI** design process.\n",
"* Here are a few examples of operators we have\n",
" in the **pycirc** package:\n",
" * **AND**, **OR**, **NOR**, **XOR**, **NOT**, **MUX**.\n",
" * They all accept an **Assign** object as an argument,\n",
" * and return an **Assign** object.\n",
" \n",
"```Python\n",
"def AND(a, output=\"y\"):\n",
" o = Assign(output)\n",
" for x in a:\n",
" if a[x] == 0:\n",
" for y in o: o[y] = 0\n",
" return o\n",
" for y in o: o[y] = 1\n",
" return o\n",
"\n",
"def OR(a, output=\"y\"):\n",
" o = Assign(output)\n",
" for x in a:\n",
" if a[x] == 1:\n",
" for y in o: o[y] = 1\n",
" return o\n",
" for y in o: o[y] = 0\n",
" return o\n",
"\n",
"def NOR(a, output=\"y\"):\n",
" o = Assign(output)\n",
" o1 = OR(a, Assign(\"y\"))\n",
" b = Assign(\"x\", o1[\"y\"])\n",
" return NOT(b, o)\n",
"\n",
"def XOR(a, output=\"y\"):\n",
" o = Assign(output)\n",
" if sum(a[x] for x in a) == 1:\n",
" for y in o: o[y] = 1\n",
" return o\n",
" else:\n",
" for y in o: o[y] = 0\n",
" return o\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "bkRsBuZy6D5a"
},
"source": [
"* Users can easily add more operators in client code.\n",
"* Here are two examples that we used in the development of\n",
" **pycirc** for testing the various **1-bit counter** cells\n",
" and the **magnitude comparator** cells.\n",
"* The first operator is simply a Python code for counting how many\n",
" 1-bits a given assigmnet object `a` has?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "FwYu12Wu6D5a"
},
"outputs": [],
"source": [
"# Count the number of 1-bits in the assignment a\n",
"def COUNT_ONES(a):\n",
" s = sum(a())\n",
" k = len(a).bit_length()\n",
" bits = bin(s)[2:].zfill(k)\n",
" names = \"y<%d:1>\" % (k,)\n",
" bits = [int(y) for y in bits]\n",
" o = Assign(names, bits)\n",
" return o\n",
"\n",
"# Magnitude Comparator Operator\n",
"# input: \"a<0:n>;b<0:n>\"\n",
"# output: \"y<1:3>\"\n",
"# If ab returns 001\n",
"def COMPARE(a):\n",
" A = []\n",
" B = []\n",
" for name in a:\n",
" if name[0] == \"a\":\n",
" A.append(name)\n",
" else:\n",
" B.append(name)\n",
" A = int(a.bits(A), 2)\n",
" B = int(a.bits(B), 2)\n",
" o = Assign(\"y<1:3>\")\n",
" if A\", \"01011\")\n",
"o = COUNT_ONES(a)\n",
"print(o)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "GIKhA3b06D5b"
},
"source": [
"* Note that the result is in numerical binary form: 011.\n",
"* The input \"01011\" has 3 occurrences of the bit 1,\n",
" which in numerical binary form is 11."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "3saExiz06D5b",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "0b13750b-8b87-4a82-ccfb-c3b6f6355e67"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Input: 11101011\n",
"Output (binary): 0110\n",
"Output (decimal): 6\n"
]
}
],
"source": [
"a = Assign(\"x<1:8>\", \"11101011\")\n",
"print(\"Input:\", a.bits())\n",
"o = COUNT_ONES(a)\n",
"print(\"Output (binary):\", o.bits())\n",
"print(\"Output (decimal):\", int(o.bits(), 2))"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Fw3CKvgV6D5b"
},
"source": [
"* Here, the input \"11101011\" contains 6 bits of 1.\n",
"* As expected, the output is 110 which is a numerical binary \n",
" representation of decimal 6.\n",
"* The following operators do not accept any input but produces\n",
" a **constant** output.\n",
"* These are the **constant operators**.\n",
"* The **ZERO** operator produces 0.\n",
"* The **ONE** operator produces 1.\n",
"* Here are the definitions of the **ZERO** and **ONE** operators\n",
"\n",
"```Python\n",
"def ZERO(a=None, output=\"y\"):\n",
" o = Assign(output)\n",
" for y in o: o[y] = 0\n",
" return o\n",
"\n",
"def ONE(a=None, output=\"y\"):\n",
" o = Assign(output)\n",
" for y in o: o[y] = 1\n",
" return o\n",
"```"
]
},
{
"cell_type": "markdown",
"source": [
"* The **Magnitude Comparator** operator acts on even length\n",
" assignments only.\n",
"* It splits the input to two equal length binary numbers and\n",
" compares their magnitude."
],
"metadata": {
"id": "kYy5YiwyDs5r"
}
},
{
"cell_type": "code",
"source": [
"a = Assign(\"a<0:7>; b<0:7>\", \"00101101\" + \"00110101\")\n",
"o = COMPARE(a)\n",
"print(o)"
],
"metadata": {
"id": "OifNYnWKC4YC",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "a61beec9-e323-435d-8be9-d233605510e4"
},
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"y1=1, y2=0, y3=0\n"
]
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "jo1ybisJ6D5b"
},
"source": [
"## Creating Cells with the `Cell` Class\n",
"* VLSI design usually means designing very large logic circuits\n",
" consisting of millions and even billions of elements.\n",
"* This is achieved by dividing the main circuit to a dozen or so\n",
" sub-circuits, usually called **sections**.\n",
"* Each **section** is divided to a set of smaller cells,\n",
" usually called **blocks**.\n",
"* Each **block** is partitioned to smaller cells,\n",
" usually called **functional unit blocks** (or **fubs** for short).\n",
"* And finally, each functional unit is partitioned to smaller\n",
" cells taken from established cell libraries.\n",
"* This design method is usually called **Hierarchical Design**.\n",
"* For example, here is a high level hierarchical view of\n",
" Intel's **Skylake** cpu\n",
"\n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Z2ef0tkm6D5c"
},
"source": [
"* It consists of roughly 5 billion transistors\n",
" and 20 billion wires.\n",
"* In the early design phase, only a small number of the cell\n",
" designs are available.\n",
"* Many other cells are replaced by \"black boxes\" that simulate cells,\n",
" but their full circuit design is postponed to a later stage after \n",
" passing many fire tests that verify the feasibility of\n",
" the overall design.\n",
"* These simulation tests determine many of the desired properties\n",
" and parameters for these cells, and thus provide a lot of information\n",
" and clues needed to design them efficiently.\n",
"* In such scenarios, a Logic Cell is viewed as a \"black box\" with\n",
" entry and exit points that can be defined more conveniently\n",
" by means of simple numerical software algorithms.\n",
"* **PyCirc** provides a high level **Cell** class for defining\n",
" such cells.\n",
"* So we have two ways to define a new cell: \n",
" 1. By defining a **PyCirc** circuit as in the examples above\n",
" 2. By defining a **boolean operator** numerically.\n",
" * A cell defined by an operator is named **black box**\n",
" or **box** for short.\n",
" * It is a place holder for a real circuit which is not\n",
" yet available, but the overall design need to be tested\n",
" before it is decided if its design is feasible.\n",
"* Here is an example of a 4x3 cell that is defined by\n",
" the `Cell` class."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "jpn1n12q6D5c"
},
"outputs": [],
"source": [
"count3 = Cell(\"count3\", operator=COUNT_ONES, input=\"x<1:3>\", output=\"y<1:2>\", depth=3)\n",
"# currently all box type Cells are stored in the default PyCirc library called pycircLib\n",
"pycircLib.add(count3)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "o4Oy_ysb6D5c"
},
"source": [
"* It accepts a 4-bits assignment and outputs a 3-bits assignment.\n",
"* It counts the number of 1-bits in the input.\n",
"* The operator **COUNT_ONES** was defined in the section above.\n",
"* We can now use **count3** as a cell type and use it to define more complex cells.\n",
"* As an example, let's define a **COUNT6** circuit by using two gates of type **COUNT3**.\n",
"\n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "pruNUy0P6D5d"
},
"source": [
"* The plan is straightforward:\n",
" * **COUNT6** accepts 6 input bits: x1, x2, x3, x4, x5, x6.\n",
" * The first 3 bits x1, x2, x3, are assigned to the gate **c1**\n",
" whose type is **COUNT3**.\n",
" * The last 3 bits x4, x5, x6, are assigned to the gate **c2**\n",
" whose type is also **COUNT3**.\n",
" * The outputs of **c1** and **c2** are sent to gate **a**\n",
" which is a **FULL_ADDER2**.\n",
" * The gate **a** is adding up the two numbers and sends its\n",
" output to y1, y2, y3.\n",
"* Here is the **PyCirc Program** for the **COUNT6** circuit."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "PrneGKdH6D5d",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "df7a5573-648e-49e9-e9b8-70c417822b6f"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Cell = count6: Validity check: OK.\n"
]
},
{
"output_type": "execute_result",
"data": {
"text/plain": [
""
]
},
"metadata": {},
"execution_count": 73
}
],
"source": [
"Define(\"count6\")\n",
"GATE(\"x<1:6>\", type=\"inp\")\n",
"GATE(\"y<1:3>\", type=\"out\")\n",
"GATE(\"c1\", type=\"count3\") # Gate \"c1\" of type count3\n",
"GATE(\"c2\", type=\"count3\") # Gate \"c2\" of type count3\n",
"GATE(\"a\", type=\"full_adder2\")\n",
"\n",
"WIRE(\"x<1:3>\", \"c1/x<1:3>\")\n",
"WIRE(\"x<4:6>\", \"c2/x<1:3>\")\n",
"WIRE(\"c1/y1\", \"a/a1\")\n",
"WIRE(\"c1/y2\", \"a/a0\")\n",
"WIRE(\"c2/y1\", \"a/b1\")\n",
"WIRE(\"c2/y2\", \"a/b0\")\n",
"WIRE(\"a/y<2:0>\", \"y<1:3>\")\n",
"EndDef()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "y1BPWSO06D5d"
},
"source": [
"* Here is the Python code for adding some of the box cells in **PyCirc**.\n",
"* See the **factory** module in the **PyCirc** package for more examples.\n",
"\n",
" ```python\n",
"pycircLib.add_box(name=\"and2\", operator=AND, input=\"x<1:2>\", output=[\"y\"])\n",
"pycircLib.add_box(name=\"and3\", operator=AND, input=\"x<1:3>\", output=[\"y\"])\n",
"pycircLib.add_box(name=\"and4\", operator=AND, input=\"x<1:4>\", output=[\"y\"])\n",
"pycircLib.add_box(name=\"and5\", operator=AND, input=\"x<1:5>\", output=[\"y\"])\n",
"pycircLib.add_box(name=\"and6\", operator=AND, input=\"x<1:6>\", output=[\"y\"])\n",
"pycircLib.add_box(name=\"and7\", operator=AND, input=\"x<1:7>\", output=[\"y\"])\n",
"pycircLib.add_box(name=\"and8\", operator=AND, input=\"x<1:8>\", output=[\"y\"])\n",
"```\n",
"\n",
"* We can also use Python loops to add box cells to our cell library.\n",
"* The following Python loop, adds 32 box cellls to\n",
" the **PyCirc cell library**\n",
" * 8 **OR** box cells: **OR2, OR3, ..., OR8**\n",
" * 8 **XOR** box cells: **XOR2, XOR3, ..., XOR8**\n",
" * 8 **NOR** box cells: **NOR2, NOR3, ..., NOR8**\n",
"\n",
" ```\n",
"for k in range(2,9):\n",
" inp = \"x<1:%s>\" % (k,)\n",
" name = \"or\" + str(k)\n",
" pycircLib.add_box(name, operator=OR, input=inp, output=[\"y\"])\n",
" name = \"xor\" + str(k)\n",
" pycircLib.add_box(name, operator=XOR, input=inp, output=[\"y\"])\n",
" name = \"nor\" + str(k)\n",
" pycircLib.add_box(name, operator=NOR, input=inp, output=[\"y\"])\n",
" name = \"nand\" + str(k)\n",
" pycircLib.add_box(name, operator=NAND, input=inp, output=[\"y\"])\n",
" ```"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "0QI7OGTB6D5d"
},
"source": [
"## Advanced Topics -- To be Continued ...\n",
"* For the more experienced students we present here some more\n",
" advanced usage of the PyCirc package will be added within the\n",
" near future. To be contniued ..."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "vwSWkAFp6D5d",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 17
},
"outputId": "8a382b82-78d9-453a-b8ab-a0c2597e1f1e"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
""
],
"text/html": [
""
]
},
"metadata": {},
"execution_count": 74
}
],
"source": [
"from IPython.display import HTML\n",
"from urllib.request import urlopen\n",
"css = urlopen(\"https://samyzaf.com/css/pycirc.css\").read().decode('utf-8')\n",
"HTML(''.format(css))"
]
}
],
"metadata": {
"anaconda-cloud": {},
"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.7.11"
},
"colab": {
"provenance": [],
"collapsed_sections": []
}
},
"nbformat": 4,
"nbformat_minor": 0
}