diff options
-rw-r--r-- | icetime/icetime.cc | 132 | ||||
-rw-r--r-- | icetime/mktest.py | 15 |
2 files changed, 120 insertions, 27 deletions
diff --git a/icetime/icetime.cc b/icetime/icetime.cc index e0c3df7..84cbfc2 100644 --- a/icetime/icetime.cc +++ b/icetime/icetime.cc @@ -2,7 +2,7 @@ #include <stdlib.h> #include <unistd.h> #include <assert.h> -#include <string.h> +#include <string.h> #include <stdarg.h> #include <functional> @@ -32,7 +32,7 @@ struct net_segment_t net_segment_t(int x, int y, int net, std::string name) : x(x), y(y), net(net), name(name) { } - + bool operator<(const net_segment_t &other) const { if (x != other.x) return x < other.x; @@ -52,7 +52,7 @@ std::set<int> used_nets; std::set<net_segment_t> interconn_src, interconn_dst; std::set<int> no_interconn_net; -int iconn_cell_cnt = 0; +int tname_cnt = 0; // netlist_cells[cell_name][port_name] = port_expr std::map<std::string, std::map<std::string, std::string>> netlist_cells; @@ -108,17 +108,24 @@ std::string stringf(const char *fmt, ...) return string; } +std::string tname() +{ + return stringf("t%d", tname_cnt++); +} + std::string net_name(int net) { declared_nets.insert(net); return stringf("net_%d", net); } -std::string seg_name(const net_segment_t &seg) +std::string seg_name(const net_segment_t &seg, int idx = 0) { std::string str = stringf("seg_%d_%d_%s_%d", seg.x, seg.y, seg.name.c_str(), seg.net); for (auto &ch : str) if (ch == '/') ch = '_'; + if (idx != 0) + str += stringf("_i%d", idx); extra_wires.insert(str); return str; } @@ -544,7 +551,7 @@ std::string make_lc40(int x, int y, int z) lcbits[i] = config_bits[x][y][lcbits_pos[i].first][lcbits_pos[i].second] ? '1' : '0'; // FIXME: fill in the '0' - netlist_cell_params[cell]["C_ON"] = stringf("1'b%c", '0'); + netlist_cell_params[cell]["C_ON"] = stringf("1'b%c", lcbits[8]); netlist_cell_params[cell]["SEQ_MODE"] = stringf("4'b%c%c%c%c", lcbits[9], '0', '0', '0'); netlist_cell_params[cell]["LUT_INIT"] = stringf("16'b%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", lcbits[0], lcbits[10], lcbits[11], lcbits[1], @@ -552,9 +559,62 @@ std::string make_lc40(int x, int y, int z) lcbits[7], lcbits[17], lcbits[16], lcbits[6], lcbits[5], lcbits[15], lcbits[14], lcbits[4]); + if (lcbits[8] == '1') + { + if (z == 0) + { + auto co_cell = make_lc40(x, y-1, 7); + std::string n1, n2; + + char cinit_1 = config_bits[x][y][1][49] ? '1' : '0'; + char cinit_0 = config_bits[x][y][1][50] ? '1' : '0'; + + if (cinit_1 == '1') { + std::tuple<int, int, std::string> key(x, y-1, "lutff_7/cout"); + if (x_y_name_net.count(key)) { + n1 = net_name(x_y_name_net.at(key)); + } else { + n1 = tname(); + netlist_cells[co_cell]["carryout"] = n1; + extra_wires.insert(n1); + } + } + + std::tuple<int, int, std::string> key(x, y, "carry_in_mux"); + if (x_y_name_net.count(key)) { + n2 = net_name(x_y_name_net.at(key)); + } else { + n2 = tname(); + extra_wires.insert(n2); + } + + extra_vlog.push_back(stringf(" ICE_CARRY_IN_MUX #(.C_INIT(2'b%c%c)) %s (.carryinitin(%s), " + ".carryinitout(%s));\n", cinit_1, cinit_0, tname().c_str(), n1.c_str(), n2.c_str())); + netlist_cells[cell]["carryin"] = n2; + } + else + { + auto co_cell = make_lc40(x, y, z-1); + std::tuple<int, int, std::string> key(x, y, stringf("lutff_%d/cout", z-1)); + auto n = x_y_name_net.count(key) ? net_name(x_y_name_net.at(key)) : tname(); + + netlist_cells[co_cell]["carryout"] = n; + netlist_cells[cell]["carryin"] = n; + extra_wires.insert(n); + } + + std::tuple<int, int, std::string> key(x, y, stringf("lutff_%d/cout", z-1)); + } + return cell; } +bool dff_uses_clock(int x, int y, int z) +{ + auto bitpos = logic_tile_bits[stringf("LC_%d", z)][9]; + return config_bits[x][y][bitpos.first][bitpos.second]; +} + void make_odrv(int x, int y, int src) { for (int dst : net_buffers[src]) @@ -643,8 +703,8 @@ void make_seg_cell(int net, const net_segment_t &seg) if (b == 2) { // Lattice tools always put a CascadeMux on in2 extra_wires.insert(net_name(net) + "_cascademuxed"); - extra_vlog.push_back(stringf(" CascadeMux conn_%d (.I(%s), .O(%s));\n", - iconn_cell_cnt++, net_name(net).c_str(), (net_name(net) + "_cascademuxed").c_str())); + extra_vlog.push_back(stringf(" CascadeMux %s (.I(%s), .O(%s));\n", + tname().c_str(), net_name(net).c_str(), (net_name(net) + "_cascademuxed").c_str())); netlist_cells[cell][stringf("in%d", b)] = net_name(net) + "_cascademuxed"; } else { netlist_cells[cell][stringf("in%d", b)] = net_name(net); @@ -682,6 +742,9 @@ void make_seg_cell(int net, const net_segment_t &seg) { for (int i = 0; i < 8; i++) { + if (!dff_uses_clock(seg.x, seg.y, i)) + continue; + std::tuple<int, int, std::string> key(seg.x, seg.y, stringf("lutff_%d/out", i)); if (x_y_name_net.count(key)) { auto cell = make_lc40(seg.x, seg.y, i); @@ -699,6 +762,7 @@ struct make_interconn_worker_t std::map<net_segment_t, std::set<net_segment_t>> seg_tree; std::map<net_segment_t, net_segment_t> seg_parents; std::set<net_segment_t> target_segs, handled_segs; + std::set<int> handled_global_nets; void build_net_tree(int src) { @@ -801,7 +865,7 @@ struct make_interconn_worker_t void create_cells(const net_segment_t &trg) { - if (handled_segs.count(trg)) + if (handled_segs.count(trg) || handled_global_nets.count(trg.net)) return; handled_segs.insert(trg); @@ -817,8 +881,8 @@ struct make_interconn_worker_t if (trg.name.substr(0, 6) == "local_") { - extra_vlog.push_back(stringf(" LocalMux conn_%d (.I(%s), .O(%s));\n", - iconn_cell_cnt++, seg_name(*cursor).c_str(), seg_name(trg).c_str())); + extra_vlog.push_back(stringf(" LocalMux %s (.I(%s), .O(%s));\n", + tname().c_str(), seg_name(*cursor).c_str(), seg_name(trg).c_str())); goto continue_at_cursor; } @@ -839,15 +903,15 @@ struct make_interconn_worker_t goto skip_to_cursor; if (cursor->name.substr(0, 7) == "span12_" || cursor->name.substr(0, 5) == "sp12_") { - extra_vlog.push_back(stringf(" Sp12to4 conn_%d (.I(%s), .O(%s));\n", - iconn_cell_cnt++, seg_name(*cursor).c_str(), seg_name(trg).c_str())); + extra_vlog.push_back(stringf(" Sp12to4 %s (.I(%s), .O(%s));\n", + tname().c_str(), seg_name(*cursor).c_str(), seg_name(trg).c_str())); } else if (cursor->name.substr(0, 6) == "span4_") { - extra_vlog.push_back(stringf(" IoSpan4Mux conn_%d (.I(%s), .O(%s));\n", - iconn_cell_cnt++, seg_name(*cursor).c_str(), seg_name(trg).c_str())); + extra_vlog.push_back(stringf(" IoSpan4Mux %s (.I(%s), .O(%s));\n", + tname().c_str(), seg_name(*cursor).c_str(), seg_name(trg).c_str())); } else { - extra_vlog.push_back(stringf(" Span4Mux_%c%d conn_%d (.I(%s), .O(%s));\n", - horiz ? 'h' : 'v', count_length, iconn_cell_cnt++, + extra_vlog.push_back(stringf(" Span4Mux_%c%d %s (.I(%s), .O(%s));\n", + horiz ? 'h' : 'v', count_length, tname().c_str(), seg_name(*cursor).c_str(), seg_name(trg).c_str())); } @@ -870,23 +934,49 @@ struct make_interconn_worker_t if (cursor->net == trg.net) goto skip_to_cursor; - extra_vlog.push_back(stringf(" Span12Mux_%c%d conn_%d (.I(%s), .O(%s));\n", - horiz ? 'h' : 'v', count_length, iconn_cell_cnt++, + extra_vlog.push_back(stringf(" Span12Mux_%c%d %s (.I(%s), .O(%s));\n", + horiz ? 'h' : 'v', count_length, tname().c_str(), seg_name(*cursor).c_str(), seg_name(trg).c_str())); goto continue_at_cursor; } + // Global nets + + if (trg.name.substr(0, 10) == "glb_netwk_") + { + while (seg_parents.count(*cursor) && (cursor->net == trg.net || cursor->name == "fabout")) + cursor = &seg_parents.at(*cursor); + + if (cursor->net == trg.net) + goto skip_to_cursor; + + extra_vlog.push_back(stringf(" GlobalMux %s (.I(%s), .O(%s));\n", + tname().c_str(), seg_name(*cursor, 3).c_str(), seg_name(trg).c_str())); + + extra_vlog.push_back(stringf(" gio2CtrlBuf %s (.I(%s), .O(%s));\n", + tname().c_str(), seg_name(*cursor, 2).c_str(), seg_name(*cursor, 3).c_str())); + + extra_vlog.push_back(stringf(" ICE_GB %s (.USERSIGNALTOGLOBALBUFFER(%s), .GLOBALBUFFEROUTPUT(%s));\n", + tname().c_str(), seg_name(*cursor, 1).c_str(), seg_name(*cursor, 2).c_str())); + + extra_vlog.push_back(stringf(" IoInMux %s (.I(%s), .O(%s));\n", + tname().c_str(), seg_name(*cursor).c_str(), seg_name(*cursor, 1).c_str())); + + handled_global_nets.insert(trg.net); + goto continue_at_cursor; + } + // Default handler - while (seg_parents.count(*cursor)) + while (seg_parents.count(*cursor) && cursor->net == trg.net) cursor = &seg_parents.at(*cursor); if (cursor->net == trg.net) goto skip_to_cursor; - extra_vlog.push_back(stringf(" INTERCONN conn_%d (.I(%s), .O(%s));\n", - iconn_cell_cnt++, seg_name(*cursor).c_str(), seg_name(trg).c_str())); + extra_vlog.push_back(stringf(" INTERCONN %s (.I(%s), .O(%s));\n", + tname().c_str(), seg_name(*cursor).c_str(), seg_name(trg).c_str())); goto continue_at_cursor; skip_to_cursor: diff --git a/icetime/mktest.py b/icetime/mktest.py index 5d888f4..5154b02 100644 --- a/icetime/mktest.py +++ b/icetime/mktest.py @@ -17,10 +17,9 @@ with open("%s.v" % sys.argv[1], "w") as f: if mode == "test0": io_names = [ "clk", "i0", "o0", "o1", "o2" ] print("module top(input clk, i0, output o0, o1, o2);", file=f) - print(" reg [3:0] state;", file=f) - # print(" always @(posedge clk) state <= (state << 7) ^ (state >> 13) ^ i0;", file=f) - print(" always @(posedge clk) state <= (state << 1) ^ i0;", file=f) - print(" assign o0 = ^state, o1 = |state, o2 = &state;", file=f) + print(" reg [31:0] state;", file=f) + print(" always @(posedge clk) state <= ((state << 5) + state) ^ i0;", file=f) + print(" assign o0 = ^state, o1 = |state, o2 = state[31:16] + state[15:0];", file=f) print("endmodule", file=f) if mode == "test1": io_names = [ "clk", "i0", "i1", "i2", "i3", "o0", "o1", "o2", "o3" ] @@ -42,10 +41,11 @@ with open("%s.ys" % sys.argv[1], "w") as f: print("read_verilog %s_out.v" % sys.argv[1], file=f) print("prep", file=f) print("equiv_make top chip equiv", file=f) - print("hierarchy -top equiv", file=f) + print("cd equiv", file=f) + print("script %s.lc" % sys.argv[1], file=f) print("rename -hide w:N_*", file=f) print("equiv_struct", file=f) - print("opt_clean", file=f) + print("opt_clean -purge", file=f) print("write_ilang %s.il" % sys.argv[1], file=f) print("equiv_status -assert", file=f) @@ -97,6 +97,9 @@ with open("%s_ref.v" % sys.argv[1], "w") as f: f.write(line) +assert os.system("yosys -qp 'select -write %s.lc t:LogicCell40' %s_ref.v" % (sys.argv[1], sys.argv[1])) == 0 +assert os.system(r"sed -i -r 's,.*/(.*)LC_(.*),equiv_add -cell \1LC_\2_gold lc40_\2_gate,' %s.lc" % sys.argv[1]) == 0 + os.remove("%s.bin" % sys.argv[1]) os.remove("%s.vsb" % sys.argv[1]) os.remove("%s.glb" % sys.argv[1]) |