import numpy as np
import pandas as pd
from sympy import *
init_printing()

from myhdl import *
from myhdlpeek import *
import random

#python file of convince tools. Should be located with this notebook
from sympy_myhdl_tools import *

"""
Explanation: \title{Basic Digital Logic Gates with myHDL}
\author{Steven K Armour}
\maketitle
Table of Contents
<p><div class="lev1 toc-item"><a href="#Refs" data-toc-modified-id="Refs-1"><span class="toc-item-num">1&nbsp;&nbsp;</span>Refs</a></div><div class="lev1 toc-item"><a href="#Acknowledgments" data-toc-modified-id="Acknowledgments-2"><span class="toc-item-num">2&nbsp;&nbsp;</span>Acknowledgments</a></div><div class="lev1 toc-item"><a href="#Python-Liraries-utilized" data-toc-modified-id="Python-Liraries-utilized-3"><span class="toc-item-num">3&nbsp;&nbsp;</span>Python Liraries utilized</a></div><div class="lev1 toc-item"><a href="#NOT-(inverter)" data-toc-modified-id="NOT-(inverter)-4"><span class="toc-item-num">4&nbsp;&nbsp;</span>NOT (inverter)</a></div><div class="lev2 toc-item"><a href="#Symbols" data-toc-modified-id="Symbols-41"><span class="toc-item-num">4.1&nbsp;&nbsp;</span>Symbols</a></div><div class="lev2 toc-item"><a href="#NOT-Gate-Definition" data-toc-modified-id="NOT-Gate-Definition-42"><span class="toc-item-num">4.2&nbsp;&nbsp;</span>NOT Gate Definition</a></div><div class="lev2 toc-item"><a href="#NOT-Gate-in-Sympy-and-Python" data-toc-modified-id="NOT-Gate-in-Sympy-and-Python-43"><span class="toc-item-num">4.3&nbsp;&nbsp;</span>NOT Gate in Sympy and Python</a></div><div class="lev2 toc-item"><a href="#NOT-Gate-in-myHDL" data-toc-modified-id="NOT-Gate-in-myHDL-44"><span class="toc-item-num">4.4&nbsp;&nbsp;</span>NOT Gate in myHDL</a></div><div class="lev3 toc-item"><a href="#Issue" data-toc-modified-id="Issue-441"><span class="toc-item-num">4.4.1&nbsp;&nbsp;</span>Issue</a></div><div class="lev2 toc-item"><a href="#myHDL-NOT-Gate-Testing" data-toc-modified-id="myHDL-NOT-Gate-Testing-45"><span class="toc-item-num">4.5&nbsp;&nbsp;</span>myHDL NOT Gate Testing</a></div><div class="lev2 toc-item"><a href="#myHDL-NOT-Gate-to-HDL" data-toc-modified-id="myHDL-NOT-Gate-to-HDL-46"><span class="toc-item-num">4.6&nbsp;&nbsp;</span>myHDL NOT Gate to HDL</a></div><div class="lev1 toc-item"><a href="#AND" data-toc-modified-id="AND-5"><span class="toc-item-num">5&nbsp;&nbsp;</span>AND</a></div><div class="lev2 toc-item"><a href="#Symbols" data-toc-modified-id="Symbols-51"><span class="toc-item-num">5.1&nbsp;&nbsp;</span>Symbols</a></div><div class="lev2 toc-item"><a href="#AND-Gate-Definition" data-toc-modified-id="AND-Gate-Definition-52"><span class="toc-item-num">5.2&nbsp;&nbsp;</span>AND Gate Definition</a></div><div class="lev2 toc-item"><a href="#AND-Gate-in-Sympy-and-Python" data-toc-modified-id="AND-Gate-in-Sympy-and-Python-53"><span class="toc-item-num">5.3&nbsp;&nbsp;</span>AND Gate in Sympy and Python</a></div><div class="lev2 toc-item"><a href="#myHDL-Two-input-AND-Gate-and-Testing" data-toc-modified-id="myHDL-Two-input-AND-Gate-and-Testing-54"><span class="toc-item-num">5.4&nbsp;&nbsp;</span>myHDL Two input AND Gate and Testing</a></div><div class="lev2 toc-item"><a href="#myHDL-Three-Input-AND-Gate-and-Testing" data-toc-modified-id="myHDL-Three-Input-AND-Gate-and-Testing-55"><span class="toc-item-num">5.5&nbsp;&nbsp;</span>myHDL Three Input AND Gate and Testing</a></div><div class="lev2 toc-item"><a href="#myHDL-Three-Input-AND-Gate-HDL-Synthesis" data-toc-modified-id="myHDL-Three-Input-AND-Gate-HDL-Synthesis-56"><span class="toc-item-num">5.6&nbsp;&nbsp;</span>myHDL Three Input AND Gate HDL Synthesis</a></div><div class="lev1 toc-item"><a href="#OR" data-toc-modified-id="OR-6"><span class="toc-item-num">6&nbsp;&nbsp;</span>OR</a></div><div class="lev2 toc-item"><a href="#Symbols" data-toc-modified-id="Symbols-61"><span class="toc-item-num">6.1&nbsp;&nbsp;</span>Symbols</a></div><div class="lev2 toc-item"><a href="#OR-Gate-Definition" data-toc-modified-id="OR-Gate-Definition-62"><span class="toc-item-num">6.2&nbsp;&nbsp;</span>OR Gate Definition</a></div><div class="lev2 toc-item"><a href="#OR-Gate-in-Sympy-and-Python" data-toc-modified-id="OR-Gate-in-Sympy-and-Python-63"><span class="toc-item-num">6.3&nbsp;&nbsp;</span>OR Gate in Sympy and Python</a></div><div class="lev2 toc-item"><a href="#myHDL-Two-Input-OR-Gate-and-Testing" data-toc-modified-id="myHDL-Two-Input-OR-Gate-and-Testing-64"><span class="toc-item-num">6.4&nbsp;&nbsp;</span>myHDL Two Input OR Gate and Testing</a></div><div class="lev2 toc-item"><a href="#myHDL-Three-Input-OR-Gate-and-Testing" data-toc-modified-id="myHDL-Three-Input-OR-Gate-and-Testing-65"><span class="toc-item-num">6.5&nbsp;&nbsp;</span>myHDL Three Input OR Gate and Testing</a></div><div class="lev2 toc-item"><a href="#myHDL-Three-Input-AND-Gate-HDL-Synthesis" data-toc-modified-id="myHDL-Three-Input-AND-Gate-HDL-Synthesis-66"><span class="toc-item-num">6.6&nbsp;&nbsp;</span>myHDL Three Input AND Gate HDL Synthesis</a></div><div class="lev1 toc-item"><a href="#DeMorgan's-theorem" data-toc-modified-id="DeMorgan's-theorem-7"><span class="toc-item-num">7&nbsp;&nbsp;</span>DeMorgan's theorem</a></div><div class="lev1 toc-item"><a href="#NAND" data-toc-modified-id="NAND-8"><span class="toc-item-num">8&nbsp;&nbsp;</span>NAND</a></div><div class="lev2 toc-item"><a href="#Symbols" data-toc-modified-id="Symbols-81"><span class="toc-item-num">8.1&nbsp;&nbsp;</span>Symbols</a></div><div class="lev2 toc-item"><a href="#NAND-Gate-Definition" data-toc-modified-id="NAND-Gate-Definition-82"><span class="toc-item-num">8.2&nbsp;&nbsp;</span>NAND Gate Definition</a></div><div class="lev2 toc-item"><a href="#NAND-Gate-in-Sympy-and-Python" data-toc-modified-id="NAND-Gate-in-Sympy-and-Python-83"><span class="toc-item-num">8.3&nbsp;&nbsp;</span>NAND Gate in Sympy and Python</a></div><div class="lev2 toc-item"><a href="#myHDL-Two-Input-NAND-Gate-and-Testing" data-toc-modified-id="myHDL-Two-Input-NAND-Gate-and-Testing-84"><span class="toc-item-num">8.4&nbsp;&nbsp;</span>myHDL Two Input NAND Gate and Testing</a></div><div class="lev2 toc-item"><a href="#myHDL-Three-Input-NAND-Gate-and-Testing" data-toc-modified-id="myHDL-Three-Input-NAND-Gate-and-Testing-85"><span class="toc-item-num">8.5&nbsp;&nbsp;</span>myHDL Three Input NAND Gate and Testing</a></div><div class="lev2 toc-item"><a href="#myHDL-Three-Input-NAND-Gate-HDL-Synthesis" data-toc-modified-id="myHDL-Three-Input-NAND-Gate-HDL-Synthesis-86"><span class="toc-item-num">8.6&nbsp;&nbsp;</span>myHDL Three Input NAND Gate HDL Synthesis</a></div><div class="lev1 toc-item"><a href="#NOR" data-toc-modified-id="NOR-9"><span class="toc-item-num">9&nbsp;&nbsp;</span>NOR</a></div><div class="lev2 toc-item"><a href="#Symbols" data-toc-modified-id="Symbols-91"><span class="toc-item-num">9.1&nbsp;&nbsp;</span>Symbols</a></div><div class="lev2 toc-item"><a href="#NOR-Gate-Definition" data-toc-modified-id="NOR-Gate-Definition-92"><span class="toc-item-num">9.2&nbsp;&nbsp;</span>NOR Gate Definition</a></div><div class="lev2 toc-item"><a href="#NOR-Gate-in-Sympy-and-Python" data-toc-modified-id="NOR-Gate-in-Sympy-and-Python-93"><span class="toc-item-num">9.3&nbsp;&nbsp;</span>NOR Gate in Sympy and Python</a></div><div class="lev2 toc-item"><a href="#myHDL-Two-Input-NOR-Gate-and-Testing" data-toc-modified-id="myHDL-Two-Input-NOR-Gate-and-Testing-94"><span class="toc-item-num">9.4&nbsp;&nbsp;</span>myHDL Two Input NOR Gate and Testing</a></div><div class="lev2 toc-item"><a href="#myHDL-Two-Input-NOR-Gate-HDL-Synthesis" data-toc-modified-id="myHDL-Two-Input-NOR-Gate-HDL-Synthesis-95"><span class="toc-item-num">9.5&nbsp;&nbsp;</span>myHDL Two Input NOR Gate HDL Synthesis</a></div><div class="lev1 toc-item"><a href="#XOR" data-toc-modified-id="XOR-10"><span class="toc-item-num">10&nbsp;&nbsp;</span>XOR</a></div><div class="lev2 toc-item"><a href="#Symbols" data-toc-modified-id="Symbols-101"><span class="toc-item-num">10.1&nbsp;&nbsp;</span>Symbols</a></div><div class="lev2 toc-item"><a href="#XOR-Gate-Definition" data-toc-modified-id="XOR-Gate-Definition-102"><span class="toc-item-num">10.2&nbsp;&nbsp;</span>XOR Gate Definition</a></div><div class="lev3 toc-item"><a href="#need-to-come-up-with-this" data-toc-modified-id="need-to-come-up-with-this-1021"><span class="toc-item-num">10.2.1&nbsp;&nbsp;</span>need to come up with this</a></div><div class="lev2 toc-item"><a href="#XOR-Gate-in-Sympy-and-Python" data-toc-modified-id="XOR-Gate-in-Sympy-and-Python-103"><span class="toc-item-num">10.3&nbsp;&nbsp;</span>XOR Gate in Sympy and Python</a></div><div class="lev2 toc-item"><a href="#myHDL-Two-Input-XOR-Gate-and-Testing" data-toc-modified-id="myHDL-Two-Input-XOR-Gate-and-Testing-104"><span class="toc-item-num">10.4&nbsp;&nbsp;</span>myHDL Two Input XOR Gate and Testing</a></div><div class="lev2 toc-item"><a href="#myHDL-Two-Input-XOR-gate-HDL-Synthesis" data-toc-modified-id="myHDL-Two-Input-XOR-gate-HDL-Synthesis-105"><span class="toc-item-num">10.5&nbsp;&nbsp;</span>myHDL Two Input XOR gate HDL Synthesis</a></div><div class="lev3 toc-item"><a href="#!Need-to-add-the-RTL-schematic" data-toc-modified-id="!Need-to-add-the-RTL-schematic-1051"><span class="toc-item-num">10.5.1&nbsp;&nbsp;</span>!Need to add the RTL schematic</a></div><div class="lev1 toc-item"><a href="#Min-&amp;-Max-Terms,-SOP-POS" data-toc-modified-id="Min-&amp;-Max-Terms,-SOP-POS-11"><span class="toc-item-num">11&nbsp;&nbsp;</span>Min &amp; Max Terms, SOP POS</a></div><div class="lev1 toc-item"><a href="#KMaps" data-toc-modified-id="KMaps-12"><span class="toc-item-num">12&nbsp;&nbsp;</span>KMaps</a></div><div class="lev1 toc-item"><a href="#Examples-of-boolean-expressions" data-toc-modified-id="Examples-of-boolean-expressions-13"><span class="toc-item-num">13&nbsp;&nbsp;</span>Examples of boolean expressions</a></div><div class="lev2 toc-item"><a href="#Exsample-of-a-2-bit-7-Segment-Display-Logic-Synthesis" data-toc-modified-id="Exsample-of-a-2-bit-7-Segment-Display-Logic-Synthesis-131"><span class="toc-item-num">13.1&nbsp;&nbsp;</span>Exsample of a 2 bit 7 Segment Display Logic Synthesis</a></div>

# Refs
@book{brown_vranesic_2014,
place={New York, NY},
edition={3},
title={Fundamentals of digital logic with Verilog design},
publisher={McGraw-Hill},
author={Brown, Stephen and Vranesic, Zvonko G},
year={2014}
},

@book{lameres_2017,
title={Introduction to logic circuits & logic design with Verilog},
publisher={springer},
author={LaMeres, Brock J},
year={2017}
}

# Acknowledgments

Author of **myHDL** [Jan Decaluwe](http://www.myhdl.org/users/jandecaluwe.html) and the author of the **myHDL Peeker** [XESS Corp.](https://github.com/xesscorp/myhdlpeek)

[**Draw.io**](https://www.draw.io/)

**Xilinx**

# Python Liraries utilized
End of explanation
"""


x_in, y_out=symbols('x_in, y_out')
NOTDef1=Eq(y_out, ~x_in)
NOTDef2=Eq(y_out, Not(x_in))
NOTDef1, NOTDef2

NOT_TT=TruthTabelGenrator(NOTDef1)
NOT_TT

NOTDef1N=lambdify((x_in), NOTDef1.rhs, dummify=False)
NOTDef1N(False)

pyNOTEq1=lambda x: not x

pyNOTEq1(False)

"""
Explanation: NOT (inverter)
Symbols
The symbols for the NOT gate are shown below
<img style="float: center;" src="NotagateDig.jpg">
NOT Gate Definition
\begin{definition}\label{def:not}
A NOT logic gate; also called an inverter, is a single input, single output gate that will output the boolean value opposite (inverted) to that which was inputted.
Its govering equation is given by:
$$y_{out}= \bar{x_{in}}$$
or can be repersented (as sympy does )
$$y_{out} = \neg x_{in}$$
\end{definition}
NOT Gate in Sympy and Python
End of explanation
"""


#create a HDL Module (python function) and its I\O ports
def NotGate(x_in, y_out):
    """Not Logic Gate myHDL Module (function)
    
    Args:
        x_in: bool Input port
        y_out: bool Output port
    
    Returns:
        NOT Combo logic operation
        
    """
    #define what this module is to do
    
    #myHDL built in decorator to say the function is exuiquated on each
    #clock cycle
    @always_comb
    def logic():
        
        #state the logic operation: in this case negation of the input 'x_in'
        #mapped to the ouput 'y_out' at each Clock cycle
        y_out.next= not x_in
        
    return logic

"""
Explanation: NOT Gate in myHDL
End of explanation
"""


#create the test signals and intilize value to both be false(0)
x_in, y_out=[Signal(bool(0)) for _ in range(2)]
#Peeker is helper libary for viewing wavefrom outputs and run the sim inside
#jupyter notebooks
#clear any previeese data loaded into peeker
Peeker.clear()
#load and name the signals to watch into peeker
Peeker(x_in, 'x_in')
Peeker(y_out, 'y_out')

#make an instatince of the NotGate as the DUT
DUT=NotGate(x_in=x_in, y_out=y_out)
inputs=[x_in]
sim=Simulation(DUT, Combo_TB(inputs), *Peeker.instances()).run()        
Peeker.to_wavedrom(start_time=0, stop_time=2*2**len(inputs), tock=True,
                  title='NOT gate simulation',
                  caption=f'after clock cycle {2**len(inputs)-1} ->random input')


MakeDFfromPeeker(Peeker.to_wavejson())

"""
Explanation: Issue
At the moment there was a backward compatibility break so that myHDL could call in stuff from lambda functions involving strargs, see: https://github.com/myhdl/myhdl/issues/148
Till this gets fixed no instant lampdafiy into the logic to define the thing but when this gets fixed I am trying that out 
myHDL NOT Gate Testing
End of explanation
"""


toVerilog(NotGate, x_in, y_out)
toVHDL(NotGate, x_in, y_out)
_=VerilogTextReader('NotGate')


_=VHDLTextReader('NotGate')

"""
Explanation: myHDL NOT Gate to HDL
End of explanation
"""


x_1in, x_2in, y_out=symbols('x_1in, x_2in, y_out')
AND2Def1=Eq(y_out, x_1in & x_2in)
AND2Def2=Eq(y_out, And(x_1in , x_2in))
AND2Def1, AND2Def2


AND2_TT=TruthTabelGenrator(AND2Def1)
AND2_TT

AND2Def2N=lambdify((x_1in, x_2in), AND2Def2.rhs, dummify=False)
AND2Def2N(True, False)

x_1in, x_2in, x_3in, y_out=symbols('x_1in, x_2in, x_3in, y_out')
AND3Def1=Eq(y_out, x_1in & x_2in & x_3in)
AND3Def2=Eq(y_out, And(x_1in , x_2in, x_3in))
AND3Def1, AND3Def2

AND3_TT=TruthTabelGenrator(AND3Def2)
AND3_TT

AND3Def1N=lambdify((x_1in, x_2in, x_3in), AND3Def1.rhs, dummify=False)
#not working no idea
#AND3Def1N(True, True, True)

pyAND2Eq2=lambda x1, x2: x1 & x2
pyAND2Eq2=lambda x1, x2: x1 and x2
pyAND3Eq1=lambda x1, x2, x3: x1 & x2 & x3
pyAND3Eq2=lambda x1, x2, x3: x1 and x2 and x3

pyAND2Eq2(0,0), pyAND2Eq2(0,1), pyAND3Eq1(1,1,1), pyAND3Eq1(0,1,1)

"""
Explanation: The following shows the Xilinx's Vivado 2016.1 RTL generated schematic of our NOT Gate from the synthesised verilog code
<img style="float: center;" src="NotGateRTLSch.PNG">
AND
Symbols
The symbols for an AND gate are shown below
<img style="float: center;" src="AndGateDig.jpg">
AND Gate Definition
\begin{definition}
An AND gate is a multi input single output logic gate that gives the multiplication of the boolean inputs as its output.
$$y_{\text{out}}=\prod_{i=1}^{N\geq 2} x_{i\text{ in} }$$
In more compact notation it is represented as (for a 2-input):
 $$y_{\text{out}}=x_{1\text{ in} } \cdot x_{2\text{ in} }$$
 Which can also be written (as sympy does) as:
 $$y_{\text{out}}=x_{1\text{ in} }  \wedge  x_{2\text{ in} }$$
\end{definition} 
AND Gate in Sympy and Python
End of explanation
"""


#create a HDL Module (python function) and its I\O ports
def And2Gate(x_1in, x_2in, y_out):
    """AND Logic Gate myHDL Module (function)
    
    Args:
        x_1in: bool Input port
        x_2in: bool Input port
        y_out: bool Output port
    
    Returns:
        AND Combo logic operation
        
    """
    #define what this module is to do
    
    #myHDL built in decorator to say the function is exuiquated on each
    #clock cycle
    @always_comb
    def logic():
        y_out.next= x_1in and x_2in
        
    return logic

#create the test signals and intilize value to both be false(0)
x_1in, x_2in, y_out=[Signal(bool(0)) for _ in range(3)]

#Peeker is helper libary for viewing wavefrom outputs and run the sim inside
#jupyter notebooks
#clear any previeese data loaded into peeker
Peeker.clear()

#load and name the signals to watch into peeker
Peeker(x_1in, 'x_1in'); Peeker(x_2in, 'x_2in')
Peeker(y_out, 'y_out')

#make an instatince of the NotGate as the DUT
DUT=And2Gate(x_1in=x_1in, x_2in=x_2in, y_out=y_out)

inputs=[x_1in, x_2in]

sim=Simulation(DUT, Combo_TB(inputs), *Peeker.instances()).run()        
Peeker.to_wavedrom(start_time=0, stop_time=2*2**len(inputs), tock=True,
                  title='AND 2 gate simulation',
                  caption=f'after clock cycle {2**len(inputs)-1} ->random input')


MakeDFfromPeeker(Peeker.to_wavejson(start_time=0, stop_time=2**len(inputs) -1))

"""
Explanation: myHDL Two input AND Gate and Testing
End of explanation
"""


#create a myHDL Module (python function) and its I\O ports
def And3Gate(x_1in, x_2in, x_3in, y_out):
    """AND Logic Gate myHDL Module (function)
    
    Args:
        x_1in: bool Input port
        x_2in: bool Input port
        x_3in: bool Input port
        y_out: bool Output port
    
    Returns:
        AND Combo logic operation
        
    """
    #define what this module is to do
    
    #myHDL built in decorator to say the function is exuiquated on each
    #clock cycle
    @always_comb
    def logic():
        y_out.next= x_1in and x_2in and x_3in
        
    return logic

#create the test signals and intilize value to both be false(0)
x_1in, x_2in, x_3in, y_out=[Signal(bool(0)) for _ in range(4)]

#Peeker is helper libary for viewing wavefrom outputs and run the sim inside
#jupyter notebooks
#clear any previeese data loaded into peeker
Peeker.clear()

#load and name the signals to watch into peeker
Peeker(x_1in, 'x_1in'); Peeker(x_2in, 'x_2in'); Peeker(x_3in, 'x_3in')
Peeker(y_out, 'y_out')

#make an instatince of the NotGate as the DUT
DUT=And3Gate(x_1in=x_1in, x_2in=x_2in, x_3in=x_3in, y_out=y_out)

inputs=[x_1in, x_2in, x_3in]

sim=Simulation(DUT, Combo_TB(inputs), *Peeker.instances()).run()        
Peeker.to_wavedrom(start_time=0, stop_time=2*2**len(inputs), tock=True,
                  title='AND 2 gate simulation',
                  caption=f'after clock cycle {2**len(inputs)-1} ->random input')


MakeDFfromPeeker(Peeker.to_wavejson(start_time=0, stop_time=2**len(inputs) -1))

"""
Explanation: myHDL Three Input AND Gate and Testing
End of explanation
"""


toVerilog(And3Gate, x_1in, x_2in, x_3in, y_out)
#toVHDL(And3Gate, x_1in, x_2in, x_3in y_out)
_=VerilogTextReader('And3Gate')

"""
Explanation: myHDL Three Input AND Gate HDL Synthesis
End of explanation
"""


x_1in, x_2in, y_out=symbols('x_1in, x_2in, y_out')
OR2Def1=Eq(y_out, x_1in | x_2in)
OR2Def2=Eq(y_out, Or(x_1in , x_2in))
OR2Def1, OR2Def2

OR2_TT=TruthTabelGenrator(OR2Def2)
OR2_TT

OR2Def1N=lambdify((x_1in, x_2in), OR2Def1.rhs, dummify=False)
OR2Def1N(True, False)

x_1in, x_2in, x_3in, y_out=symbols('x_1in, x_2in, x_3in, y_out')
OR3Def1=Eq(y_out, x_1in | x_2in | x_3in)
OR3Def2=Eq(y_out, Or(x_1in , x_2in, x_3in))
OR3Def1, OR3Def2

OR3_TT=TruthTabelGenrator(OR3Def1)
OR3_TT

OR3Def2N=lambdify((x_1in, x_2in, x_3in), OR3Def2.rhs, dummify=False)
#yeah WTH
#OR3Def2N(False, False, False)

pyOR2Eq1=lambda x1, x2: x1 | x2
pyOR2Eq2=lambda x1, x2: x1 or x2
pyOR3Eq1=lambda x1, x2, x3: x1 | x2 | x3
pyOR3Eq2=lambda x1, x2, x3: x1 or x2 or x3

pyOR2Eq1(0, 0), pyOR2Eq2(1,1), pyOR3Eq1(1,1,0), pyOR3Eq2(0,1,0)

"""
Explanation: The following shows the Xilinx's Vivado 2016.1 RTL generated schematic of our myHDL three input AND gate's verilog code
<img style="float: center;" src="And3GateRTLSch.PNG">
OR
Symbols
The Symbols for an OR gate are shown below
<img style="float: center;" src="OrGateDig.jpg">
OR Gate Definition
\begin{definition}\label{def:or}
An OR gate is a multi input single output logic gate that gives the sum of the boolean inputs as its output
 $$y_{\text{out}}=\sum_{i=1}^{N\geq 2} x_{i\text{ in}}$$
In more compact notation it is represented as (for a 2-input):
 $$y_{\text{out}}=x_{1\text{ in} } + x_{2\text{ in} }$$
Which can also be written (as sympy does) as:
 $$y_{\text{out}}=x_{1\text{ in} }  \vee  x_{2\text{ in} }$$
\end{definition} 
OR Gate in Sympy and Python
End of explanation
"""


#create a HDL Module (python function) and its I\O ports
def Or2Gate(x_1in, x_2in, y_out):
    """AND Logic Gate myHDL Module (function)
    
    Args:
        x_1in: bool Input port
        x_2in: bool Input port
        y_out: bool Output port
    
    Returns:
        AND Combo logic operation
        
    """
    #define what this module is to do
    
    #myHDL built in decorator to say the function is exuiquated on each
    #clock cycle
    @always_comb
    def logic():
        y_out.next= x_1in or x_2in
        
    return logic

#create the test signals and intilize value to both be false(0)
x_1in, x_2in, y_out=[Signal(bool(0)) for _ in range(3)]

#Peeker is helper libary for viewing wavefrom outputs and run the sim inside
#jupyter notebooks
#clear any previeese data loaded into peeker
Peeker.clear()

#load and name the signals to watch into peeker
Peeker(x_1in, 'x_1in'); Peeker(x_2in, 'x_2in')
Peeker(y_out, 'y_out')

#make an instatince of the NotGate as the DUT
DUT=Or2Gate(x_1in=x_1in, x_2in=x_2in, y_out=y_out)

inputs=[x_1in, x_2in]

sim=Simulation(DUT, Combo_TB(inputs), *Peeker.instances()).run()        
Peeker.to_wavedrom(start_time=0, stop_time=2*2**len(inputs), tock=True,
                  title='OR 2 gate simulation',
                  caption=f'after clock cycle {2**len(inputs)-1} ->random input')


MakeDFfromPeeker(Peeker.to_wavejson(start_time=0, stop_time=2**len(inputs) -1))

"""
Explanation: myHDL Two Input OR Gate and Testing
End of explanation
"""


#create a HDL Module (python function) and its I\O ports
def Or3Gate(x_1in, x_2in, x_3in, y_out):
    """Or Logic Gate myHDL Module (function)
    
    Args:
        x_1in: bool Input port
        x_2in: bool Input port
        x_3in: bool Input port
        y_out: bool Output port
    
    Returns:
        AND Combo logic operation
        
    """
    #define what this module is to do
    
    #myHDL built in decorator to say the function is exuiquated on each
    #clock cycle
    @always_comb
    def logic():
        y_out.next= x_1in or x_2in or x_3in
        
    return logic

#create the test signals and intilize value to both be false(0)
x_1in, x_2in, x_3in, y_out=[Signal(bool(0)) for _ in range(4)]

#Peeker is helper libary for viewing wavefrom outputs and run the sim inside
#jupyter notebooks
#clear any previeese data loaded into peeker
Peeker.clear()

#load and name the signals to watch into peeker
Peeker(x_1in, 'x_1in'); Peeker(x_2in, 'x_2in'); Peeker(x_3in, 'x_3in')
Peeker(y_out, 'y_out')

#make an instatince of the NotGate as the DUT
DUT=Or3Gate(x_1in=x_1in, x_2in=x_2in, x_3in=x_3in, y_out=y_out)

inputs=[x_1in, x_2in, x_3in]

sim=Simulation(DUT, Combo_TB(inputs), *Peeker.instances()).run()        
Peeker.to_wavedrom(start_time=0, stop_time=2*2**len(inputs), tock=True,
                  title='OR 2 gate simulation',
                  caption=f'after clock cycle {2**len(inputs)-1} ->random input')


MakeDFfromPeeker(Peeker.to_wavejson(start_time=0, stop_time=2**len(inputs) -1))

"""
Explanation: myHDL Three Input OR Gate and Testing
End of explanation
"""


toVerilog(Or3Gate, x_1in, x_2in, x_3in, y_out)
#toVHDL(And3Gate, x_1in, x_2in, x_3in y_out)
_=VerilogTextReader('Or3Gate')

"""
Explanation: myHDL Three Input AND Gate HDL Synthesis
End of explanation
"""


x_1in, x_2in, y_out=symbols('x_1in, x_2in, y_out')
NAND2Def0=Eq(y_out, Nand(x_1in, x_2in))
NAND2Def1=Eq(y_out, ~(x_1in & x_2in))
NAND2Def2=Eq(y_out, Not(And(x_1in , x_2in)))
NAND2Def3=simplify(NAND2Def2) #DeMorgan equivlinacy
NAND2Def0, NAND2Def1, NAND2Def2, NAND2Def3

NAND2_TT=TruthTabelGenrator(NAND2Def0)
NAND2_TT

NAND2_DME_TT=TruthTabelGenrator(NAND2Def2)
NAND2_DME_TT

NAND2_TT.equals(NAND2_DME_TT)

NAND2Def3N=lambdify((x_1in, x_2in), NAND2Def3.rhs, dummify=False)
NAND2Def3N(True, True)

x_1in, x_2in, x_3in, y_out=symbols('x_1in, x_2in, x_3in, y_out')
NAND3Def0=Eq(y_out, Nand(x_1in, x_2in, x_3in))
NAND3Def1=Eq(y_out, ~(x_1in & x_2in & x_3in))
NAND3Def2=Eq(y_out, Not(And(x_1in , x_2in, x_3in)))
NAND3Def3=simplify(NAND3Def1) #DeMorgan equivlinacy
NAND3Def0, NAND3Def1, NAND3Def2, NAND3Def3

NAND3_TT=TruthTabelGenrator(NAND3Def0)
NAND3_TT

NAND3_DME_TT=TruthTabelGenrator(NAND3Def1)
NAND3_TT.equals(NAND3_DME_TT)

NAND3Def3N=lambdify((x_1in, x_2in, x_3in), NAND3Def3, dummify=False)
#again WTH
#NAND3Def3N(1, 0, 1)

#DoNotTrust: pyNAND2Eq1=lambda x1, x2: ~(x1 & x2)
pyNAND2Eq2=lambda x1, x2: not(x1 and x2)
#DoNotTrust: pyNAND2Eq3=lambda x1, x2: ~x1 | ~x2
pyNAND2Eq4=lambda x1, x2: not x1 or not x2

#DoNotTrust:pyNAND3Eq1=lambda x1, x2, x3: ~(x1 & x2 & x3)
pyNAND3Eq2=lambda x1, x2, x3: not(x1 and x2 and x3)
#DoNotTrust:pyNAND3Eq3=lambda x1, x2, x3: ~x1 | ~x2 | ~x3
pyNAND3Eq4=lambda x1, x2, x3: not x1 or not x2 or not x3


 pyNAND2Eq2(0,1), pyNAND2Eq4(1,1), pyNAND3Eq2(0,1,0), pyNAND3Eq4(0,0,0)

"""
Explanation: The following shows the Xilinx's Vivado 2016.1 RTL generated schematic of our myHDL three input OR gate's verilog code
<img style="float: center;" src="Or3GateRTLSch.PNG">
DeMorgan's theorem
finding the conjugate logical expression
NAND
negated and, negated multiplication, sum of negated inputs
Symbols
NAND Gate Definition
\begin{definition}
A  NAND gate is multi input single output logic gate that gives the negation of the multiplication of the boolean inputs at its output and is thus the DeMorgan conjugate of the AND Gate 
$$y_{\text{out}}=\bar{\prod_{i=1}^{N\geq 2} x_{i\text{ in} }}=\sum_{i=1}^{N\geq 2} \bar{x_{i\text{ in} }}$$
In more compact notation it is represented as (for a 2-input):
 $$y_{\text{out}}=\bar{x_{1\text{ in} }} + \bar{x_{2\text{ in} }}$$
 Which can also be written (as sympy does) as:
 $$y_{\text{out}}=\neg(x_{1\text{ in} }  \wedge  x_{2\text{ in} })=\neg x_{1\text{ in} } \vee \neg x_{2\text{ in} }$$
\end{definition} 
NAND Gate in Sympy and Python
End of explanation
"""


#create a HDL Module (python function) and its I\O ports
def Nand2Gate(x_1in, x_2in, y_out):
    """AND Logic Gate myHDL Module (function)
    
    Args:
        x_1in: bool Input port
        x_2in: bool Input port
        y_out: bool Output port
    
    Returns:
        AND Combo logic operation
        
    """
    #define what this module is to do
    
    #myHDL built in decorator to say the function is exuiquated on each
    #clock cycle
    @always_comb
    def logic():
        y_out.next= not(x_1in and x_2in)
        
    return logic

#create the test signals and intilize value to both be false(0)
x_1in, x_2in, y_out=[Signal(bool(0)) for _ in range(3)]

#Peeker is helper libary for viewing wavefrom outputs and run the sim inside
#jupyter notebooks
#clear any previeese data loaded into peeker
Peeker.clear()

#load and name the signals to watch into peeker
Peeker(x_1in, 'x_1in'); Peeker(x_2in, 'x_2in')
Peeker(y_out, 'y_out')

#make an instatince of the NotGate as the DUT
DUT=Nand2Gate(x_1in=x_1in, x_2in=x_2in, y_out=y_out)

inputs=[x_1in, x_2in]

sim=Simulation(DUT, Combo_TB(inputs), *Peeker.instances()).run()        
Peeker.to_wavedrom(start_time=0, stop_time=2*2**len(inputs), tock=True,
                  title='NAND 2 gate simulation',
                  caption=f'after clock cycle {2**len(inputs)-1} ->random input')

MakeDFfromPeeker(Peeker.to_wavejson(start_time=0, stop_time=2**len(inputs) -1))

"""
Explanation: myHDL Two Input NAND Gate and Testing
End of explanation
"""


#create a HDL Module (python function) and its I\O ports
def Nand3Gate(x_1in, x_2in, x_3in, y_out):
    """AND Logic Gate myHDL Module (function)
    
    Args:
        x_1in: bool Input port
        x_2in: bool Input port
        x_3in: bool Input port
        y_out: bool Output port
    
    Returns:
        AND Combo logic operation
        
    """
    #define what this module is to do
    
    #myHDL built in decorator to say the function is exuiquated on each
    #clock cycle
    @always_comb
    def logic():
        y_out.next= (not x_1in) or  (not x_2in) or (not x_3in)
        
    return logic

#create the test signals and intilize value to both be false(0)
x_1in, x_2in, x_3in, y_out=[Signal(bool(0)) for _ in range(4)]

#Peeker is helper libary for viewing wavefrom outputs and run the sim inside
#jupyter notebooks
#clear any previeese data loaded into peeker
Peeker.clear()

#load and name the signals to watch into peeker
Peeker(x_1in, 'x_1in'); Peeker(x_2in, 'x_2in'); Peeker(x_3in, 'x_3in')
Peeker(y_out, 'y_out')

#make an instatince of the NotGate as the DUT
DUT=Nand3Gate(x_1in=x_1in, x_2in=x_2in, x_3in=x_3in, y_out=y_out)

inputs=[x_1in, x_2in, x_3in]

sim=Simulation(DUT, Combo_TB(inputs), *Peeker.instances()).run()        
Peeker.to_wavedrom(start_time=0, stop_time=2*2**len(inputs), tock=True,
                  title='NAND 3 gate simulation',
             ## myHDL Three Input AND Gate HDL Synthesis
     caption=f'after clock cycle {2**len(inputs)-1} ->random input')

MakeDFfromPeeker(Peeker.to_wavejson(start_time=0, stop_time=2**len(inputs) -1))

"""
Explanation: myHDL Three Input NAND Gate and Testing
End of explanation
"""


toVerilog(Nand3Gate, x_1in, x_2in, x_3in, y_out)
#toVHDL(And3Gate, x_1in, x_2in, x_3in y_out)
_=VerilogTextReader('Nand3Gate')

"""
Explanation: myHDL Three Input NAND Gate HDL Synthesis
End of explanation
"""


x_1in, x_2in, y_out=symbols('x_1in, x_2in, y_out')
NOR2Def0=Eq(y_out, Nor(x_1in, x_2in))
NOR2Def1=Eq(y_out, ~(x_1in | x_2in))
NOR2Def2=Eq(y_out, Not(Or(x_1in , x_2in)))
NOR2Def3=simplify(NOR2Def2) #DeMorgan equivlinacy
NOR2Def0, NOR2Def1, NOR2Def2, NOR2Def3

NOR2_TT=TruthTabelGenrator(NOR2Def0)
NOR2_TT

NOR2_DME_TT=TruthTabelGenrator(NOR2Def3)
NOR2_TT.equals(NOR2_DME_TT)

NOR2Def2N=lambdify((x_1in, x_2in), NOR2Def2.rhs, dummify=False)
NOR2Def2N(0,1)

x_1in, x_2in, x_3in, y_out=symbols('x_1in, x_2in, x_3in, y_out')
NOR3Def0=Eq(y_out, Nor(x_1in, x_2in, x_3in))
NOR3Def1=Eq(y_out, ~(x_1in | x_2in | x_3in))
NOR3Def2=Eq(y_out, Not(Or(x_1in , x_2in, x_3in)))
NOR3Def3=simplify(NOR3Def1) #DeMorgan equivlinacy
NOR3Def0, NOR3Def1, NOR3Def2, NOR3Def3

NOR3_TT=TruthTabelGenrator(NOR3Def0)
NOR3_TT

NOR3_DME_TT=TruthTabelGenrator(NOR3Def1)
NOR3_TT.equals(NOR3_DME_TT)

NOR3Def2N=lambdify((x_1in, x_2in, x_3in), NOR3Def2.rhs, dummify=False)
#Again WTH
#NOR3Def2N(False, False, False)

#DoNotTrust: pyNOR2Eq1=lambda x1, x2: ~(x1 | x2)
pyNOR2Eq2=lambda x1, x2: not(x1 or x2)
#DoNotTrust: pyNOR2Eq3=lambda x1, x2: ~x1 & ~x2
pyNOR2Eq4=lambda x1, x2: not x1 and not x2

#DoNotTrust: pyNOR3Eq1=lambda x1, x2, x3: ~(x1 | x2 | x3)
pyNOR3Eq2=lambda x1, x2, x3: not(x1 or x2 or x3)
#DoNotTrust: pyNOR3Eq3=lambda x1, x2, x3: ~x1 & ~x2 & ~x3
pyNOR3Eq4=lambda x1, x2, x3: not x1 and not x2 and not x3


pyNOR2Eq2(0,1), pyNOR2Eq4(1,0), pyNOR3Eq2(0,0,0), pyNOR3Eq4(1,0,1)

"""
Explanation: The following shows the Xilinx's Vivado 2016.1 RTL generated schematic of our myHDL three input NAND gate's verilog code
<img style="float: center;" src="Nand3GateRTLSch.PNG">
NOR
negated or, negated addition, product of negated inputs
Symbols
NOR Gate Definition
\begin{definition}\label{def:nor}
A NOR gate is a multi input single output logic gate that gives the negation of the sum of the boolean inputs at its output  and is thus the DeMorgan conjugate of the OR Gate
 $$y_{\text{out}}=\bar{\sum_{i=1}^{N\geq 2} x_{i\text{ in}}}=\prod_{i=1}^{N\geq 2} \bar{x_{i\text{ in}}}$$
In more compact notation it is represented as (for a 2-input):
 $$y_{\text{out}}=\bar{x_{1\text{ in} } + x_{2\text{ in} }}=\bar{x_{1\text{ in} }} \cdot \bar{x_{2\text{ in} }}$$
Which can also be written (as sympy does) as:
 $$y_{\text{out}}=\neg(x_{1\text{ in} }  \vee  x_{2\text{ in} })=\neg x_{1\text{ in} }  \wedge  \neg x_{2\text{ in} }$$
\end{definition}
NOR Gate in Sympy and Python
End of explanation
"""


#create a HDL Module (python function) and its I\O ports
def Nor2Gate(x_1in, x_2in, y_out):
    """AND Logic Gate myHDL Module (function)
    
    Args:
        x_1in: bool Input port
        x_2in: bool Input port
        y_out: bool Output port
    
    Returns:
        AND Combo logic operation
        
    """
    #define what this module is to do
    
    #myHDL built in decorator to say the function is exuiquated on each
    #clock cycle
    @always_comb
    def logic():
        y_out.next= not(x_1in or x_2in)
        
    return logic

#create the test signals and intilize value to both be false(0)
x_1in, x_2in, y_out=[Signal(bool(0)) for _ in range(3)]

#Peeker is helper libary for viewing wavefrom outputs and run the sim inside
#jupyter notebooks
#clear any previeese data loaded into peeker
Peeker.clear()

#load and name the signals to watch into peeker
Peeker(x_1in, 'x_1in'); Peeker(x_2in, 'x_2in')
Peeker(y_out, 'y_out')

#make an instatince of the NotGate as the DUT
DUT=Nor2Gate(x_1in=x_1in, x_2in=x_2in, y_out=y_out)

inputs=[x_1in, x_2in]

sim=Simulation(DUT, Combo_TB(inputs), *Peeker.instances()).run()        
Peeker.to_wavedrom(start_time=0, stop_time=2*2**len(inputs), tock=True,
                  title='NOR 2 gate simulation',
                  caption=f'after clock cycle {2**len(inputs)-1} ->random input')

MakeDFfromPeeker(Peeker.to_wavejson(start_time=0, stop_time=2**len(inputs) -1))

"""
Explanation: myHDL Two Input NOR Gate and Testing
End of explanation
"""


toVerilog(Nor2Gate, x_1in, x_2in, y_out)
#toVHDL(Nor2Gate, x_1in, x_2in y_out)
_=VerilogTextReader('Nor2Gate')

"""
Explanation: myHDL Two Input NOR Gate HDL Synthesis
End of explanation
"""


x_1in, x_2in, y_out=symbols('x_1in, x_2in, y_out')
XOR2Def0=Eq(y_out, Xor(x_1in, x_2in))
XOR2Def1=Eq(y_out, x_1in ^ x_2in)
XOR2Def2=Eq(y_out, ~x_1in&x_2in | x_1in& ~x_2in)
XOR2Def0, XOR2Def1, XOR2Def2, simplify_logic(XOR2Def2)

XOR2_TT=TruthTabelGenrator(XOR2Def0)
XOR2_TT

XOR2_TT2=TruthTabelGenrator(XOR2Def2)
XOR2_TT.equals(XOR2_TT2)

XOR2Def1N=lambdify((x_1in, x_2in), XOR2Def1, dummify=False)
#oh come on
#XOR2Def1N(0, 1)

pyXOR2Eq1=lambda x1, x2: x1^x2
pyXOR2Eq1(1, 1)

"""
Explanation: The following shows the Xilinx's Vivado 2016.1 RTL generated schematic of our myHDL two input NOR gate's verilog code
<img style="float: center;" src="Nor2GateRTLSch.PNG">
XOR
The Exclusive OR
Symbols
The Symbols for a XOR gate are show below
<img style="float: center;" src="XorGateDig.jpg">
XOR Gate Definition
need to come up with this
XOR Gate in Sympy and Python
End of explanation
"""


#create a HDL Module (python function) and its I\O ports
def Xor2Gate(x_1in, x_2in, y_out):
    """Or Logic Gate myHDL Module (function)
    
    Args:
        x_1in: bool Input port
        x_2in: bool Input port
        y_out: bool Output port
    
    Returns:
        XOR Combo logic operation
        
    """
    #define what this module is to do
    
    #myHDL built in decorator to say the function is exuiquated on each
    #clock cycle
    @always_comb
    def logic():
        y_out.next= x_1in ^ x_2in 
        
    return logic

#create the test signals and intilize value to both be false(0)
x_1in, x_2in, y_out=[Signal(bool(0)) for _ in range(3)]

#Peeker is helper libary for viewing wavefrom outputs and run the sim inside
#jupyter notebooks
#clear any previeese data loaded into peeker
Peeker.clear()

#load and name the signals to watch into peeker
Peeker(x_1in, 'x_1in'); Peeker(x_2in, 'x_2in')
Peeker(y_out, 'y_out')

#make an instatince of the NotGate as the DUT
DUT=Xor2Gate(x_1in=x_1in, x_2in=x_2in, y_out=y_out)

inputs=[x_1in, x_2in]

sim=Simulation(DUT, Combo_TB(inputs), *Peeker.instances()).run()        
Peeker.to_wavedrom(start_time=0, stop_time=2*2**len(inputs), tock=True,
                  title='XOR 2 gate simulation',
                  caption=f'after clock cycle {2**len(inputs)-1} ->random input')

MakeDFfromPeeker(Peeker.to_wavejson(start_time=0, stop_time=2**len(inputs) -1))

"""
Explanation: myHDL Two Input XOR Gate and Testing
End of explanation
"""


toVerilog(Xor2Gate, x_1in, x_2in, y_out)
#toVHDL(Xor2Gate, x_1in, x_2in y_out)
_=VerilogTextReader('Xor2Gate')

"""
Explanation: myHDL Two Input XOR gate HDL Synthesis
End of explanation
"""


x1, x2, x3, x4=symbols('x_1, x_2, x_3, x_4')
lits=[x1, x2, x3, x4]

terms=set(list(range(2**len(lits)))); terms

DCterms=set(list(range(10, 15+1))); DCterms

usableTerms=terms-DCterms; usableTerms

SOPfromUT=lambda POSterms: usableTerms-POSterms

aPOSterms={1,4}; aSOPterms=SOPfromUT(aPOSterms)
bPOSterms={5,6}; bSOPterms=SOPfromUT(bPOSterms)
cPOSterms={2}; cSOPterms=SOPfromUT(cPOSterms)
dPOSterms={2,4,7}; dSOPterms=SOPfromUT(dPOSterms)
ePOSterms={1,3,4,5,7,9}; eSOPterms=SOPfromUT(ePOSterms)
fPOSterms={1,2,3,7}; fSOPterms=SOPfromUT(fPOSterms)
gPOSterms={0,1,7}; gSOPterms=SOPfromUT(gPOSterms)


aSOP, aPOS=POS_SOPformCalcater(lits, aSOPterms, aPOSterms, DCterms)
bSOP, bPOS=POS_SOPformCalcater(lits, bSOPterms, bPOSterms, DCterms)
cSOP, cPOS=POS_SOPformCalcater(lits, cSOPterms, cPOSterms, DCterms)
dSOP, dPOS=POS_SOPformCalcater(lits, dSOPterms, dPOSterms, DCterms)
eSOP, ePOS=POS_SOPformCalcater(lits, eSOPterms, ePOSterms, DCterms)
fSOP, fPOS=POS_SOPformCalcater(lits, fSOPterms, fPOSterms, DCterms)
gSOP, gPOS=POS_SOPformCalcater(lits, gSOPterms, gPOSterms, DCterms)

aSOP, aPOS

bSOP, bPOS

cSOP, cPOS

dSOP, dPOS

eSOP, ePOS

fSOP, fPOS

gSOP, gPOS

"""
Explanation: The following shows the Xilinx's Vivado 2016.1 RTL generated schematic of our myHDL two input NOR gate's verilog code
!Need to add the RTL schematic
Min & Max Terms, SOP POS
KMaps
Examples of boolean expressions
Exsample of a 2 bit 7 Segment Display Logic Synthesis
End of explanation
"""


