Module circuitgraph.logic

A collection of common logic elements as Circuit objects

Expand source code
"""A collection of common logic elements as `Circuit` objects"""

from itertools import product

from circuitgraph import Circuit
from circuitgraph.utils import clog2


def adder(w):
    """
    Create an adder.

    Parameters
    ----------
    w : int
            Input width of adder.

    Returns
    -------
    Circuit
            Adder circuit.
    """
    c = Circuit(name="adder")
    carry = c.add("null", "0")
    for i in range(w):
        # sum
        c.add(f"a_{i}", "input")
        c.add(f"b_{i}", "input")
        c.add(f"sum_{i}", "xor", fanin=[f"a_{i}", f"b_{i}", carry])
        c.add(f"out_{i}", "output", fanin=f"sum_{i}")

        # carry
        c.add(f"and_ab_{i}", "and", fanin=[f"a_{i}", f"b_{i}"])
        c.add(f"and_ac_{i}", "and", fanin=[f"a_{i}", carry])
        c.add(f"and_bc_{i}", "and", fanin=[f"b_{i}", carry])
        carry = c.add(
            f"carry_{i}", "or", fanin=[f"and_ab_{i}", f"and_ac_{i}", f"and_bc_{i}"],
        )

    c.add(f"out_{w}", "output", fanin=carry)
    return c


def mux(w):
    """
    Create a mux.

    Parameters
    ----------
    w : int
            Input width of the mux.

    Returns
    -------
    Circuit
            Mux circuit.
    """
    c = Circuit(name="mux")

    # create inputs
    for i in range(w):
        c.add(f"in_{i}", "input")
    sels = []
    for i in range(clog2(w)):
        c.add(f"sel_{i}", "input")
        c.add(f"not_sel_{i}", "not", fanin=f"sel_{i}")
        sels.append([f"not_sel_{i}", f"sel_{i}"])

    # create output or
    c.add("or", "or")
    c.add("out", "output", fanin="or")

    i = 0
    for sel in product(*sels[::-1]):
        c.add(f"and_{i}", "and", fanin=[*sel, f"in_{i}"], fanout="or")

        i += 1
        if i == w:
            break

    return c


def popcount(w):
    """
    Create a population count circuit.

    Parameters
    ----------
    w : int
            Input width of the circuit.

    Returns
    -------
    Circuit
            Population count circuit.
    """
    c = Circuit(name="popcount")
    ps = [[c.add(f"in_{i}", "input")] for i in range(w)]

    i = 0
    while len(ps) > 1:
        # get values
        ns = ps.pop(0)
        ms = ps.pop(0)

        # pad
        aw = max(len(ns), len(ms))
        while len(ms) < aw:
            ms += ["null"]
        while len(ns) < aw:
            ns += ["null"]

        # instantiate and connect adder
        c.add_subcircuit(adder(aw), f"add_{i}")
        for j, (n, m) in enumerate(zip(ns, ms)):
            c.connect(n, f"add_{i}_a_{j}")
            c.connect(m, f"add_{i}_b_{j}")

        # add adder outputs
        ps.append([f"add_{i}_out_{j}" for j in range(aw + 1)])
        i += 1

    # connect outputs
    for i, o in enumerate(ps[0]):
        c.add(f"out_{i}", "output", fanin=o)

    if "null" in c:
        c.set_type("null", "0")

    return c


# def comb_lat():
#    """
#    Combinational model of a latch.
#
#    Returns
#    -------
#    Circuit
#            Latch model circuit.
#    """
#    lm = Circuit(name="lat")
#
#    # mux
#    m = strip_io(mux(2))
#    lm.extend(m, {n: f"mux_{n}" for n in m.nodes()})
#
#    # inputs
#    lm.add("si", "input", fanout="mux_in_0")
#    lm.add("d", "input", fanout="mux_in_1")
#    lm.add("clk", "input", fanout="mux_sel_0")
#    lm.add("r", "input")
#    lm.add("s", "input")
#
#    # logic
#    lm.add("r_b", "not", fanin="r")
#    lm.add("qr", "and", fanin=["mux_out", "r_b"])
#    lm.add("q", "or", fanin=["qr", "s"], output=True)
#    lm.add("so", "buf", fanin="q", output=True)
#
#    return lm
#
#
# def comb_ff():
#    """
#    Combinational model of a flip-flop.
#
#    Returns
#    -------
#    Circuit
#            Flip-flop model circuit.
#    """
#    fm = Circuit(name="ff")
#
#    # mux
#    m = strip_io(mux(2))
#    fm.extend(m, {n: f"mux_{n}" for n in m.nodes()})
#
#    # inputs
#    fm.add("si", "input", fanout="mux_in_1")
#    fm.add("d", "input", fanout="mux_in_0")
#    fm.add("clk", "input", fanout="mux_sel_0")
#    fm.add("r", "input")
#    fm.add("s", "input")
#
#    # logic
#    fm.add("r_b", "not", fanin="r")
#    fm.add("qr", "and", fanin=["si", "r_b"])
#    fm.add("q", "or", fanin=["qr", "s"], output=True)
#    fm.add("so", "buf", fanin="mux_out", output=True)
#
#    return fm

Functions

def adder(w)

Create an adder.

Parameters

w : int
Input width of adder.

Returns

Circuit
Adder circuit.
Expand source code
def adder(w):
    """
    Create an adder.

    Parameters
    ----------
    w : int
            Input width of adder.

    Returns
    -------
    Circuit
            Adder circuit.
    """
    c = Circuit(name="adder")
    carry = c.add("null", "0")
    for i in range(w):
        # sum
        c.add(f"a_{i}", "input")
        c.add(f"b_{i}", "input")
        c.add(f"sum_{i}", "xor", fanin=[f"a_{i}", f"b_{i}", carry])
        c.add(f"out_{i}", "output", fanin=f"sum_{i}")

        # carry
        c.add(f"and_ab_{i}", "and", fanin=[f"a_{i}", f"b_{i}"])
        c.add(f"and_ac_{i}", "and", fanin=[f"a_{i}", carry])
        c.add(f"and_bc_{i}", "and", fanin=[f"b_{i}", carry])
        carry = c.add(
            f"carry_{i}", "or", fanin=[f"and_ab_{i}", f"and_ac_{i}", f"and_bc_{i}"],
        )

    c.add(f"out_{w}", "output", fanin=carry)
    return c
def mux(w)

Create a mux.

Parameters

w : int
Input width of the mux.

Returns

Circuit
Mux circuit.
Expand source code
def mux(w):
    """
    Create a mux.

    Parameters
    ----------
    w : int
            Input width of the mux.

    Returns
    -------
    Circuit
            Mux circuit.
    """
    c = Circuit(name="mux")

    # create inputs
    for i in range(w):
        c.add(f"in_{i}", "input")
    sels = []
    for i in range(clog2(w)):
        c.add(f"sel_{i}", "input")
        c.add(f"not_sel_{i}", "not", fanin=f"sel_{i}")
        sels.append([f"not_sel_{i}", f"sel_{i}"])

    # create output or
    c.add("or", "or")
    c.add("out", "output", fanin="or")

    i = 0
    for sel in product(*sels[::-1]):
        c.add(f"and_{i}", "and", fanin=[*sel, f"in_{i}"], fanout="or")

        i += 1
        if i == w:
            break

    return c
def popcount(w)

Create a population count circuit.

Parameters

w : int
Input width of the circuit.

Returns

Circuit
Population count circuit.
Expand source code
def popcount(w):
    """
    Create a population count circuit.

    Parameters
    ----------
    w : int
            Input width of the circuit.

    Returns
    -------
    Circuit
            Population count circuit.
    """
    c = Circuit(name="popcount")
    ps = [[c.add(f"in_{i}", "input")] for i in range(w)]

    i = 0
    while len(ps) > 1:
        # get values
        ns = ps.pop(0)
        ms = ps.pop(0)

        # pad
        aw = max(len(ns), len(ms))
        while len(ms) < aw:
            ms += ["null"]
        while len(ns) < aw:
            ns += ["null"]

        # instantiate and connect adder
        c.add_subcircuit(adder(aw), f"add_{i}")
        for j, (n, m) in enumerate(zip(ns, ms)):
            c.connect(n, f"add_{i}_a_{j}")
            c.connect(m, f"add_{i}_b_{j}")

        # add adder outputs
        ps.append([f"add_{i}_out_{j}" for j in range(aw + 1)])
        i += 1

    # connect outputs
    for i, o in enumerate(ps[0]):
        c.add(f"out_{i}", "output", fanin=o)

    if "null" in c:
        c.set_type("null", "0")

    return c