This example demonstrates how to construct FSM's in magma using the combinational circuit definition.

UART

UART is a serialization/deserialization protocol. It consists of a transmitter circuit and reciever circuit. Let's take a look at a verilog implementation of the transmitter circuit.

module TXMOD(
  output TX,
  input CLK,
  input [7:0] data,
  input valid,
  output ready);

reg TXReg = 1;
assign TX = TXReg;

reg [10:0] dataStore = 1536; // MSB=1, LSB=0
reg writing = 0;
assign ready = (writing==0);

reg [13:0] writeClock = 0; // which cycle are we in?
reg [3:0] writeBit = 0; // which bit are we writing? (10 bits total)

always @(posedge CLK) begin
  if(writing==0 && valid==1) begin
    writing <= 1;
    dataStore[8:1] <= data;
    writeClock <= 100;
    writeBit <= 0;
    TXReg <= dataStore[0];
  end else if(writing==1 && writeClock==0 && writeBit==9) begin
    // we're done
    TXReg <= 1;
    writing <= 0;
  end else if(writing==1 && writeClock==0) begin
    // move on to next bit
    TXReg <= dataStore[writeBit];
    writeBit <= writeBit+1;
    writeClock <= 100;
  end else if(writing==1) begin
    TXReg <= dataStore[writeBit];
    writeClock <= writeClock - 1;
  end else begin
    TXReg <= 1;
  end 

end

endmodule

We can see that it is essentially a simple FSM. Using magma's circuit.combinational we can replicate this functionality.


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


@m.circuit.combinational
def txmod_logic(
        data : m.Bits(8),
        writing : m.Bit,
        valid : m.Bit,
        dataStore : m.Bits(11),
        writeClock : m.Bits(14),
        writeBit : m.Bits(4),) -> (m.Bit,
                                   m.Bits(11),
                                   m.Bits(14),
                                   m.Bits(4),
                                   m.Bit,):

    if (writing == m.bit(0)) & (valid == m.bit(1)):
        writing_out = m.bit(1)
        dataStore_out = m.concat(dataStore[0:1], data, dataStore[9:])
        writeClock_out = m.bits(100, 14)
        writeBit_out = m.bits(0, 4)
        TXReg_out = dataStore[0]
    elif (writing == m.bit(1)) & \
         (writeClock == m.bits(0, 14)) & \
         (writeBit == m.bits(9, 4)):
        dataStore_out = dataStore
        writeClock_out = writeClock
        writeBit_out = writeBit
        TXReg_out = m.bit(1)
        writing_out = m.bit(0)
    elif (writing == m.bit(1)) & (writeClock == m.bits(0, 14)):
        writing_out = writing
        dataStore_out = dataStore
        TXReg_out = dataStore[writeBit]
        writeBit_out = m.bits(m.uint(writeBit) + m.bits(1, 4))
        writeClock_out = m.bits(100, 14)
    elif writing == m.bit(1):
        writing_out = writing
        dataStore_out = dataStore
        writeBit_out = writeBit
        TXReg_out = dataStore[writeBit]
        writeClock_out = m.bits(m.uint(writeClock) - m.bits(1, 14))
    else:
        writing_out = writing
        dataStore_out = dataStore
        writeClock_out = writeClock
        writeBit_out = writeBit
        TXReg_out = m.bit(1)

    return (writing_out,
            dataStore_out,
            writeClock_out,
            writeBit_out,
            TXReg_out,)


class TXMOD(m.Circuit):
    IO = ["TX", m.Out(m.Bit),
          "data", m.In(m.Bits(8)),
          "valid", m.In(m.Bit),
          "ready", m.Out(m.Bit),
          "CLK", m.In(m.Clock),]

    @classmethod
    def definition(io):
        TXReg = Register(1, init=1)
        dataStore = Register(11, init=1536)
        writing = Register(1, init=0)
        writeClock = Register(14, init=0)
        writeBit = Register(4, init=0)
        (writing_next,
         dataStore_next,
         writeClock_next,
         writeBit_next,
         TXReg_next,) = txmod_logic(io.data,
                                   writing.O[0],
                                   io.valid,
                                   dataStore.O,
                                   writeClock.O,
                                   writeBit.O)
        m.wire(writing_next, writing.I[0])
        m.wire(dataStore_next, dataStore.I)
        m.wire(writeClock_next, writeClock.I)
        m.wire(writeBit_next, writeBit.I)
        m.wire(TXReg_next, TXReg.I[0])
        ready = writing.O[0] == m.bit(0)
        m.wire(ready, io.ready)
        m.wire(TXReg.O[0], io.TX)


import lattice ice40
import lattice mantle40

We replicate the functionality by splitting up the logic into a purely combinational part and a stateful part. The function txmod_logic() which is decorated with m.circuit.combinational, is converted into a combinational circuit which describes the next state as a function of the current state.

Limitations

Note that circuit.combinational has some limitations. First, default values for outputs is not supported, therefore each output must be set in each if/else-if/else block. This adds many more lines of code compared to the verilog version. Also, temporaries and over-writing/reusing variables within the combinational function is not supported. This limits the readability and compactness of the code.

Using the TXMOD circuit

We can now use the TXMOD circuit with the ice stick. We will first do this using the verilog implementations (see txmod.v, rxmod.v, and uart_main.v). The main circuit reads in a stream of characters and returns the same stream offset by 10 (i.e. +10 in ascii).

Note that here and below, you may need to do some setup to get the icesticks working, see the previous tutorials for directions. Also, you may need to replace /dev/tty.usbserial-14101 with the actual path of your mounted icestick, wherever it appears below.


In [2]:
%%bash
make clean && make uart_main.run


\rm -rf out/*
mkdir -p out
yosys -q -p 'synth_ice40 -top main -blif out/uart_main.blif' txmod.v rxmod.v uart_main.v
arachne-pnr -q -d 1k -o out/uart_main_pnr.txt -p ice40.pcf out/uart_main.blif
icepack out/uart_main_pnr.txt out/uart_main.bin
iceprog out/uart_main.bin
rm out/uart_main_pnr.txt out/uart_main.blif
Warning: Resizing cell port main.txmod.data from 32 bits to 8 bits.
init..
cdone: high
reset..
cdone: low
flash ID: 0x20 0xBA 0x16 0x10 0x00 0x00 0x23 0x51 0x73 0x10 0x23 0x00 0x35 0x00 0x35 0x06 0x06 0x15 0x43 0xB6
file size: 32220
erase 64kB sector at 0x000000..
programming..
reading..
VERIFY OK
cdone: high
Bye.

In [3]:
%%bash
python uart_driver.py infile outfile /dev/tty.usbserial-14101


Running with infile=infile, outfile=outfile
infile length=12

In [4]:
%cat outfile


rovvy*�y|vn

Now let's replace the verilog version with the magma version of the TXMOD circuit (which will overwrite txmod.v).


In [5]:
%%bash
python txmod.py


import lattice ice40
import lattice mantle40

In [6]:
m.compile("txmod", TXMOD, output="verilog")

In [7]:
%cat txmod.v


module Register1_0001 (input [0:0] I, output [0:0] O, input  CLK);
wire  inst0_Q;
wire  inst1_O;
wire  inst2_O;
SB_DFF inst0 (.C(CLK), .D(inst1_O), .Q(inst0_Q));
SB_LUT4 #(.LUT_INIT(16'h5555)) inst1 (.I0(I[0]), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst1_O));
SB_LUT4 #(.LUT_INIT(16'h5555)) inst2 (.I0(inst0_Q), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst2_O));
assign O = {inst2_O};
endmodule

module Register11_0600 (input [10:0] I, output [10:0] O, input  CLK);
wire  inst0_Q;
wire  inst1_Q;
wire  inst2_Q;
wire  inst3_Q;
wire  inst4_Q;
wire  inst5_Q;
wire  inst6_Q;
wire  inst7_Q;
wire  inst8_Q;
wire  inst9_Q;
wire  inst10_O;
wire  inst11_O;
wire  inst12_Q;
wire  inst13_O;
wire  inst14_O;
SB_DFF inst0 (.C(CLK), .D(I[0]), .Q(inst0_Q));
SB_DFF inst1 (.C(CLK), .D(I[1]), .Q(inst1_Q));
SB_DFF inst2 (.C(CLK), .D(I[2]), .Q(inst2_Q));
SB_DFF inst3 (.C(CLK), .D(I[3]), .Q(inst3_Q));
SB_DFF inst4 (.C(CLK), .D(I[4]), .Q(inst4_Q));
SB_DFF inst5 (.C(CLK), .D(I[5]), .Q(inst5_Q));
SB_DFF inst6 (.C(CLK), .D(I[6]), .Q(inst6_Q));
SB_DFF inst7 (.C(CLK), .D(I[7]), .Q(inst7_Q));
SB_DFF inst8 (.C(CLK), .D(I[8]), .Q(inst8_Q));
SB_DFF inst9 (.C(CLK), .D(inst10_O), .Q(inst9_Q));
SB_LUT4 #(.LUT_INIT(16'h5555)) inst10 (.I0(I[9]), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst10_O));
SB_LUT4 #(.LUT_INIT(16'h5555)) inst11 (.I0(inst9_Q), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst11_O));
SB_DFF inst12 (.C(CLK), .D(inst13_O), .Q(inst12_Q));
SB_LUT4 #(.LUT_INIT(16'h5555)) inst13 (.I0(I[10]), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst13_O));
SB_LUT4 #(.LUT_INIT(16'h5555)) inst14 (.I0(inst12_Q), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst14_O));
assign O = {inst14_O,inst11_O,inst8_Q,inst7_Q,inst6_Q,inst5_Q,inst4_Q,inst3_Q,inst2_Q,inst1_Q,inst0_Q};
endmodule

module Register1 (input [0:0] I, output [0:0] O, input  CLK);
wire  inst0_Q;
SB_DFF inst0 (.C(CLK), .D(I[0]), .Q(inst0_Q));
assign O = {inst0_Q};
endmodule

module Register14 (input [13:0] I, output [13:0] O, input  CLK);
wire  inst0_Q;
wire  inst1_Q;
wire  inst2_Q;
wire  inst3_Q;
wire  inst4_Q;
wire  inst5_Q;
wire  inst6_Q;
wire  inst7_Q;
wire  inst8_Q;
wire  inst9_Q;
wire  inst10_Q;
wire  inst11_Q;
wire  inst12_Q;
wire  inst13_Q;
SB_DFF inst0 (.C(CLK), .D(I[0]), .Q(inst0_Q));
SB_DFF inst1 (.C(CLK), .D(I[1]), .Q(inst1_Q));
SB_DFF inst2 (.C(CLK), .D(I[2]), .Q(inst2_Q));
SB_DFF inst3 (.C(CLK), .D(I[3]), .Q(inst3_Q));
SB_DFF inst4 (.C(CLK), .D(I[4]), .Q(inst4_Q));
SB_DFF inst5 (.C(CLK), .D(I[5]), .Q(inst5_Q));
SB_DFF inst6 (.C(CLK), .D(I[6]), .Q(inst6_Q));
SB_DFF inst7 (.C(CLK), .D(I[7]), .Q(inst7_Q));
SB_DFF inst8 (.C(CLK), .D(I[8]), .Q(inst8_Q));
SB_DFF inst9 (.C(CLK), .D(I[9]), .Q(inst9_Q));
SB_DFF inst10 (.C(CLK), .D(I[10]), .Q(inst10_Q));
SB_DFF inst11 (.C(CLK), .D(I[11]), .Q(inst11_Q));
SB_DFF inst12 (.C(CLK), .D(I[12]), .Q(inst12_Q));
SB_DFF inst13 (.C(CLK), .D(I[13]), .Q(inst13_Q));
assign O = {inst13_Q,inst12_Q,inst11_Q,inst10_Q,inst9_Q,inst8_Q,inst7_Q,inst6_Q,inst5_Q,inst4_Q,inst3_Q,inst2_Q,inst1_Q,inst0_Q};
endmodule

module Register4 (input [3:0] I, output [3:0] O, input  CLK);
wire  inst0_Q;
wire  inst1_Q;
wire  inst2_Q;
wire  inst3_Q;
SB_DFF inst0 (.C(CLK), .D(I[0]), .Q(inst0_Q));
SB_DFF inst1 (.C(CLK), .D(I[1]), .Q(inst1_Q));
SB_DFF inst2 (.C(CLK), .D(I[2]), .Q(inst2_Q));
SB_DFF inst3 (.C(CLK), .D(I[3]), .Q(inst3_Q));
assign O = {inst3_Q,inst2_Q,inst1_Q,inst0_Q};
endmodule

module EQNone (input  I0, input  I1, output  O);
wire  inst0_O;
SB_LUT4 #(.LUT_INIT(16'h9999)) inst0 (.I0(I0), .I1(I1), .I2(1'b0), .I3(1'b0), .O(inst0_O));
assign O = inst0_O;
endmodule

module Mux2 (input [1:0] I, input  S, output  O);
wire  inst0_O;
SB_LUT4 #(.LUT_INIT(16'hCACA)) inst0 (.I0(I[0]), .I1(I[1]), .I2(S), .I3(1'b0), .O(inst0_O));
assign O = inst0_O;
endmodule

module EQ14 (input [13:0] I0, input [13:0] I1, output  O);
wire  inst0_O;
wire  inst1_O;
wire  inst2_O;
wire  inst3_O;
wire  inst4_O;
wire  inst5_O;
wire  inst6_O;
wire  inst7_O;
wire  inst8_O;
wire  inst9_O;
wire  inst10_O;
wire  inst11_O;
wire  inst12_O;
wire  inst13_O;
SB_LUT4 #(.LUT_INIT(16'h8282)) inst0 (.I0(1'b1), .I1(I0[0]), .I2(I1[0]), .I3(1'b0), .O(inst0_O));
SB_LUT4 #(.LUT_INIT(16'h8282)) inst1 (.I0(inst0_O), .I1(I0[1]), .I2(I1[1]), .I3(1'b0), .O(inst1_O));
SB_LUT4 #(.LUT_INIT(16'h8282)) inst2 (.I0(inst1_O), .I1(I0[2]), .I2(I1[2]), .I3(1'b0), .O(inst2_O));
SB_LUT4 #(.LUT_INIT(16'h8282)) inst3 (.I0(inst2_O), .I1(I0[3]), .I2(I1[3]), .I3(1'b0), .O(inst3_O));
SB_LUT4 #(.LUT_INIT(16'h8282)) inst4 (.I0(inst3_O), .I1(I0[4]), .I2(I1[4]), .I3(1'b0), .O(inst4_O));
SB_LUT4 #(.LUT_INIT(16'h8282)) inst5 (.I0(inst4_O), .I1(I0[5]), .I2(I1[5]), .I3(1'b0), .O(inst5_O));
SB_LUT4 #(.LUT_INIT(16'h8282)) inst6 (.I0(inst5_O), .I1(I0[6]), .I2(I1[6]), .I3(1'b0), .O(inst6_O));
SB_LUT4 #(.LUT_INIT(16'h8282)) inst7 (.I0(inst6_O), .I1(I0[7]), .I2(I1[7]), .I3(1'b0), .O(inst7_O));
SB_LUT4 #(.LUT_INIT(16'h8282)) inst8 (.I0(inst7_O), .I1(I0[8]), .I2(I1[8]), .I3(1'b0), .O(inst8_O));
SB_LUT4 #(.LUT_INIT(16'h8282)) inst9 (.I0(inst8_O), .I1(I0[9]), .I2(I1[9]), .I3(1'b0), .O(inst9_O));
SB_LUT4 #(.LUT_INIT(16'h8282)) inst10 (.I0(inst9_O), .I1(I0[10]), .I2(I1[10]), .I3(1'b0), .O(inst10_O));
SB_LUT4 #(.LUT_INIT(16'h8282)) inst11 (.I0(inst10_O), .I1(I0[11]), .I2(I1[11]), .I3(1'b0), .O(inst11_O));
SB_LUT4 #(.LUT_INIT(16'h8282)) inst12 (.I0(inst11_O), .I1(I0[12]), .I2(I1[12]), .I3(1'b0), .O(inst12_O));
SB_LUT4 #(.LUT_INIT(16'h8282)) inst13 (.I0(inst12_O), .I1(I0[13]), .I2(I1[13]), .I3(1'b0), .O(inst13_O));
assign O = inst13_O;
endmodule

module And2 (input [1:0] I, output  O);
wire  inst0_O;
SB_LUT4 #(.LUT_INIT(16'h8888)) inst0 (.I0(I[0]), .I1(I[1]), .I2(1'b0), .I3(1'b0), .O(inst0_O));
assign O = inst0_O;
endmodule

module EQ4 (input [3:0] I0, input [3:0] I1, output  O);
wire  inst0_O;
wire  inst1_O;
wire  inst2_O;
wire  inst3_O;
SB_LUT4 #(.LUT_INIT(16'h8282)) inst0 (.I0(1'b1), .I1(I0[0]), .I2(I1[0]), .I3(1'b0), .O(inst0_O));
SB_LUT4 #(.LUT_INIT(16'h8282)) inst1 (.I0(inst0_O), .I1(I0[1]), .I2(I1[1]), .I3(1'b0), .O(inst1_O));
SB_LUT4 #(.LUT_INIT(16'h8282)) inst2 (.I0(inst1_O), .I1(I0[2]), .I2(I1[2]), .I3(1'b0), .O(inst2_O));
SB_LUT4 #(.LUT_INIT(16'h8282)) inst3 (.I0(inst2_O), .I1(I0[3]), .I2(I1[3]), .I3(1'b0), .O(inst3_O));
assign O = inst3_O;
endmodule

module Mux2x11 (input [10:0] I0, input [10:0] I1, input  S, output [10:0] O);
wire  inst0_O;
wire  inst1_O;
wire  inst2_O;
wire  inst3_O;
wire  inst4_O;
wire  inst5_O;
wire  inst6_O;
wire  inst7_O;
wire  inst8_O;
wire  inst9_O;
wire  inst10_O;
Mux2 inst0 (.I({I1[0],I0[0]}), .S(S), .O(inst0_O));
Mux2 inst1 (.I({I1[1],I0[1]}), .S(S), .O(inst1_O));
Mux2 inst2 (.I({I1[2],I0[2]}), .S(S), .O(inst2_O));
Mux2 inst3 (.I({I1[3],I0[3]}), .S(S), .O(inst3_O));
Mux2 inst4 (.I({I1[4],I0[4]}), .S(S), .O(inst4_O));
Mux2 inst5 (.I({I1[5],I0[5]}), .S(S), .O(inst5_O));
Mux2 inst6 (.I({I1[6],I0[6]}), .S(S), .O(inst6_O));
Mux2 inst7 (.I({I1[7],I0[7]}), .S(S), .O(inst7_O));
Mux2 inst8 (.I({I1[8],I0[8]}), .S(S), .O(inst8_O));
Mux2 inst9 (.I({I1[9],I0[9]}), .S(S), .O(inst9_O));
Mux2 inst10 (.I({I1[10],I0[10]}), .S(S), .O(inst10_O));
assign O = {inst10_O,inst9_O,inst8_O,inst7_O,inst6_O,inst5_O,inst4_O,inst3_O,inst2_O,inst1_O,inst0_O};
endmodule

module Invert14 (input [13:0] I, output [13:0] O);
wire  inst0_O;
wire  inst1_O;
wire  inst2_O;
wire  inst3_O;
wire  inst4_O;
wire  inst5_O;
wire  inst6_O;
wire  inst7_O;
wire  inst8_O;
wire  inst9_O;
wire  inst10_O;
wire  inst11_O;
wire  inst12_O;
wire  inst13_O;
SB_LUT4 #(.LUT_INIT(16'h5555)) inst0 (.I0(I[0]), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst0_O));
SB_LUT4 #(.LUT_INIT(16'h5555)) inst1 (.I0(I[1]), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst1_O));
SB_LUT4 #(.LUT_INIT(16'h5555)) inst2 (.I0(I[2]), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst2_O));
SB_LUT4 #(.LUT_INIT(16'h5555)) inst3 (.I0(I[3]), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst3_O));
SB_LUT4 #(.LUT_INIT(16'h5555)) inst4 (.I0(I[4]), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst4_O));
SB_LUT4 #(.LUT_INIT(16'h5555)) inst5 (.I0(I[5]), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst5_O));
SB_LUT4 #(.LUT_INIT(16'h5555)) inst6 (.I0(I[6]), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst6_O));
SB_LUT4 #(.LUT_INIT(16'h5555)) inst7 (.I0(I[7]), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst7_O));
SB_LUT4 #(.LUT_INIT(16'h5555)) inst8 (.I0(I[8]), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst8_O));
SB_LUT4 #(.LUT_INIT(16'h5555)) inst9 (.I0(I[9]), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst9_O));
SB_LUT4 #(.LUT_INIT(16'h5555)) inst10 (.I0(I[10]), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst10_O));
SB_LUT4 #(.LUT_INIT(16'h5555)) inst11 (.I0(I[11]), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst11_O));
SB_LUT4 #(.LUT_INIT(16'h5555)) inst12 (.I0(I[12]), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst12_O));
SB_LUT4 #(.LUT_INIT(16'h5555)) inst13 (.I0(I[13]), .I1(1'b0), .I2(1'b0), .I3(1'b0), .O(inst13_O));
assign O = {inst13_O,inst12_O,inst11_O,inst10_O,inst9_O,inst8_O,inst7_O,inst6_O,inst5_O,inst4_O,inst3_O,inst2_O,inst1_O,inst0_O};
endmodule

module FullAdder (input  I0, input  I1, input  CIN, output  O, output  COUT);
wire  inst0_O;
wire  inst1_CO;
SB_LUT4 #(.LUT_INIT(16'h9696)) inst0 (.I0(I0), .I1(I1), .I2(CIN), .I3(1'b0), .O(inst0_O));
SB_CARRY inst1 (.I0(I0), .I1(I1), .CI(CIN), .CO(inst1_CO));
assign O = inst0_O;
assign COUT = inst1_CO;
endmodule

module Add14_CIN (input [13:0] I0, input [13:0] I1, input  CIN, output [13:0] O);
wire  inst0_O;
wire  inst0_COUT;
wire  inst1_O;
wire  inst1_COUT;
wire  inst2_O;
wire  inst2_COUT;
wire  inst3_O;
wire  inst3_COUT;
wire  inst4_O;
wire  inst4_COUT;
wire  inst5_O;
wire  inst5_COUT;
wire  inst6_O;
wire  inst6_COUT;
wire  inst7_O;
wire  inst7_COUT;
wire  inst8_O;
wire  inst8_COUT;
wire  inst9_O;
wire  inst9_COUT;
wire  inst10_O;
wire  inst10_COUT;
wire  inst11_O;
wire  inst11_COUT;
wire  inst12_O;
wire  inst12_COUT;
wire  inst13_O;
wire  inst13_COUT;
FullAdder inst0 (.I0(I0[0]), .I1(I1[0]), .CIN(CIN), .O(inst0_O), .COUT(inst0_COUT));
FullAdder inst1 (.I0(I0[1]), .I1(I1[1]), .CIN(inst0_COUT), .O(inst1_O), .COUT(inst1_COUT));
FullAdder inst2 (.I0(I0[2]), .I1(I1[2]), .CIN(inst1_COUT), .O(inst2_O), .COUT(inst2_COUT));
FullAdder inst3 (.I0(I0[3]), .I1(I1[3]), .CIN(inst2_COUT), .O(inst3_O), .COUT(inst3_COUT));
FullAdder inst4 (.I0(I0[4]), .I1(I1[4]), .CIN(inst3_COUT), .O(inst4_O), .COUT(inst4_COUT));
FullAdder inst5 (.I0(I0[5]), .I1(I1[5]), .CIN(inst4_COUT), .O(inst5_O), .COUT(inst5_COUT));
FullAdder inst6 (.I0(I0[6]), .I1(I1[6]), .CIN(inst5_COUT), .O(inst6_O), .COUT(inst6_COUT));
FullAdder inst7 (.I0(I0[7]), .I1(I1[7]), .CIN(inst6_COUT), .O(inst7_O), .COUT(inst7_COUT));
FullAdder inst8 (.I0(I0[8]), .I1(I1[8]), .CIN(inst7_COUT), .O(inst8_O), .COUT(inst8_COUT));
FullAdder inst9 (.I0(I0[9]), .I1(I1[9]), .CIN(inst8_COUT), .O(inst9_O), .COUT(inst9_COUT));
FullAdder inst10 (.I0(I0[10]), .I1(I1[10]), .CIN(inst9_COUT), .O(inst10_O), .COUT(inst10_COUT));
FullAdder inst11 (.I0(I0[11]), .I1(I1[11]), .CIN(inst10_COUT), .O(inst11_O), .COUT(inst11_COUT));
FullAdder inst12 (.I0(I0[12]), .I1(I1[12]), .CIN(inst11_COUT), .O(inst12_O), .COUT(inst12_COUT));
FullAdder inst13 (.I0(I0[13]), .I1(I1[13]), .CIN(inst12_COUT), .O(inst13_O), .COUT(inst13_COUT));
assign O = {inst13_O,inst12_O,inst11_O,inst10_O,inst9_O,inst8_O,inst7_O,inst6_O,inst5_O,inst4_O,inst3_O,inst2_O,inst1_O,inst0_O};
endmodule

module Sub14 (input [13:0] I0, input [13:0] I1, output [13:0] O);
wire [13:0] inst0_O;
wire [13:0] inst1_O;
Invert14 inst0 (.I(I1), .O(inst0_O));
Add14_CIN inst1 (.I0(I0), .I1(inst0_O), .CIN(1'b1), .O(inst1_O));
assign O = inst1_O;
endmodule

module Mux2x14 (input [13:0] I0, input [13:0] I1, input  S, output [13:0] O);
wire  inst0_O;
wire  inst1_O;
wire  inst2_O;
wire  inst3_O;
wire  inst4_O;
wire  inst5_O;
wire  inst6_O;
wire  inst7_O;
wire  inst8_O;
wire  inst9_O;
wire  inst10_O;
wire  inst11_O;
wire  inst12_O;
wire  inst13_O;
Mux2 inst0 (.I({I1[0],I0[0]}), .S(S), .O(inst0_O));
Mux2 inst1 (.I({I1[1],I0[1]}), .S(S), .O(inst1_O));
Mux2 inst2 (.I({I1[2],I0[2]}), .S(S), .O(inst2_O));
Mux2 inst3 (.I({I1[3],I0[3]}), .S(S), .O(inst3_O));
Mux2 inst4 (.I({I1[4],I0[4]}), .S(S), .O(inst4_O));
Mux2 inst5 (.I({I1[5],I0[5]}), .S(S), .O(inst5_O));
Mux2 inst6 (.I({I1[6],I0[6]}), .S(S), .O(inst6_O));
Mux2 inst7 (.I({I1[7],I0[7]}), .S(S), .O(inst7_O));
Mux2 inst8 (.I({I1[8],I0[8]}), .S(S), .O(inst8_O));
Mux2 inst9 (.I({I1[9],I0[9]}), .S(S), .O(inst9_O));
Mux2 inst10 (.I({I1[10],I0[10]}), .S(S), .O(inst10_O));
Mux2 inst11 (.I({I1[11],I0[11]}), .S(S), .O(inst11_O));
Mux2 inst12 (.I({I1[12],I0[12]}), .S(S), .O(inst12_O));
Mux2 inst13 (.I({I1[13],I0[13]}), .S(S), .O(inst13_O));
assign O = {inst13_O,inst12_O,inst11_O,inst10_O,inst9_O,inst8_O,inst7_O,inst6_O,inst5_O,inst4_O,inst3_O,inst2_O,inst1_O,inst0_O};
endmodule

module Mux2x4 (input [3:0] I0, input [3:0] I1, input  S, output [3:0] O);
wire  inst0_O;
wire  inst1_O;
wire  inst2_O;
wire  inst3_O;
Mux2 inst0 (.I({I1[0],I0[0]}), .S(S), .O(inst0_O));
Mux2 inst1 (.I({I1[1],I0[1]}), .S(S), .O(inst1_O));
Mux2 inst2 (.I({I1[2],I0[2]}), .S(S), .O(inst2_O));
Mux2 inst3 (.I({I1[3],I0[3]}), .S(S), .O(inst3_O));
assign O = {inst3_O,inst2_O,inst1_O,inst0_O};
endmodule

module Add4 (input [3:0] I0, input [3:0] I1, output [3:0] O);
wire  inst0_O;
wire  inst0_COUT;
wire  inst1_O;
wire  inst1_COUT;
wire  inst2_O;
wire  inst2_COUT;
wire  inst3_O;
wire  inst3_COUT;
FullAdder inst0 (.I0(I0[0]), .I1(I1[0]), .CIN(1'b0), .O(inst0_O), .COUT(inst0_COUT));
FullAdder inst1 (.I0(I0[1]), .I1(I1[1]), .CIN(inst0_COUT), .O(inst1_O), .COUT(inst1_COUT));
FullAdder inst2 (.I0(I0[2]), .I1(I1[2]), .CIN(inst1_COUT), .O(inst2_O), .COUT(inst2_COUT));
FullAdder inst3 (.I0(I0[3]), .I1(I1[3]), .CIN(inst2_COUT), .O(inst3_O), .COUT(inst3_COUT));
assign O = {inst3_O,inst2_O,inst1_O,inst0_O};
endmodule

module Mux4 (input [3:0] I, input [1:0] S, output  O);
wire  inst0_O;
wire  inst1_O;
wire  inst2_O;
Mux2 inst0 (.I({I[1],I[0]}), .S(S[0]), .O(inst0_O));
Mux2 inst1 (.I({I[3],I[2]}), .S(S[0]), .O(inst1_O));
Mux2 inst2 (.I({inst1_O,inst0_O}), .S(S[1]), .O(inst2_O));
assign O = inst2_O;
endmodule

module Mux8 (input [7:0] I, input [2:0] S, output  O);
wire  inst0_O;
wire  inst1_O;
wire  inst2_O;
Mux4 inst0 (.I({I[3],I[2],I[1],I[0]}), .S({S[1],S[0]}), .O(inst0_O));
Mux4 inst1 (.I({I[7],I[6],I[5],I[4]}), .S({S[1],S[0]}), .O(inst1_O));
Mux2 inst2 (.I({inst1_O,inst0_O}), .S(S[2]), .O(inst2_O));
assign O = inst2_O;
endmodule

module Mux16 (input [15:0] I, input [3:0] S, output  O);
wire  inst0_O;
wire  inst1_O;
wire  inst2_O;
Mux8 inst0 (.I({I[7],I[6],I[5],I[4],I[3],I[2],I[1],I[0]}), .S({S[2],S[1],S[0]}), .O(inst0_O));
Mux8 inst1 (.I({I[15],I[14],I[13],I[12],I[11],I[10],I[9],I[8]}), .S({S[2],S[1],S[0]}), .O(inst1_O));
Mux2 inst2 (.I({inst1_O,inst0_O}), .S(S[3]), .O(inst2_O));
assign O = inst2_O;
endmodule

module txmod_logic (input [7:0] data, input  writing, input  valid, input [10:0] dataStore, input [13:0] writeClock, input [3:0] writeBit, output  O0, output [10:0] O1, output [13:0] O2, output [3:0] O3, output  O4);
wire  inst0_O;
wire  inst1_O;
wire  inst2_O;
wire  inst3_O;
wire  inst4_O;
wire  inst5_O;
wire  inst6_O;
wire  inst7_O;
wire  inst8_O;
wire  inst9_O;
wire  inst10_O;
wire  inst11_O;
wire  inst12_O;
wire  inst13_O;
wire  inst14_O;
wire  inst15_O;
wire  inst16_O;
wire [10:0] inst17_O;
wire  inst18_O;
wire  inst19_O;
wire  inst20_O;
wire [10:0] inst21_O;
wire  inst22_O;
wire  inst23_O;
wire  inst24_O;
wire  inst25_O;
wire  inst26_O;
wire [10:0] inst27_O;
wire  inst28_O;
wire  inst29_O;
wire  inst30_O;
wire [10:0] inst31_O;
wire [13:0] inst32_O;
wire  inst33_O;
wire [13:0] inst34_O;
wire  inst35_O;
wire  inst36_O;
wire  inst37_O;
wire [13:0] inst38_O;
wire  inst39_O;
wire  inst40_O;
wire  inst41_O;
wire  inst42_O;
wire  inst43_O;
wire [13:0] inst44_O;
wire  inst45_O;
wire  inst46_O;
wire  inst47_O;
wire [13:0] inst48_O;
wire  inst49_O;
wire [3:0] inst50_O;
wire [3:0] inst51_O;
wire  inst52_O;
wire  inst53_O;
wire  inst54_O;
wire [3:0] inst55_O;
wire  inst56_O;
wire  inst57_O;
wire  inst58_O;
wire  inst59_O;
wire  inst60_O;
wire [3:0] inst61_O;
wire  inst62_O;
wire  inst63_O;
wire  inst64_O;
wire [3:0] inst65_O;
wire  inst66_O;
wire  inst67_O;
wire  inst68_O;
wire  inst69_O;
wire  inst70_O;
wire  inst71_O;
wire  inst72_O;
wire  inst73_O;
wire  inst74_O;
wire  inst75_O;
wire  inst76_O;
wire  inst77_O;
wire  inst78_O;
wire  inst79_O;
wire  inst80_O;
wire  inst81_O;
wire  inst82_O;
wire  inst83_O;
EQNone inst0 (.I0(writing), .I1(1'b1), .O(inst0_O));
Mux2 inst1 (.I({writing,writing}), .S(inst0_O), .O(inst1_O));
EQNone inst2 (.I0(writing), .I1(1'b1), .O(inst2_O));
EQ14 inst3 (.I0(writeClock), .I1({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}), .O(inst3_O));
And2 inst4 (.I({inst3_O,inst2_O}), .O(inst4_O));
Mux2 inst5 (.I({writing,inst1_O}), .S(inst4_O), .O(inst5_O));
EQNone inst6 (.I0(writing), .I1(1'b1), .O(inst6_O));
EQ14 inst7 (.I0(writeClock), .I1({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}), .O(inst7_O));
And2 inst8 (.I({inst7_O,inst6_O}), .O(inst8_O));
EQ4 inst9 (.I0(writeBit), .I1({1'b1,1'b0,1'b0,1'b1}), .O(inst9_O));
And2 inst10 (.I({inst9_O,inst8_O}), .O(inst10_O));
Mux2 inst11 (.I({1'b0,inst5_O}), .S(inst10_O), .O(inst11_O));
EQNone inst12 (.I0(writing), .I1(1'b0), .O(inst12_O));
EQNone inst13 (.I0(valid), .I1(1'b1), .O(inst13_O));
And2 inst14 (.I({inst13_O,inst12_O}), .O(inst14_O));
Mux2 inst15 (.I({1'b1,inst11_O}), .S(inst14_O), .O(inst15_O));
EQNone inst16 (.I0(writing), .I1(1'b1), .O(inst16_O));
Mux2x11 inst17 (.I0(dataStore), .I1(dataStore), .S(inst16_O), .O(inst17_O));
EQNone inst18 (.I0(writing), .I1(1'b1), .O(inst18_O));
EQ14 inst19 (.I0(writeClock), .I1({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}), .O(inst19_O));
And2 inst20 (.I({inst19_O,inst18_O}), .O(inst20_O));
Mux2x11 inst21 (.I0(inst17_O), .I1(dataStore), .S(inst20_O), .O(inst21_O));
EQNone inst22 (.I0(writing), .I1(1'b1), .O(inst22_O));
EQ14 inst23 (.I0(writeClock), .I1({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}), .O(inst23_O));
And2 inst24 (.I({inst23_O,inst22_O}), .O(inst24_O));
EQ4 inst25 (.I0(writeBit), .I1({1'b1,1'b0,1'b0,1'b1}), .O(inst25_O));
And2 inst26 (.I({inst25_O,inst24_O}), .O(inst26_O));
Mux2x11 inst27 (.I0(inst21_O), .I1(dataStore), .S(inst26_O), .O(inst27_O));
EQNone inst28 (.I0(writing), .I1(1'b0), .O(inst28_O));
EQNone inst29 (.I0(valid), .I1(1'b1), .O(inst29_O));
And2 inst30 (.I({inst29_O,inst28_O}), .O(inst30_O));
Mux2x11 inst31 (.I0(inst27_O), .I1({dataStore[10],dataStore[9],data[7],data[6],data[5],data[4],data[3],data[2],data[1],data[0],dataStore[0]}), .S(inst30_O), .O(inst31_O));
Sub14 inst32 (.I0(writeClock), .I1({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b1}), .O(inst32_O));
EQNone inst33 (.I0(writing), .I1(1'b1), .O(inst33_O));
Mux2x14 inst34 (.I0(writeClock), .I1(inst32_O), .S(inst33_O), .O(inst34_O));
EQNone inst35 (.I0(writing), .I1(1'b1), .O(inst35_O));
EQ14 inst36 (.I0(writeClock), .I1({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}), .O(inst36_O));
And2 inst37 (.I({inst36_O,inst35_O}), .O(inst37_O));
Mux2x14 inst38 (.I0(inst34_O), .I1({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b1,1'b1,1'b0,1'b0,1'b1,1'b0,1'b0}), .S(inst37_O), .O(inst38_O));
EQNone inst39 (.I0(writing), .I1(1'b1), .O(inst39_O));
EQ14 inst40 (.I0(writeClock), .I1({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}), .O(inst40_O));
And2 inst41 (.I({inst40_O,inst39_O}), .O(inst41_O));
EQ4 inst42 (.I0(writeBit), .I1({1'b1,1'b0,1'b0,1'b1}), .O(inst42_O));
And2 inst43 (.I({inst42_O,inst41_O}), .O(inst43_O));
Mux2x14 inst44 (.I0(inst38_O), .I1(writeClock), .S(inst43_O), .O(inst44_O));
EQNone inst45 (.I0(writing), .I1(1'b0), .O(inst45_O));
EQNone inst46 (.I0(valid), .I1(1'b1), .O(inst46_O));
And2 inst47 (.I({inst46_O,inst45_O}), .O(inst47_O));
Mux2x14 inst48 (.I0(inst44_O), .I1({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b1,1'b1,1'b0,1'b0,1'b1,1'b0,1'b0}), .S(inst47_O), .O(inst48_O));
EQNone inst49 (.I0(writing), .I1(1'b1), .O(inst49_O));
Mux2x4 inst50 (.I0(writeBit), .I1(writeBit), .S(inst49_O), .O(inst50_O));
Add4 inst51 (.I0(writeBit), .I1({1'b0,1'b0,1'b0,1'b1}), .O(inst51_O));
EQNone inst52 (.I0(writing), .I1(1'b1), .O(inst52_O));
EQ14 inst53 (.I0(writeClock), .I1({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}), .O(inst53_O));
And2 inst54 (.I({inst53_O,inst52_O}), .O(inst54_O));
Mux2x4 inst55 (.I0(inst50_O), .I1(inst51_O), .S(inst54_O), .O(inst55_O));
EQNone inst56 (.I0(writing), .I1(1'b1), .O(inst56_O));
EQ14 inst57 (.I0(writeClock), .I1({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}), .O(inst57_O));
And2 inst58 (.I({inst57_O,inst56_O}), .O(inst58_O));
EQ4 inst59 (.I0(writeBit), .I1({1'b1,1'b0,1'b0,1'b1}), .O(inst59_O));
And2 inst60 (.I({inst59_O,inst58_O}), .O(inst60_O));
Mux2x4 inst61 (.I0(inst55_O), .I1(writeBit), .S(inst60_O), .O(inst61_O));
EQNone inst62 (.I0(writing), .I1(1'b0), .O(inst62_O));
EQNone inst63 (.I0(valid), .I1(1'b1), .O(inst63_O));
And2 inst64 (.I({inst63_O,inst62_O}), .O(inst64_O));
Mux2x4 inst65 (.I0(inst61_O), .I1({1'b0,1'b0,1'b0,1'b0}), .S(inst64_O), .O(inst65_O));
Mux16 inst66 (.I({1'b0,1'b0,1'b0,1'b0,1'b0,dataStore[10],dataStore[9],dataStore[8],dataStore[7],dataStore[6],dataStore[5],dataStore[4],dataStore[3],dataStore[2],dataStore[1],dataStore[0]}), .S(writeBit), .O(inst66_O));
EQNone inst67 (.I0(writing), .I1(1'b1), .O(inst67_O));
Mux2 inst68 (.I({inst66_O,1'b1}), .S(inst67_O), .O(inst68_O));
Mux16 inst69 (.I({1'b0,1'b0,1'b0,1'b0,1'b0,dataStore[10],dataStore[9],dataStore[8],dataStore[7],dataStore[6],dataStore[5],dataStore[4],dataStore[3],dataStore[2],dataStore[1],dataStore[0]}), .S(writeBit), .O(inst69_O));
EQNone inst70 (.I0(writing), .I1(1'b1), .O(inst70_O));
EQ14 inst71 (.I0(writeClock), .I1({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}), .O(inst71_O));
And2 inst72 (.I({inst71_O,inst70_O}), .O(inst72_O));
Mux2 inst73 (.I({inst69_O,inst68_O}), .S(inst72_O), .O(inst73_O));
EQNone inst74 (.I0(writing), .I1(1'b1), .O(inst74_O));
EQ14 inst75 (.I0(writeClock), .I1({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}), .O(inst75_O));
And2 inst76 (.I({inst75_O,inst74_O}), .O(inst76_O));
EQ4 inst77 (.I0(writeBit), .I1({1'b1,1'b0,1'b0,1'b1}), .O(inst77_O));
And2 inst78 (.I({inst77_O,inst76_O}), .O(inst78_O));
Mux2 inst79 (.I({1'b1,inst73_O}), .S(inst78_O), .O(inst79_O));
EQNone inst80 (.I0(writing), .I1(1'b0), .O(inst80_O));
EQNone inst81 (.I0(valid), .I1(1'b1), .O(inst81_O));
And2 inst82 (.I({inst81_O,inst80_O}), .O(inst82_O));
Mux2 inst83 (.I({dataStore[0],inst79_O}), .S(inst82_O), .O(inst83_O));
assign O0 = inst15_O;
assign O1 = inst31_O;
assign O2 = inst48_O;
assign O3 = inst65_O;
assign O4 = inst83_O;
endmodule

module TXMOD (output  TX, input [7:0] data, input  valid, output  ready, input  CLK);
wire [0:0] inst0_O;
wire [10:0] inst1_O;
wire [0:0] inst2_O;
wire [13:0] inst3_O;
wire [3:0] inst4_O;
wire  inst5_O0;
wire [10:0] inst5_O1;
wire [13:0] inst5_O2;
wire [3:0] inst5_O3;
wire  inst5_O4;
wire  inst6_O;
Register1_0001 inst0 (.I({inst5_O4}), .O(inst0_O), .CLK(CLK));
Register11_0600 inst1 (.I(inst5_O1), .O(inst1_O), .CLK(CLK));
Register1 inst2 (.I({inst5_O0}), .O(inst2_O), .CLK(CLK));
Register14 inst3 (.I(inst5_O2), .O(inst3_O), .CLK(CLK));
Register4 inst4 (.I(inst5_O3), .O(inst4_O), .CLK(CLK));
txmod_logic inst5 (.data(data), .writing(inst2_O[0]), .valid(valid), .dataStore(inst1_O), .writeClock(inst3_O), .writeBit(inst4_O), .O0(inst5_O0), .O1(inst5_O1), .O2(inst5_O2), .O3(inst5_O3), .O4(inst5_O4));
EQNone inst6 (.I0(inst2_O[0]), .I1(1'b0), .O(inst6_O));
assign TX = inst0_O[0];
assign ready = inst6_O;
endmodule

Now we run the flow again, and see that the output has not changed!


In [8]:
%%bash
make clean && make uart_main.run
python uart_driver.py infile outfile /dev/tty.usbserial-14101


\rm -rf out/*
mkdir -p out
yosys -q -p 'synth_ice40 -top main -blif out/uart_main.blif' txmod.v rxmod.v uart_main.v
arachne-pnr -q -d 1k -o out/uart_main_pnr.txt -p ice40.pcf out/uart_main.blif
icepack out/uart_main_pnr.txt out/uart_main.bin
iceprog out/uart_main.bin
rm out/uart_main_pnr.txt out/uart_main.blif
Running with infile=infile, outfile=outfile
infile length=12
Warning: Resizing cell port main.txmod.data from 32 bits to 8 bits.
init..
cdone: high
reset..
cdone: low
flash ID: 0x20 0xBA 0x16 0x10 0x00 0x00 0x23 0x51 0x73 0x10 0x23 0x00 0x35 0x00 0x35 0x06 0x06 0x15 0x43 0xB6
file size: 32220
erase 64kB sector at 0x000000..
programming..
reading..
VERIFY OK
cdone: high
Bye.

In [10]:
%cat outfile


rovvy*�y|vn