aboutsummaryrefslogtreecommitdiffstats
path: root/icetime
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2015-10-25 15:28:58 +0100
committerClifford Wolf <clifford@clifford.at>2015-10-25 15:28:58 +0100
commite4ed27a3ab81284d556be3dde77a64caab895397 (patch)
treebd0764be6e62f25e7169cacfb0f517a894acf717 /icetime
parent2a8c4b7e6cc60d87ff75576426dedcb9c62e64c8 (diff)
downloadicestorm-e4ed27a3ab81284d556be3dde77a64caab895397.tar.gz
icestorm-e4ed27a3ab81284d556be3dde77a64caab895397.tar.bz2
icestorm-e4ed27a3ab81284d556be3dde77a64caab895397.zip
icetime progress
Diffstat (limited to 'icetime')
-rw-r--r--icetime/icetime.cc132
-rw-r--r--icetime/mktest.py15
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])