import "primitives/core.futil";
import "primitives/memories/comb.futil";
import "primitives/unsynthesizable.futil";
component main() -> () {
cells {
t0_idx = std_reg(2);
t0_add = std_add(2);
@external(1) t0 = comb_mem_d1(32, 3, 2);
t1_idx = std_reg(2);
t1_add = std_add(2);
@external(1) t1 = comb_mem_d1(32, 3, 2);
l0_idx = std_reg(2);
l0_add = std_add(2);
@external(1) l0 = comb_mem_d1(32, 3, 2);
l1_idx = std_reg(2);
l1_add = std_add(2);
@external(1) l1 = comb_mem_d1(32, 3, 2);
@external(1) out_mem = comb_mem_d1(32, 4, 3);
top_0_0 = std_reg(32);
left_0_0 = std_reg(32);
top_0_1 = std_reg(32);
left_0_1 = std_reg(32);
top_1_0 = std_reg(32);
left_1_0 = std_reg(32);
top_1_1 = std_reg(32);
left_1_1 = std_reg(32);
@inline pe_1_0 = mac_pe();
@inline pe_1_1 = mac_pe();
@inline pe_0_1 = mac_pe();
@inline pe_0_0 = mac_pe();
}
wires {
group t0_idx_init {
t0_idx.in = 2'd3;
t0_idx.write_en = 1'd1;
t0_idx_init[done] = t0_idx.done;
}
group t0_idx_update {
t0_add.left = 2'd1;
t0_add.right = t0_idx.out;
t0_idx.in = t0_add.out;
t0_idx.write_en = 1'd1;
t0_idx_update[done] = t0_idx.done;
}
group t0_move {
t0.addr0 = t0_idx.out;
top_0_0.in = t0.read_data;
top_0_0.write_en = 1'd1;
t0_move[done] = top_0_0.done;
}
group t1_idx_init {
t1_idx.in = 2'd3;
t1_idx.write_en = 1'd1;
t1_idx_init[done] = t1_idx.done;
}
group t1_idx_update {
t1_add.left = 2'd1;
t1_add.right = t1_idx.out;
t1_idx.in = t1_add.out;
t1_idx.write_en = 1'd1;
t1_idx_update[done] = t1_idx.done;
}
group t1_move {
t1.addr0 = t1_idx.out;
top_0_1.in = t1.read_data;
top_0_1.write_en = 1'd1;
t1_move[done] = top_0_1.done;
}
group l0_idx_init {
l0_idx.in = 2'd3;
l0_idx.write_en = 1'd1;
l0_idx_init[done] = l0_idx.done;
}
group l0_idx_update {
l0_add.left = 2'd1;
l0_add.right = l0_idx.out;
l0_idx.in = l0_add.out;
l0_idx.write_en = 1'd1;
l0_idx_update[done] = l0_idx.done;
}
group l0_move {
l0.addr0 = l0_idx.out;
left_0_0.in = l0.read_data;
left_0_0.write_en = 1'd1;
l0_move[done] = left_0_0.done;
}
group l1_idx_init {
l1_idx.in = 2'd3;
l1_idx.write_en = 1'd1;
l1_idx_init[done] = l1_idx.done;
}
group l1_idx_update {
l1_add.left = 2'd1;
l1_add.right = l1_idx.out;
l1_idx.in = l1_add.out;
l1_idx.write_en = 1'd1;
l1_idx_update[done] = l1_idx.done;
}
group l1_move {
l1.addr0 = l1_idx.out;
left_1_0.in = l1.read_data;
left_1_0.write_en = 1'd1;
l1_move[done] = left_1_0.done;
}
group pe_0_0_right_move {
left_0_1.in = left_0_0.out;
left_0_1.write_en = 1'd1;
pe_0_0_right_move[done] = left_0_1.done;
}
group pe_0_0_down_move {
top_1_0.in = top_0_0.out;
top_1_0.write_en = 1'd1;
pe_0_0_down_move[done] = top_1_0.done;
}
group pe_0_0_out_write {
out_mem.addr0 = 3'd0;
out_mem.write_data = pe_0_0.out;
out_mem.write_en = 1'd1;
pe_0_0_out_write[done] = out_mem.done;
}
group pe_0_1_down_move {
top_1_1.in = top_0_1.out;
top_1_1.write_en = 1'd1;
pe_0_1_down_move[done] = top_1_1.done;
}
group pe_0_1_out_write {
out_mem.addr0 = 3'd1;
out_mem.write_data = pe_0_1.out;
out_mem.write_en = 1'd1;
pe_0_1_out_write[done] = out_mem.done;
}
group pe_1_0_right_move {
left_1_1.in = left_1_0.out;
left_1_1.write_en = 1'd1;
pe_1_0_right_move[done] = left_1_1.done;
}
group pe_1_0_out_write {
out_mem.addr0 = 3'd2;
out_mem.write_data = pe_1_0.out;
out_mem.write_en = 1'd1;
pe_1_0_out_write[done] = out_mem.done;
}
group pe_1_1_out_write {
out_mem.addr0 = 3'd3;
out_mem.write_data = pe_1_1.out;
out_mem.write_en = 1'd1;
pe_1_1_out_write[done] = out_mem.done;
}
}
control {
seq {
par {
t0_idx_init;
t1_idx_init;
l0_idx_init;
l1_idx_init;
}
par {
t0_idx_update;
l0_idx_update;
}
par {
t0_move;
l0_move;
}
par {
t0_idx_update;
l0_idx_update;
t1_idx_update;
l1_idx_update;
invoke pe_0_0(top=top_0_0.out, left=left_0_0.out)();
}
par {
t0_move;
t1_move;
pe_0_0_down_move;
l0_move;
pe_0_0_right_move;
l1_move;
}
par {
t0_idx_update;
l0_idx_update;
t1_idx_update;
l1_idx_update;
invoke pe_0_0(top=top_0_0.out, left=left_0_0.out)();
invoke pe_0_1(top=top_0_1.out, left=left_0_1.out)();
invoke pe_1_0(top=top_1_0.out, left=left_1_0.out)();
}
par {
t0_move;
t1_move;
pe_0_0_down_move;
pe_0_1_down_move;
l0_move;
pe_0_0_right_move;
l1_move;
pe_1_0_right_move;
}
par {
t1_idx_update;
l1_idx_update;
invoke pe_0_0(top=top_0_0.out, left=left_0_0.out)();
invoke pe_0_1(top=top_0_1.out, left=left_0_1.out)();
invoke pe_1_0(top=top_1_0.out, left=left_1_0.out)();
invoke pe_1_1(top=top_1_1.out, left=left_1_1.out)();
}
par {
t1_move;
pe_0_0_down_move;
pe_0_1_down_move;
pe_0_0_right_move;
l1_move;
pe_1_0_right_move;
}
par {
invoke pe_0_1(top=top_0_1.out, left=left_0_1.out)();
invoke pe_1_0(top=top_1_0.out, left=left_1_0.out)();
invoke pe_1_1(top=top_1_1.out, left=left_1_1.out)();
}
par {
pe_0_1_down_move;
pe_1_0_right_move;
}
par {
invoke pe_1_1(top=top_1_1.out, left=left_1_1.out)();
}
seq {
pe_0_0_out_write;
pe_0_1_out_write;
pe_1_0_out_write;
pe_1_1_out_write;
}
}
}
}
component mac_pe(top: 32, left: 32) -> (out: 32) {
cells {
// Storage
mul_out = std_reg(32);
acc = std_reg(32);
// Computation
add = std_add(32);
mult0 = std_unsyn_mult(32);
}
wires {
group do_mul {
mult0.left = top;
mult0.right = left;
mul_out.in = mult0.out;
mul_out.write_en = 1'd1;
do_mul[done] = mul_out.done;
}
group do_add {
add.left = acc.out;
add.right = mul_out.out;
acc.in = add.out;
acc.write_en = 1'd1;
do_add[done] = acc.done;
}
out = acc.out;
}
control {
seq {
do_mul;
do_add;
}
}
}