{ "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 }