Graphviz

Let's play around with the graphviz backend.

Shift register

Let's create a Shift register. This example is taken from the shift_register notebook.


In [1]:
import magma as m
m.set_mantle_target("ice40")
import mantle

N = 4
Register4 = mantle.DefineRegister(4)
T = m.Bits(N)

class ShiftRegister(m.Circuit):
    name = "ShiftRegister"
    IO = ["I", m.In(T), "O", m.Out(T), "CLK", m.In(m.Clock)]
    @classmethod
    def definition(io):
        regs = [Register4() for _ in range(N)]
        [m.wire(io.CLK, reg.CLK) for reg in regs]
        m.wire(io.I, getattr(regs[0], "I"))
        m.braid(regs, foldargs={"I":"O"})
        m.wire(regs[-1].O, io.O)


import lattice ice40
import lattice mantle40

If Python returns a Circuit in a jupyter notebook, the circuit is displayed using graphviz. Now let's visualize our ShiftRegister type.


In [2]:
ShiftRegister


Out[2]:
Register4 Register4(I: In(Bits(4)), O: Out(Bits(4)), CLK: In(Clock)) I I Out(Bits(4)) O O In(Bits(4)) CLK CLK Out(Clock) inst0 C D ff (inst0) SB_DFF Q CLK->inst0:C inst1 C D ff (inst1) SB_DFF Q CLK->inst1:C inst2 C D ff (inst2) SB_DFF Q CLK->inst2:C inst3 C D ff (inst3) SB_DFF Q CLK->inst3:C inst0_Q inst0_Q Out(Bit) [inst3_Q,inst2_Q,inst1_Q,inst0_Q] inst3_Q inst2_Q inst1_Q inst0_Q inst0_Q->[inst3_Q,inst2_Q,inst1_Q,inst0_Q]:inst0_Q inst1_Q inst1_Q Out(Bit) inst1_Q->[inst3_Q,inst2_Q,inst1_Q,inst0_Q]:inst1_Q inst2_Q inst2_Q Out(Bit) inst2_Q->[inst3_Q,inst2_Q,inst1_Q,inst0_Q]:inst2_Q inst3_Q inst3_Q Out(Bit) inst3_Q->[inst3_Q,inst2_Q,inst1_Q,inst0_Q]:inst3_Q inst0:Q->inst0_Q I[0] I[0] I[0]->inst0:D inst1:Q->inst1_Q I[1] I[1] I[1]->inst1:D inst2:Q->inst2_Q I[2] I[2] I[2]->inst2:D inst3:Q->inst3_Q I[3] I[3] I[3]->inst3:D [inst3_Q,inst2_Q,inst1_Q,inst0_Q]->O ShiftRegister ShiftRegister(I: In(Bits(4)), O: Out(Bits(4)), CLK: In(Clock)) I I Out(Bits(4)) inst0 I CLK regs[0] (inst0) Register4 O I->inst0:I O O In(Bits(4)) CLK CLK Out(Clock) CLK->inst0:CLK inst1 I CLK regs[1] (inst1) Register4 O CLK->inst1:CLK inst2 I CLK regs[2] (inst2) Register4 O CLK->inst2:CLK inst3 I CLK regs[3] (inst3) Register4 O CLK->inst3:CLK inst0_O inst0_O Out(Bits(4)) inst0_O->inst1:I inst1_O inst1_O Out(Bits(4)) inst1_O->inst2:I inst2_O inst2_O Out(Bits(4)) inst2_O->inst3:I inst3_O inst3_O Out(Bits(4)) inst3_O->O inst0:O->inst0_O inst1:O->inst1_O inst2:O->inst2_O inst3:O->inst3_O

Simple ALU

Another example, taken from the Chisel examples folder.


In [3]:
from functools import reduce

def one_hot_mux(conds, inputs):
    outputs = []
    for cond, inp in zip(conds, inputs):
        outputs.append(inp & m.uint([cond for _ in range(len(inp))]))
    return reduce(lambda x, y: x | y, outputs)


class SimpleALU(m.Circuit):
    name = "SimpleALU"
    IO = ["a", m.In(m.UInt(4)), "b", m.In(m.UInt(4)),
          "opcode", m.In(m.UInt(2)), "out", m.Out(m.UInt(4))]
    
    @classmethod
    def definition(io):
        is_op0 = io.opcode == m.uint(0, n=2)
        is_op1 = io.opcode == m.uint(1, n=2)
        is_op2 = io.opcode == m.uint(2, n=2)
        is_op3 = io.opcode == m.uint(3, n=2)
        op0_out = io.a + io.b
        op1_out = io.a - io.b
        op2_out = io.a
        op3_out = io.b
        m.wire(io.out, one_hot_mux([is_op0, is_op1, is_op2, is_op3], [op0_out, op1_out, op2_out, op3_out]))

In [4]:
SimpleALU


Out[4]:
EQ2 EQ2(I0: In(Bits(2)), I1: In(Bits(2)), O: Out(Bit)) I0 I0 Out(Bits(2)) I1 I1 Out(Bits(2)) O O In(Bit) inst0_O inst0_O Out(Bit) inst0_O->O I0[0] I0[0] inst0 I0 I1 I2 I3 inst0 SB_LUT4 O I0[0]->inst0:I0 inst0:O->inst0_O I1[0] I1[0] I1[0]->inst0:I1 I0[1] I0[1] I0[1]->inst0:I2 I1[1] I1[1] I1[1]->inst0:I3 FullAdder FullAdder(I0: In(Bit), I1: In(Bit), CIN: In(Bit), O: Out(Bit), COUT: Out(Bit)) I0 I0 Out(Bit) inst0 I0 I1 I2 I3 lut (inst0) SB_LUT4 O I0->inst0:I0 inst1 I0 I1 CI carry (inst1) SB_CARRY CO I0->inst1:I0 I1 I1 Out(Bit) I1->inst0:I1 I1->inst1:I1 CIN CIN Out(Bit) CIN->inst0:I2 CIN->inst1:CI O O In(Bit) COUT COUT In(Bit) inst0_O inst0_O Out(Bit) inst0_O->O inst1_CO inst1_CO Out(Bit) inst1_CO->COUT inst0:O->inst0_O 0 0 0->inst0:I3 inst1:CO->inst1_CO Add4 Add4(I0: In(Bits(4)), I1: In(Bits(4)), O: Out(Bits(4))) I0 I0 Out(Bits(4)) I1 I1 Out(Bits(4)) O O In(Bits(4)) inst0_O inst0_O Out(Bit) [inst3_O,inst2_O,inst1_O,inst0_O] inst3_O inst2_O inst1_O inst0_O inst0_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst0_O inst0_COUT inst0_COUT Out(Bit) inst1 I0 I1 CIN inst1 FullAdder O COUT inst0_COUT->inst1:CIN inst1_O inst1_O Out(Bit) inst1_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst1_O inst1_COUT inst1_COUT Out(Bit) inst2 I0 I1 CIN inst2 FullAdder O COUT inst1_COUT->inst2:CIN inst2_O inst2_O Out(Bit) inst2_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst2_O inst2_COUT inst2_COUT Out(Bit) inst3 I0 I1 CIN inst3 FullAdder O COUT inst2_COUT->inst3:CIN inst3_O inst3_O Out(Bit) inst3_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst3_O inst3_COUT inst3_COUT Out(Bit) I0[0] I0[0] inst0 I0 I1 CIN inst0 FullAdder O COUT I0[0]->inst0:I0 inst0:O->inst0_O inst0:COUT->inst0_COUT I1[0] I1[0] I1[0]->inst0:I1 0 0 0->inst0:CIN I0[1] I0[1] I0[1]->inst1:I0 inst1:O->inst1_O inst1:COUT->inst1_COUT I1[1] I1[1] I1[1]->inst1:I1 I0[2] I0[2] I0[2]->inst2:I0 inst2:O->inst2_O inst2:COUT->inst2_COUT I1[2] I1[2] I1[2]->inst2:I1 I0[3] I0[3] I0[3]->inst3:I0 inst3:O->inst3_O inst3:COUT->inst3_COUT I1[3] I1[3] I1[3]->inst3:I1 [inst3_O,inst2_O,inst1_O,inst0_O]->O Invert4 Invert4(I: In(Bits(4)), O: Out(Bits(4))) I I Out(Bits(4)) O O In(Bits(4)) inst0_O inst0_O Out(Bit) [inst3_O,inst2_O,inst1_O,inst0_O] inst3_O inst2_O inst1_O inst0_O inst0_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst0_O inst1_O inst1_O Out(Bit) inst1_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst1_O inst2_O inst2_O Out(Bit) inst2_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst2_O inst3_O inst3_O Out(Bit) inst3_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst3_O I[0] I[0] inst0 I0 I1 I2 I3 lut (inst0) SB_LUT4 O I[0]->inst0:I0 inst0:O->inst0_O 0 0 0->inst0:I1 0->inst0:I2 0->inst0:I3 inst1 I0 I1 I2 I3 lut (inst1) SB_LUT4 O 0->inst1:I1 0->inst1:I2 0->inst1:I3 inst2 I0 I1 I2 I3 lut (inst2) SB_LUT4 O 0->inst2:I1 0->inst2:I2 0->inst2:I3 inst3 I0 I1 I2 I3 lut (inst3) SB_LUT4 O 0->inst3:I1 0->inst3:I2 0->inst3:I3 I[1] I[1] I[1]->inst1:I0 inst1:O->inst1_O I[2] I[2] I[2]->inst2:I0 inst2:O->inst2_O I[3] I[3] I[3]->inst3:I0 inst3:O->inst3_O [inst3_O,inst2_O,inst1_O,inst0_O]->O Add4_CIN Add4_CIN(I0: In(Bits(4)), I1: In(Bits(4)), CIN: In(Bit), O: Out(Bits(4))) I0 I0 Out(Bits(4)) I1 I1 Out(Bits(4)) CIN CIN Out(Bit) inst0 I0 I1 CIN inst0 FullAdder O COUT CIN->inst0:CIN O O In(Bits(4)) inst0_O inst0_O Out(Bit) [inst3_O,inst2_O,inst1_O,inst0_O] inst3_O inst2_O inst1_O inst0_O inst0_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst0_O inst0_COUT inst0_COUT Out(Bit) inst1 I0 I1 CIN inst1 FullAdder O COUT inst0_COUT->inst1:CIN inst1_O inst1_O Out(Bit) inst1_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst1_O inst1_COUT inst1_COUT Out(Bit) inst2 I0 I1 CIN inst2 FullAdder O COUT inst1_COUT->inst2:CIN inst2_O inst2_O Out(Bit) inst2_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst2_O inst2_COUT inst2_COUT Out(Bit) inst3 I0 I1 CIN inst3 FullAdder O COUT inst2_COUT->inst3:CIN inst3_O inst3_O Out(Bit) inst3_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst3_O inst3_COUT inst3_COUT Out(Bit) I0[0] I0[0] I0[0]->inst0:I0 inst0:O->inst0_O inst0:COUT->inst0_COUT I1[0] I1[0] I1[0]->inst0:I1 I0[1] I0[1] I0[1]->inst1:I0 inst1:O->inst1_O inst1:COUT->inst1_COUT I1[1] I1[1] I1[1]->inst1:I1 I0[2] I0[2] I0[2]->inst2:I0 inst2:O->inst2_O inst2:COUT->inst2_COUT I1[2] I1[2] I1[2]->inst2:I1 I0[3] I0[3] I0[3]->inst3:I0 inst3:O->inst3_O inst3:COUT->inst3_COUT I1[3] I1[3] I1[3]->inst3:I1 [inst3_O,inst2_O,inst1_O,inst0_O]->O Sub4 Sub4(I0: In(Bits(4)), I1: In(Bits(4)), O: Out(Bits(4))) I0 I0 Out(Bits(4)) inst1 I0 I1 CIN add (inst1) Add4_CIN O I0->inst1:I0 I1 I1 Out(Bits(4)) inst0 I invert (inst0) Invert4 O I1->inst0:I O O In(Bits(4)) inst0_O inst0_O Out(Bits(4)) inst0_O->inst1:I1 inst1_O inst1_O Out(Bits(4)) inst1_O->O inst0:O->inst0_O inst1:O->inst1_O 1 1 1->inst1:CIN And2 And2(I: In(Bits(2)), O: Out(Bit)) I I Out(Bits(2)) O O In(Bit) inst0_O inst0_O Out(Bit) inst0_O->O I[0] I[0] inst0 I0 I1 I2 I3 lut (inst0) SB_LUT4 O I[0]->inst0:I0 inst0:O->inst0_O I[1] I[1] I[1]->inst0:I1 0 0 0->inst0:I2 0->inst0:I3 And2x4 And2x4(I0: In(Bits(4)), I1: In(Bits(4)), O: Out(Bits(4))) I0 I0 Out(Bits(4)) I1 I1 Out(Bits(4)) O O In(Bits(4)) inst0_O inst0_O Out(Bit) [inst3_O,inst2_O,inst1_O,inst0_O] inst3_O inst2_O inst1_O inst0_O inst0_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst0_O inst1_O inst1_O Out(Bit) inst1_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst1_O inst2_O inst2_O Out(Bit) inst2_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst2_O inst3_O inst3_O Out(Bit) inst3_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst3_O [I1[0],I0[0]] I1[0] I0[0] inst0 I inst0 And2 O [I1[0],I0[0]]->inst0:I I1[0] I1[0] I1[0]->[I1[0],I0[0]]:I1[0] I0[0] I0[0] I0[0]->[I1[0],I0[0]]:I0[0] inst0:O->inst0_O [I1[1],I0[1]] I1[1] I0[1] inst1 I inst1 And2 O [I1[1],I0[1]]->inst1:I I1[1] I1[1] I1[1]->[I1[1],I0[1]]:I1[1] I0[1] I0[1] I0[1]->[I1[1],I0[1]]:I0[1] inst1:O->inst1_O [I1[2],I0[2]] I1[2] I0[2] inst2 I inst2 And2 O [I1[2],I0[2]]->inst2:I I1[2] I1[2] I1[2]->[I1[2],I0[2]]:I1[2] I0[2] I0[2] I0[2]->[I1[2],I0[2]]:I0[2] inst2:O->inst2_O [I1[3],I0[3]] I1[3] I0[3] inst3 I inst3 And2 O [I1[3],I0[3]]->inst3:I I1[3] I1[3] I1[3]->[I1[3],I0[3]]:I1[3] I0[3] I0[3] I0[3]->[I1[3],I0[3]]:I0[3] inst3:O->inst3_O [inst3_O,inst2_O,inst1_O,inst0_O]->O Or2 Or2(I: In(Bits(2)), O: Out(Bit)) I I Out(Bits(2)) O O In(Bit) inst0_O inst0_O Out(Bit) inst0_O->O I[0] I[0] inst0 I0 I1 I2 I3 lut (inst0) SB_LUT4 O I[0]->inst0:I0 inst0:O->inst0_O I[1] I[1] I[1]->inst0:I1 0 0 0->inst0:I2 0->inst0:I3 Or2x4 Or2x4(I0: In(Bits(4)), I1: In(Bits(4)), O: Out(Bits(4))) I0 I0 Out(Bits(4)) I1 I1 Out(Bits(4)) O O In(Bits(4)) inst0_O inst0_O Out(Bit) [inst3_O,inst2_O,inst1_O,inst0_O] inst3_O inst2_O inst1_O inst0_O inst0_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst0_O inst1_O inst1_O Out(Bit) inst1_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst1_O inst2_O inst2_O Out(Bit) inst2_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst2_O inst3_O inst3_O Out(Bit) inst3_O->[inst3_O,inst2_O,inst1_O,inst0_O]:inst3_O [I1[0],I0[0]] I1[0] I0[0] inst0 I inst0 Or2 O [I1[0],I0[0]]->inst0:I I1[0] I1[0] I1[0]->[I1[0],I0[0]]:I1[0] I0[0] I0[0] I0[0]->[I1[0],I0[0]]:I0[0] inst0:O->inst0_O [I1[1],I0[1]] I1[1] I0[1] inst1 I inst1 Or2 O [I1[1],I0[1]]->inst1:I I1[1] I1[1] I1[1]->[I1[1],I0[1]]:I1[1] I0[1] I0[1] I0[1]->[I1[1],I0[1]]:I0[1] inst1:O->inst1_O [I1[2],I0[2]] I1[2] I0[2] inst2 I inst2 Or2 O [I1[2],I0[2]]->inst2:I I1[2] I1[2] I1[2]->[I1[2],I0[2]]:I1[2] I0[2] I0[2] I0[2]->[I1[2],I0[2]]:I0[2] inst2:O->inst2_O [I1[3],I0[3]] I1[3] I0[3] inst3 I inst3 Or2 O [I1[3],I0[3]]->inst3:I I1[3] I1[3] I1[3]->[I1[3],I0[3]]:I1[3] I0[3] I0[3] I0[3]->[I1[3],I0[3]]:I0[3] inst3:O->inst3_O [inst3_O,inst2_O,inst1_O,inst0_O]->O SimpleALU SimpleALU(a: In(UInt(4)), b: In(UInt(4)), opcode: In(UInt(2)), out: Out(UInt(4))) a a Out(UInt(4)) inst4 I0 I1 inst4 Add4 O a->inst4:I0 inst5 I0 I1 inst5 Sub4 O a->inst5:I0 inst8 I0 I1 inst8 And2x4 O a->inst8:I0 b b Out(UInt(4)) b->inst4:I1 b->inst5:I1 inst9 I0 I1 inst9 And2x4 O b->inst9:I0 opcode opcode Out(UInt(2)) inst0 I0 I1 inst0 EQ2 O opcode->inst0:I0 inst1 I0 I1 inst1 EQ2 O opcode->inst1:I0 inst2 I0 I1 inst2 EQ2 O opcode->inst2:I0 inst3 I0 I1 inst3 EQ2 O opcode->inst3:I0 out out In(UInt(4)) inst0_O inst0_O Out(Bit) [inst0_O,inst0_O,inst0_O,inst0_O] inst0_O inst0_O inst0_O inst0_O inst0_O->[inst0_O,inst0_O,inst0_O,inst0_O]:inst0_O inst0_O->[inst0_O,inst0_O,inst0_O,inst0_O]:inst0_O inst0_O->[inst0_O,inst0_O,inst0_O,inst0_O]:inst0_O inst0_O->[inst0_O,inst0_O,inst0_O,inst0_O]:inst0_O inst1_O inst1_O Out(Bit) [inst1_O,inst1_O,inst1_O,inst1_O] inst1_O inst1_O inst1_O inst1_O inst1_O->[inst1_O,inst1_O,inst1_O,inst1_O]:inst1_O inst1_O->[inst1_O,inst1_O,inst1_O,inst1_O]:inst1_O inst1_O->[inst1_O,inst1_O,inst1_O,inst1_O]:inst1_O inst1_O->[inst1_O,inst1_O,inst1_O,inst1_O]:inst1_O inst2_O inst2_O Out(Bit) [inst2_O,inst2_O,inst2_O,inst2_O] inst2_O inst2_O inst2_O inst2_O inst2_O->[inst2_O,inst2_O,inst2_O,inst2_O]:inst2_O inst2_O->[inst2_O,inst2_O,inst2_O,inst2_O]:inst2_O inst2_O->[inst2_O,inst2_O,inst2_O,inst2_O]:inst2_O inst2_O->[inst2_O,inst2_O,inst2_O,inst2_O]:inst2_O inst3_O inst3_O Out(Bit) [inst3_O,inst3_O,inst3_O,inst3_O] inst3_O inst3_O inst3_O inst3_O inst3_O->[inst3_O,inst3_O,inst3_O,inst3_O]:inst3_O inst3_O->[inst3_O,inst3_O,inst3_O,inst3_O]:inst3_O inst3_O->[inst3_O,inst3_O,inst3_O,inst3_O]:inst3_O inst3_O->[inst3_O,inst3_O,inst3_O,inst3_O]:inst3_O inst4_O inst4_O Out(Bits(4)) inst6 I0 I1 inst6 And2x4 O inst4_O->inst6:I0 inst5_O inst5_O Out(Bits(4)) inst7 I0 I1 inst7 And2x4 O inst5_O->inst7:I0 inst6_O inst6_O Out(Bits(4)) inst10 I0 I1 inst10 Or2x4 O inst6_O->inst10:I0 inst7_O inst7_O Out(Bits(4)) inst7_O->inst10:I1 inst8_O inst8_O Out(Bits(4)) inst11 I0 I1 inst11 Or2x4 O inst8_O->inst11:I1 inst9_O inst9_O Out(Bits(4)) inst12 I0 I1 inst12 Or2x4 O inst9_O->inst12:I1 inst10_O inst10_O Out(Bits(4)) inst10_O->inst11:I0 inst11_O inst11_O Out(Bits(4)) inst11_O->inst12:I0 inst12_O inst12_O Out(Bits(4)) inst12_O->out inst0:O->inst0_O [0,0] 0 0 [0,0]->inst0:I1 0 0 0->[0,0]:0 0->[0,0]:0 [0,1] 0 1 0->[0,1]:0 [1,0] 1 0 0->[1,0]:0 inst1:O->inst1_O [0,1]->inst1:I1 1 1 1->[0,1]:1 1->[1,0]:1 [1,1] 1 1 1->[1,1]:1 1->[1,1]:1 inst2:O->inst2_O [1,0]->inst2:I1 inst3:O->inst3_O [1,1]->inst3:I1 inst4:O->inst4_O inst5:O->inst5_O inst6:O->inst6_O [inst0_O,inst0_O,inst0_O,inst0_O]->inst6:I1 inst7:O->inst7_O [inst1_O,inst1_O,inst1_O,inst1_O]->inst7:I1 inst8:O->inst8_O [inst2_O,inst2_O,inst2_O,inst2_O]->inst8:I1 inst9:O->inst9_O [inst3_O,inst3_O,inst3_O,inst3_O]->inst9:I1 inst10:O->inst10_O inst11:O->inst11_O inst12:O->inst12_O