aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--icefuzz/pinloc/.gitignore5
-rw-r--r--icetime/.gitignore3
-rw-r--r--icetime/Makefile24
-rw-r--r--icetime/cells.v686
-rw-r--r--icetime/icetime.cc653
5 files changed, 1371 insertions, 0 deletions
diff --git a/icefuzz/pinloc/.gitignore b/icefuzz/pinloc/.gitignore
new file mode 100644
index 0000000..02fa5b5
--- /dev/null
+++ b/icefuzz/pinloc/.gitignore
@@ -0,0 +1,5 @@
+pinloc-*.mk
+pinloc-*.exp
+pinloc-*.log
+pinloc-*.pcf
+pinloc-*.v
diff --git a/icetime/.gitignore b/icetime/.gitignore
new file mode 100644
index 0000000..a28ed80
--- /dev/null
+++ b/icetime/.gitignore
@@ -0,0 +1,3 @@
+icetime
+*.d
+*.o
diff --git a/icetime/Makefile b/icetime/Makefile
new file mode 100644
index 0000000..2eef844
--- /dev/null
+++ b/icetime/Makefile
@@ -0,0 +1,24 @@
+# CXX = clang
+LDLIBS = -lm -lstdc++
+CXXFLAGS = -MD -O0 -ggdb -Wall -std=c++11 -I/usr/local/include
+CC = $(CXX)
+DESTDIR = /usr/local
+
+all: icetime
+
+icetime: icetime.o
+
+install: all
+ cp icetime $(DESTDIR)/bin/icetime
+
+uninstall:
+ rm -f $(DESTDIR)/bin/icetime
+
+clean:
+ rm -f icetime
+ rm -f *.o *.d
+
+-include *.d
+
+.PHONY: all install uninstall clean
+
diff --git a/icetime/cells.v b/icetime/cells.v
new file mode 100644
index 0000000..289c55e
--- /dev/null
+++ b/icetime/cells.v
@@ -0,0 +1,686 @@
+module AND2(A, B, O);
+ input A;
+ input B;
+ output O;
+endmodule
+
+module CEMux(I, O);
+ input I;
+ output O;
+endmodule
+
+module CascadeBuf(I, O);
+ input I;
+ output O;
+endmodule
+
+module CascadeMux(I, O);
+ input I;
+ output O;
+endmodule
+
+module ClkMux(I, O);
+ input I;
+ output O;
+endmodule
+
+module ColCtrlBuf(I, O);
+ input I;
+ output O;
+endmodule
+
+module DummyBuf(I, O);
+ input I;
+ output O;
+endmodule
+
+module Glb2LocalMux(I, O);
+ input I;
+ output O;
+endmodule
+
+module GlobalMux(I, O);
+ input I;
+ output O;
+endmodule
+
+module ICE_CARRY_IN_MUX(carryinitout, carryinitin);
+ input carryinitin;
+ output carryinitout;
+endmodule
+
+module ICE_GB(GLOBALBUFFEROUTPUT, USERSIGNALTOGLOBALBUFFER);
+ output GLOBALBUFFEROUTPUT;
+ input USERSIGNALTOGLOBALBUFFER;
+endmodule
+
+module ICE_GB_IO(PACKAGEPIN, LATCHINPUTVALUE, CLOCKENABLE, INPUTCLK, OUTPUTCLK, OUTPUTENABLE, DOUT1, DOUT0, DIN1, DIN0, GLOBALBUFFEROUTPUT);
+ input CLOCKENABLE;
+ output DIN0;
+ output DIN1;
+ input DOUT0;
+ input DOUT1;
+ output GLOBALBUFFEROUTPUT;
+ input INPUTCLK;
+ input LATCHINPUTVALUE;
+ input OUTPUTCLK;
+ input OUTPUTENABLE;
+ inout PACKAGEPIN;
+endmodule
+
+module ICE_IO(PACKAGEPIN, LATCHINPUTVALUE, CLOCKENABLE, INPUTCLK, OUTPUTCLK, OUTPUTENABLE, DOUT1, DOUT0, DIN1, DIN0);
+ input CLOCKENABLE;
+ output DIN0;
+ output DIN1;
+ input DOUT0;
+ input DOUT1;
+ input INPUTCLK;
+ input LATCHINPUTVALUE;
+ input OUTPUTCLK;
+ input OUTPUTENABLE;
+ inout PACKAGEPIN;
+endmodule
+
+module ICE_IO_DLY(PACKAGEPIN, LATCHINPUTVALUE, CLOCKENABLE, INPUTCLK, OUTPUTCLK, OUTPUTENABLE, DOUT1, DOUT0, DIN1, DIN0, SCLK, SDI, CRSEL, SDO);
+ input CLOCKENABLE;
+ input CRSEL;
+ output DIN0;
+ output DIN1;
+ input DOUT0;
+ input DOUT1;
+ input INPUTCLK;
+ input LATCHINPUTVALUE;
+ input OUTPUTCLK;
+ input OUTPUTENABLE;
+ inout PACKAGEPIN;
+ input SCLK;
+ input SDI;
+ output SDO;
+endmodule
+
+module ICE_IO_DS(PACKAGEPIN, PACKAGEPINB, LATCHINPUTVALUE, CLOCKENABLE, INPUTCLK, OUTPUTCLK, OUTPUTENABLE, DOUT1, DOUT0, DIN1, DIN0);
+ input CLOCKENABLE;
+ output DIN0;
+ output DIN1;
+ input DOUT0;
+ input DOUT1;
+ input INPUTCLK;
+ input LATCHINPUTVALUE;
+ input OUTPUTCLK;
+ input OUTPUTENABLE;
+ inout PACKAGEPIN;
+ inout PACKAGEPINB;
+endmodule
+
+module ICE_IO_OD(PACKAGEPIN, LATCHINPUTVALUE, CLOCKENABLE, INPUTCLK, OUTPUTCLK, OUTPUTENABLE, DOUT1, DOUT0, DIN1, DIN0);
+ input CLOCKENABLE;
+ output DIN0;
+ output DIN1;
+ input DOUT0;
+ input DOUT1;
+ input INPUTCLK;
+ input LATCHINPUTVALUE;
+ input OUTPUTCLK;
+ input OUTPUTENABLE;
+ inout PACKAGEPIN;
+endmodule
+
+module ICE_IR500_DRV(IRLEDEN, IRPWM, CURREN, IRLEDEN2, IRPWM2, IRLED1, IRLED2);
+ input CURREN;
+ output IRLED1;
+ output IRLED2;
+ input IRLEDEN;
+ input IRLEDEN2;
+ input IRPWM;
+ input IRPWM2;
+endmodule
+
+module INV(I, O);
+ input I;
+ output O;
+endmodule
+
+module IO_PAD(PACKAGEPIN, DOUT, DIN, OE);
+ input DIN;
+ output DOUT;
+ input OE;
+ inout PACKAGEPIN;
+endmodule
+
+module InMux(I, O);
+ input I;
+ output O;
+endmodule
+
+module IoInMux(I, O);
+ input I;
+ output O;
+endmodule
+
+module IoSpan4Mux(I, O);
+ input I;
+ output O;
+endmodule
+
+module IpInMux(I, O);
+ input I;
+ output O;
+endmodule
+
+module IpOutMux(I, O);
+ input I;
+ output O;
+endmodule
+
+module LocalMux(I, O);
+ input I;
+ output O;
+endmodule
+
+module LogicCell(carryout, lcout, carryin, clk, clkb, in0, in1, in2, in3, sr);
+ input carryin;
+ output carryout;
+ input clk;
+ input clkb;
+ input in0;
+ input in1;
+ input in2;
+ input in3;
+ output lcout;
+ input sr;
+endmodule
+
+module LogicCell2(carryout, lcout, carryin, clk, in0, in1, in2, in3, sr, ce);
+ input carryin;
+ output carryout;
+ input ce;
+ input clk;
+ input in0;
+ input in1;
+ input in2;
+ input in3;
+ output lcout;
+ input sr;
+endmodule
+
+module LogicCell40(carryout, lcout, ltout, carryin, clk, in0, in1, in2, in3, sr, ce);
+ input carryin;
+ output carryout;
+ input ce;
+ input clk;
+ input in0;
+ input in1;
+ input in2;
+ input in3;
+ output lcout;
+ output ltout;
+ input sr;
+endmodule
+
+module Odrv12(I, O);
+ input I;
+ output O;
+endmodule
+
+module Odrv4(I, O);
+ input I;
+ output O;
+endmodule
+
+module PAD_BANK0(PAD, PADIN, PADOUT, PADOEN);
+ inout PAD;
+ output PADIN;
+ input PADOEN;
+ input PADOUT;
+endmodule
+
+module PAD_BANK1(PAD, PADIN, PADOUT, PADOEN);
+ inout PAD;
+ output PADIN;
+ input PADOEN;
+ input PADOUT;
+endmodule
+
+module PAD_BANK2(PAD, PADIN, PADOUT, PADOEN);
+ inout PAD;
+ output PADIN;
+ input PADOEN;
+ input PADOUT;
+endmodule
+
+module PAD_BANK3(PAD, PADIN, PADOUT, PADOEN);
+ inout PAD;
+ output PADIN;
+ input PADOEN;
+ input PADOUT;
+endmodule
+
+module PLL40(PLLIN, PLLOUTCORE, PLLOUTGLOBAL, EXTFEEDBACK, DYNAMICDELAY, LOCK, BYPASS, RESETB, SDI, SDO, SCLK, LATCHINPUTVALUE);
+ input BYPASS;
+ input [7:0] DYNAMICDELAY;
+ input EXTFEEDBACK;
+ input LATCHINPUTVALUE;
+ output LOCK;
+ input PLLIN;
+ output PLLOUTCORE;
+ output PLLOUTGLOBAL;
+ input RESETB;
+ input SCLK;
+ input SDI;
+ output SDO;
+endmodule
+
+module PLL40_2(PLLIN, PLLOUTCOREA, PLLOUTGLOBALA, PLLOUTCOREB, PLLOUTGLOBALB, EXTFEEDBACK, DYNAMICDELAY, LOCK, BYPASS, RESETB, SDI, SDO, SCLK, LATCHINPUTVALUE);
+ input BYPASS;
+ input [7:0] DYNAMICDELAY;
+ input EXTFEEDBACK;
+ input LATCHINPUTVALUE;
+ output LOCK;
+ input PLLIN;
+ output PLLOUTCOREA;
+ output PLLOUTCOREB;
+ output PLLOUTGLOBALA;
+ output PLLOUTGLOBALB;
+ input RESETB;
+ input SCLK;
+ input SDI;
+ output SDO;
+endmodule
+
+module PLL40_2F(PLLIN, PLLOUTCOREA, PLLOUTGLOBALA, PLLOUTCOREB, PLLOUTGLOBALB, EXTFEEDBACK, DYNAMICDELAY, LOCK, BYPASS, RESETB, SDI, SDO, SCLK, LATCHINPUTVALUE);
+ input BYPASS;
+ input [7:0] DYNAMICDELAY;
+ input EXTFEEDBACK;
+ input LATCHINPUTVALUE;
+ output LOCK;
+ input PLLIN;
+ output PLLOUTCOREA;
+ output PLLOUTCOREB;
+ output PLLOUTGLOBALA;
+ output PLLOUTGLOBALB;
+ input RESETB;
+ input SCLK;
+ input SDI;
+ output SDO;
+endmodule
+
+module PREIO(PADIN, PADOUT, PADOEN, LATCHINPUTVALUE, CLOCKENABLE, INPUTCLK, OUTPUTCLK, OUTPUTENABLE, DOUT1, DOUT0, DIN1, DIN0);
+ input CLOCKENABLE;
+ output DIN0;
+ output DIN1;
+ input DOUT0;
+ input DOUT1;
+ input INPUTCLK;
+ input LATCHINPUTVALUE;
+ input OUTPUTCLK;
+ input OUTPUTENABLE;
+ input PADIN;
+ output PADOEN;
+ output PADOUT;
+endmodule
+
+module PRE_IO(PADIN, PADOUT, PADOEN, LATCHINPUTVALUE, CLOCKENABLE, INPUTCLK, OUTPUTCLK, OUTPUTENABLE, DOUT1, DOUT0, DIN1, DIN0);
+ input CLOCKENABLE;
+ output DIN0;
+ output DIN1;
+ input DOUT0;
+ input DOUT1;
+ input INPUTCLK;
+ input LATCHINPUTVALUE;
+ input OUTPUTCLK;
+ input OUTPUTENABLE;
+ input PADIN;
+ output PADOEN;
+ output PADOUT;
+endmodule
+
+module PRE_IO_GBUF(GLOBALBUFFEROUTPUT, PADSIGNALTOGLOBALBUFFER);
+ output GLOBALBUFFEROUTPUT;
+ input PADSIGNALTOGLOBALBUFFER;
+endmodule
+
+module QuadClkMux(I, O);
+ input I;
+ output O;
+endmodule
+
+module SB_G2TBuf(I, O);
+ input I;
+ output O;
+endmodule
+
+module SMCCLK(CLK);
+ output CLK;
+endmodule
+
+module SRMux(I, O);
+ input I;
+ output O;
+endmodule
+
+module Sp12to4(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_h(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s0_h(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s0_v(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s10_h(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s10_v(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s11_h(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s11_v(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s1_h(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s1_v(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s2_h(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s2_v(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s3_h(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s3_v(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s4_h(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s4_v(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s5_h(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s5_v(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s6_h(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s6_v(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s7_h(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s7_v(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s8_h(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s8_v(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s9_h(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_s9_v(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span12Mux_v(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span4Mux(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span4Mux_h(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span4Mux_s0_h(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span4Mux_s0_v(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span4Mux_s1_h(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span4Mux_s1_v(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span4Mux_s2_h(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span4Mux_s2_v(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span4Mux_s3_h(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span4Mux_s3_v(I, O);
+ input I;
+ output O;
+endmodule
+
+module Span4Mux_v(I, O);
+ input I;
+ output O;
+endmodule
+
+module carry_logic(cout, carry_in, a, a_bar, b, b_bar, vg_en);
+ input a;
+ input a_bar;
+ input b;
+ input b_bar;
+ input carry_in;
+ output cout;
+ input vg_en;
+endmodule
+
+module clut4(lut4, in0, in1, in2, in3, in0b, in1b, in2b, in3b, cbit);
+ input [15:0] cbit;
+ input in0;
+ input in0b;
+ input in1;
+ input in1b;
+ input in2;
+ input in2b;
+ input in3;
+ input in3b;
+ output lut4;
+endmodule
+
+module coredffr(q, d, purst, S_R, cbit, clk, clkb);
+ input S_R;
+ input [1:0] cbit;
+ input clk;
+ input clkb;
+ input d;
+ input purst;
+ output q;
+endmodule
+
+module coredffr2(q, d, purst, S_R, cbit, clk, clkb, ce);
+ input S_R;
+ input [1:0] cbit;
+ input ce;
+ input clk;
+ input clkb;
+ input d;
+ input purst;
+ output q;
+endmodule
+
+module gio2CtrlBuf(I, O);
+ input I;
+ output O;
+endmodule
+
+module inv_hvt(Y, A);
+ input A;
+ output Y;
+endmodule
+
+module logic_cell(carry_out, lc_out, carry_in, cbit, clk, clkb, in0, in1, in2, in3, prog, purst, s_r);
+ input carry_in;
+ output carry_out;
+ input [20:0] cbit;
+ input clk;
+ input clkb;
+ input in0;
+ input in1;
+ input in2;
+ input in3;
+ output lc_out;
+ input prog;
+ input purst;
+ input s_r;
+endmodule
+
+module logic_cell2(carry_out, lc_out, carry_in, cbit, clk, clkb, in0, in1, in2, in3, prog, purst, s_r, ce);
+ input carry_in;
+ output carry_out;
+ input [20:0] cbit;
+ input ce;
+ input clk;
+ input clkb;
+ input in0;
+ input in1;
+ input in2;
+ input in3;
+ output lc_out;
+ input prog;
+ input purst;
+ input s_r;
+endmodule
+
+module logic_cell40(carry_out, lc_out, lt_out, carry_in, cbit, clk, clkb, in0, in1, in2, in3, prog, purst, s_r, ce);
+ input carry_in;
+ output carry_out;
+ input [20:0] cbit;
+ input ce;
+ input clk;
+ input clkb;
+ input in0;
+ input in1;
+ input in2;
+ input in3;
+ output lc_out;
+ output lt_out;
+ input prog;
+ input purst;
+ input s_r;
+endmodule
+
+module o_mux(O, in0, in1, cbit, prog);
+ output O;
+ input cbit;
+ input in0;
+ input in1;
+ input prog;
+endmodule
+
+module sync_clk_enable(D, NC, Q);
+ input D;
+ input NC;
+ output Q;
+endmodule
+
+module GND(Y);
+ output Y;
+endmodule
+
+module VCC(Y);
+ output Y;
+endmodule
+
+module INTERCONN(I, O);
+ input I;
+ output O;
+endmodule
diff --git a/icetime/icetime.cc b/icetime/icetime.cc
new file mode 100644
index 0000000..9ba91a9
--- /dev/null
+++ b/icetime/icetime.cc
@@ -0,0 +1,653 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <functional>
+#include <string>
+#include <vector>
+#include <tuple>
+#include <map>
+#include <set>
+
+FILE *fin, *fout;
+
+std::string config_device;
+std::vector<std::vector<std::string>> config_tile_type;
+std::vector<std::vector<std::vector<std::vector<bool>>>> config_bits;
+
+struct net_segment_t
+{
+ int x, y, net;
+ std::string name;
+
+ net_segment_t() :
+ x(-1), y(-1), net(-1) { }
+
+ 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;
+ if (y != other.y)
+ return y < other.y;
+ return name < other.name;
+ }
+};
+
+std::set<net_segment_t> segments;
+std::map<int, std::set<net_segment_t>> net_to_segments;
+std::map<std::tuple<int, int, int>, net_segment_t> x_y_net_segment;
+std::map<int, std::set<int>> net_buffers, net_rbuffers, net_routing;
+std::map<std::pair<int, int>, std::pair<int, int>> connection_pos;
+std::set<int> used_nets;
+
+std::set<net_segment_t> interconn_src, interconn_dst;
+std::set<int> no_interconn_net;
+
+// netlist_cells[cell_name][port_name] = port_expr
+std::map<std::string, std::map<std::string, std::string>> netlist_cells;
+std::map<std::string, std::string> netlist_cell_types;
+
+std::vector<std::string> extra_vlog;
+std::set<int> declared_nets;
+
+std::string vstringf(const char *fmt, va_list ap)
+{
+ std::string string;
+ char *str = NULL;
+
+#ifdef _WIN32
+ int sz = 64, rc;
+ while (1) {
+ va_list apc;
+ va_copy(apc, ap);
+ str = (char*)realloc(str, sz);
+ rc = vsnprintf(str, sz, fmt, apc);
+ va_end(apc);
+ if (rc >= 0 && rc < sz)
+ break;
+ sz *= 2;
+ }
+#else
+ if (vasprintf(&str, fmt, ap) < 0)
+ str = NULL;
+#endif
+
+ if (str != NULL) {
+ string = str;
+ free(str);
+ }
+
+ return string;
+}
+
+std::string stringf(const char *fmt, ...)
+{
+ std::string string;
+ va_list ap;
+
+ va_start(ap, fmt);
+ string = vstringf(fmt, ap);
+ va_end(ap);
+
+ return string;
+}
+
+std::string net_name(int net)
+{
+ declared_nets.insert(net);
+ return stringf("net_%d", net);
+}
+
+void read_config()
+{
+ char buffer[128];
+ int tile_x, tile_y, line_nr = -1;
+
+ while (fgets(buffer, 128, fin))
+ {
+ if (buffer[0] == '.')
+ {
+ line_nr = -1;
+ const char *tok = strtok(buffer, " \t\r\n");
+
+ if (!strcmp(tok, ".device"))
+ {
+ config_device = strtok(nullptr, " \t\r\n");
+ } else
+ if (!strcmp(tok, ".io_tile") || !strcmp(tok, ".logic_tile") ||
+ !strcmp(tok, ".ramb_tile") || !strcmp(tok, ".ramt_tile"))
+ {
+ line_nr = 0;
+ tile_x = atoi(strtok(nullptr, " \t\r\n"));
+ tile_y = atoi(strtok(nullptr, " \t\r\n"));
+
+ if (tile_x >= int(config_tile_type.size())) {
+ config_tile_type.resize(tile_x+1);
+ config_bits.resize(tile_x+1);
+ }
+
+ if (tile_y >= int(config_tile_type.at(tile_x).size())) {
+ config_tile_type.at(tile_x).resize(tile_y+1);
+ config_bits.at(tile_x).resize(tile_y+1);
+ }
+
+ if (!strcmp(tok, ".io_tile"))
+ config_tile_type.at(tile_x).at(tile_y) = "io";
+ if (!strcmp(tok, ".logic_tile"))
+ config_tile_type.at(tile_x).at(tile_y) = "logic";
+ if (!strcmp(tok, ".ramb_tile"))
+ config_tile_type.at(tile_x).at(tile_y) = "ramb";
+ if (!strcmp(tok, ".ramt_tile"))
+ config_tile_type.at(tile_x).at(tile_y) = "ramt";
+ }
+ } else
+ if (line_nr >= 0)
+ {
+ assert(int(config_bits.at(tile_x).at(tile_y).size()) == line_nr);
+ config_bits.at(tile_x).at(tile_y).resize(line_nr+1);
+ for (int i = 0; buffer[i] == '0' || buffer[i] == '1'; i++)
+ config_bits.at(tile_x).at(tile_y).at(line_nr).push_back(buffer[i] == '1');
+ line_nr++;
+ }
+ }
+}
+
+void read_chipdb()
+{
+ char buffer[1024];
+ snprintf(buffer, 1024, "/usr/local/share/icebox/chipdb-%s.txt", config_device.c_str());
+
+ FILE *fdb = fopen(buffer, "r");
+ if (fdb == nullptr) {
+ perror("Can't open chipdb file");
+ exit(1);
+ }
+
+
+ std::string mode;
+ int current_net = -1;
+ int tile_x = -1, tile_y = -1;
+ std::string thiscfg;
+
+ while (fgets(buffer, 1024, fdb))
+ {
+ if (buffer[0] == '#')
+ continue;
+
+ const char *tok = strtok(buffer, " \t\r\n");
+ if (tok == nullptr)
+ continue;
+
+ if (tok[0] == '.')
+ {
+ mode = tok;
+
+ if (mode == ".net")
+ {
+ current_net = atoi(strtok(nullptr, " \t\r\n"));
+ continue;
+ }
+
+ if (mode == ".buffer" || mode == ".routing")
+ {
+ tile_x = atoi(strtok(nullptr, " \t\r\n"));
+ tile_y = atoi(strtok(nullptr, " \t\r\n"));
+ current_net = atoi(strtok(nullptr, " \t\r\n"));
+
+ thiscfg = "";
+ while ((tok = strtok(nullptr, " \t\r\n")) != nullptr) {
+ int bit_row, bit_col, rc;
+ rc = sscanf(tok, "B%d[%d]", &bit_row, &bit_col);
+ assert(rc == 2);
+ thiscfg.push_back(config_bits[tile_x][tile_y][bit_row][bit_col] ? '1' : '0');
+ }
+ continue;
+ }
+
+ continue;
+ }
+
+ if (mode == ".net") {
+ int tile_x = atoi(tok);
+ int tile_y = atoi(strtok(nullptr, " \t\r\n"));
+ std::string segment_name = strtok(nullptr, " \t\r\n");
+ net_segment_t seg(tile_x, tile_y, current_net, segment_name);
+ net_to_segments[current_net].insert(seg);
+ segments.insert(seg);
+ }
+
+ if (mode == ".buffer" && !strcmp(tok, thiscfg.c_str())) {
+ int other_net = atoi(strtok(nullptr, " \t\r\n"));
+ net_rbuffers[current_net].insert(other_net);
+ net_buffers[other_net].insert(current_net);
+ connection_pos[std::pair<int, int>(current_net, other_net)] =
+ connection_pos[std::pair<int, int>(other_net, current_net)] =
+ std::pair<int, int>(tile_x, tile_y);
+ used_nets.insert(current_net);
+ used_nets.insert(other_net);
+ }
+
+ if (mode == ".routing" && !strcmp(tok, thiscfg.c_str())) {
+ int other_net = atoi(strtok(nullptr, " \t\r\n"));
+ net_routing[current_net].insert(other_net);
+ net_routing[other_net].insert(current_net);
+ connection_pos[std::pair<int, int>(current_net, other_net)] =
+ connection_pos[std::pair<int, int>(other_net, current_net)] =
+ std::pair<int, int>(tile_x, tile_y);
+ used_nets.insert(current_net);
+ used_nets.insert(other_net);
+ }
+ }
+
+ fclose(fdb);
+
+ // purge unused nets from memory
+ int max_net = net_to_segments.rbegin()->first;
+ for (int net = 0; net <= max_net; net++)
+ {
+ if (used_nets.count(net))
+ continue;
+
+ for (auto seg : net_to_segments[net])
+ segments.erase(seg);
+ net_to_segments.erase(net);
+
+ for (auto other : net_buffers[net])
+ net_rbuffers[other].erase(net);
+ net_buffers.erase(net);
+
+ for (auto other : net_rbuffers[net])
+ net_buffers[other].erase(net);
+ net_rbuffers.erase(net);
+
+ for (auto other : net_routing[net])
+ net_routing[other].erase(net);
+ net_routing.erase(net);
+ }
+
+ // create index
+ for (auto seg : segments) {
+ std::tuple<int, int, int> key(seg.x, seg.y, seg.net);
+ x_y_net_segment[key] = seg;
+ }
+
+#if 1
+ for (int net : used_nets)
+ {
+ printf("// NET %d:\n", net);
+ for (auto seg : net_to_segments[net])
+ printf("// SEG %d %d %s\n", seg.x, seg.y, seg.name.c_str());
+ for (auto other : net_buffers[net])
+ printf("// BUFFER %d %d %d\n", connection_pos[std::pair<int, int>(net, other)].first,
+ connection_pos[std::pair<int, int>(net, other)].second, other);
+ for (auto other : net_rbuffers[net])
+ printf("// RBUFFER %d %d %d\n", connection_pos[std::pair<int, int>(net, other)].first,
+ connection_pos[std::pair<int, int>(net, other)].second, other);
+ for (auto other : net_routing[net])
+ printf("// ROUTE %d %d %d\n", connection_pos[std::pair<int, int>(net, other)].first,
+ connection_pos[std::pair<int, int>(net, other)].second, other);
+ }
+#endif
+}
+
+void register_interconn_src(int x, int y, int net)
+{
+ std::tuple<int, int, int> key(x, y, net);
+ interconn_src.insert(x_y_net_segment.at(key));
+}
+
+void register_interconn_dst(int x, int y, int net)
+{
+ std::tuple<int, int, int> key(x, y, net);
+ interconn_dst.insert(x_y_net_segment.at(key));
+}
+
+std::string make_seg_pre_io(int x, int y, int z)
+{
+ auto cell = stringf("pre_io_%d_%d_%d", x, y, z);
+
+ if (netlist_cell_types.count(cell))
+ return cell;
+
+ netlist_cell_types[cell] = "PRE_IO";
+ netlist_cells[cell]["PADIN"] = stringf("io_pad_%d_%d_%d_dout", x, y, z);
+ netlist_cells[cell]["PADOUT"] = stringf("io_pad_%d_%d_%d_din", x, y, z);
+ netlist_cells[cell]["PADOEN"] = stringf("io_pad_%d_%d_%d_oe", x, y, z);
+ netlist_cells[cell]["LATCHINPUTVALUE"] = "";
+ netlist_cells[cell]["CLOCKENABLE"] = "";
+ netlist_cells[cell]["INPUTCLK"] = "";
+ netlist_cells[cell]["OUTPUTCLK"] = "";
+ netlist_cells[cell]["OUTPUTENABLE"] = "";
+ netlist_cells[cell]["DOUT1"] = "";
+ netlist_cells[cell]["DOUT0"] = "";
+ netlist_cells[cell]["DIN1"] = "";
+ netlist_cells[cell]["DIN0"] = "";
+
+ extra_vlog.push_back(stringf(" wire io_pad_%d_%d_%d_din;\n", x, y, z));
+ extra_vlog.push_back(stringf(" wire io_pad_%d_%d_%d_dout;\n", x, y, z));
+ extra_vlog.push_back(stringf(" wire io_pad_%d_%d_%d_oe;\n", x, y, z));
+ extra_vlog.push_back(stringf(" (* keep *) wire io_pad_%d_%d_%d_pin;\n", x, y, z));
+ extra_vlog.push_back(stringf(" IO_PAD io_pad_%d_%d_%d (\n", x, y, z));
+ extra_vlog.push_back(stringf(" .DIN(io_pad_%d_%d_%d_din),\n", x, y, z));
+ extra_vlog.push_back(stringf(" .DOUT(io_pad_%d_%d_%d_dout),\n", x, y, z));
+ extra_vlog.push_back(stringf(" .OE(io_pad_%d_%d_%d_oe),\n", x, y, z));
+ extra_vlog.push_back(stringf(" .PACKAGEPIN(io_pad_%d_%d_%d_pin)\n", x, y, z));
+ extra_vlog.push_back(stringf(" );\n"));
+
+ return cell;
+}
+
+std::string make_lc40(int x, int y, int z)
+{
+ auto cell = stringf("lc40_%d_%d_%d", x, y, z);
+
+ if (netlist_cell_types.count(cell))
+ return cell;
+
+ netlist_cell_types[cell] = "LogicCell40";
+ netlist_cells[cell]["carryin"] = "";
+ netlist_cells[cell]["ce"] = "";
+ netlist_cells[cell]["clk"] = "";
+ netlist_cells[cell]["in0"] = "";
+ netlist_cells[cell]["in1"] = "";
+ netlist_cells[cell]["in2"] = "";
+ netlist_cells[cell]["in3"] = "";
+ netlist_cells[cell]["sr"] = "";
+ netlist_cells[cell]["carryout"] = "";
+ netlist_cells[cell]["lcout"] = "";
+ netlist_cells[cell]["ltout"] = "";
+
+ return cell;
+}
+
+void make_odrv(int x, int y, int src)
+{
+ for (int dst : net_buffers[src])
+ {
+ auto cell = stringf("odrv_%d_%d_%d_%d", x, y, src, dst);
+
+ if (netlist_cell_types.count(cell))
+ continue;
+
+ bool is4 = false, is12 = false;
+
+ for (auto &seg : net_to_segments[dst]) {
+ if (seg.name.substr(0, 4) == "sp4_") is4 = true;
+ if (seg.name.substr(0, 5) == "sp12_") is12 = true;
+ }
+
+ if (!is4 && !is12) {
+ register_interconn_src(x, y, src);
+ continue;
+ }
+
+ assert(is4 != is12);
+ netlist_cell_types[cell] = is4 ? "Odrv4" : "Odrv12";
+ netlist_cells[cell]["I"] = net_name(src);
+ netlist_cells[cell]["O"] = net_name(dst);
+ register_interconn_src(x, y, dst);
+ }
+}
+
+void make_inmux(int x, int y, int dst)
+{
+ for (int src : net_rbuffers[dst])
+ {
+ auto cell = stringf("inmux_%d_%d_%d_%d", x, y, src, dst);
+
+ if (netlist_cell_types.count(cell))
+ continue;
+
+ netlist_cell_types[cell] = config_tile_type[x][y] == "io" ? "IoInMux" : "InMux";
+ netlist_cells[cell]["I"] = net_name(src);
+ netlist_cells[cell]["O"] = net_name(dst);
+ register_interconn_dst(x, y, src);
+ no_interconn_net.insert(dst);
+ }
+}
+
+void make_seg_cell(int net, const net_segment_t &seg)
+{
+ int a = -1, b = -1;
+ char c = 0;
+
+ if (sscanf(seg.name.c_str(), "io_%d/D_IN_%d", &a, &b) == 2) {
+ auto cell = make_seg_pre_io(seg.x, seg.y, a);
+ netlist_cells[cell][stringf("DIN%d", b)] = net_name(net);
+ make_odrv(seg.x, seg.y, net);
+ return;
+ }
+
+ if (sscanf(seg.name.c_str(), "io_%d/D_OUT_%d", &a, &b) == 2) {
+ auto cell = make_seg_pre_io(seg.x, seg.y, a);
+ netlist_cells[cell][stringf("DOUT%d", b)] = net_name(net);
+ make_inmux(seg.x, seg.y, net);
+ return;
+ }
+
+ if (sscanf(seg.name.c_str(), "lutff_%d/in_%d", &a, &b) == 2) {
+ auto cell = make_lc40(seg.x, seg.y, a);
+ netlist_cells[cell][stringf("in%d", b)] = net_name(net);
+ make_inmux(seg.x, seg.y, net);
+ return;
+ }
+
+ if (sscanf(seg.name.c_str(), "lutff_%d/ou%c", &a, &c) == 2 && c == 't') {
+ auto cell = make_lc40(seg.x, seg.y, a);
+ netlist_cells[cell]["lcout"] = net_name(net);
+ make_odrv(seg.x, seg.y, net);
+ return;
+ }
+}
+
+struct make_interconn_worker_t
+{
+ std::map<int, std::set<int>> net_tree;
+ std::map<net_segment_t, std::set<net_segment_t>> seg_tree;
+
+ void build_net_tree(int src)
+ {
+ auto &children = net_tree[src];
+
+ for (auto &other : net_buffers[src])
+ if (!net_tree.count(other) && !no_interconn_net.count(other)) {
+ build_net_tree(other);
+ children.insert(other);
+ }
+
+ for (auto &other : net_routing[src])
+ if (!net_tree.count(other) && !no_interconn_net.count(other)) {
+ build_net_tree(other);
+ children.insert(other);
+ }
+ }
+
+ void build_seg_tree(const net_segment_t &src)
+ {
+ std::set<net_segment_t> queue, targets;
+ std::map<net_segment_t, int> distances;
+ std::map<net_segment_t, net_segment_t> reverse_edges;
+ queue.insert(src);
+
+ std::map<net_segment_t, std::set<net_segment_t>> seg_connections;
+
+ for (auto &it: net_tree)
+ for (int child : it.second) {
+ auto pos = connection_pos.at(std::pair<int, int>(it.first, child));
+ std::tuple<int, int, int> key_parent(pos.first, pos.second, it.first);
+ std::tuple<int, int, int> key_child(pos.first, pos.second, child);
+ seg_connections[x_y_net_segment.at(key_parent)].insert(x_y_net_segment.at(key_child));
+ }
+
+ for (int distance_counter = 0; !queue.empty(); distance_counter++)
+ {
+ std::set<net_segment_t> next_queue;
+
+ for (auto &seg : queue)
+ distances[seg] = distance_counter;
+
+ for (auto &seg : queue)
+ {
+ if (interconn_dst.count(seg))
+ targets.insert(seg);
+
+ if (seg_connections.count(seg))
+ for (auto &child : seg_connections.at(seg))
+ {
+ if (distances.count(child) != 0)
+ continue;
+
+ reverse_edges[child] = seg;
+ next_queue.insert(child);
+ }
+
+ for (int x = seg.x-1; x <= seg.x+1; x++)
+ for (int y = seg.y-1; y <= seg.y+1; y++)
+ {
+ std::tuple<int, int, int> key(x, y, seg.net);
+
+ if (x_y_net_segment.count(key) == 0)
+ continue;
+
+ auto &child = x_y_net_segment.at(key);
+
+ if (distances.count(child) != 0)
+ continue;
+
+ reverse_edges[child] = seg;
+ next_queue.insert(child);
+ }
+ }
+
+ queue.swap(next_queue);
+ }
+
+ for (auto &trg : targets)
+ seg_tree[trg];
+
+ while (!targets.empty()) {
+ std::set<net_segment_t> next_targets;
+ for (auto &trg : targets)
+ if (reverse_edges.count(trg)) {
+ seg_tree[reverse_edges.at(trg)].insert(trg);
+ next_targets.insert(reverse_edges.at(trg));
+ }
+ targets.swap(next_targets);
+ }
+ }
+};
+
+void make_interconn(const net_segment_t &src)
+{
+ make_interconn_worker_t worker;
+ worker.build_net_tree(src.net);
+ worker.build_seg_tree(src);
+
+#if 1
+ printf("// INTERCONN %d %d %s %d\n", src.x, src.y, src.name.c_str(), src.net);
+ std::function<void(int,int)> print_net_tree = [&] (int net, int indent) {
+ printf("// %*sNET_TREE %d\n", indent, "", net);
+ for (int child : worker.net_tree.at(net))
+ print_net_tree(child, indent+2);
+ };
+ std::function<void(const net_segment_t&,int,bool)> print_seg_tree = [&] (const net_segment_t &seg, int indent, bool chain) {
+ printf("// %*sSEG_TREE %d %d %s %d\n", indent, chain ? "`" : "", seg.x, seg.y, seg.name.c_str(), seg.net);
+ auto &children = worker.seg_tree.at(seg);
+ bool child_chain = children.size() == 1;
+ for (auto &child : children)
+ print_seg_tree(child, child_chain ? (chain ? indent : indent+1) : indent+2, child_chain);
+ };
+ print_net_tree(src.net, 2);
+ print_seg_tree(src, 2, false);
+#endif
+
+ // FIXME: interconnect cells
+ for (auto &it : worker.net_tree)
+ for (auto &dst : it.second)
+ if (declared_nets.count(dst))
+ extra_vlog.push_back(stringf(" INTERCONN conn_%d_%d (.I(%s), .O(%s));\n",
+ src.net, dst, net_name(src.net).c_str(), net_name(dst).c_str()));
+}
+
+void help(const char *cmd)
+{
+ printf("\n");
+ printf("Usage: %s [options] input.txt [output.v]\n", cmd);
+ printf("\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ int opt;
+ while ((opt = getopt(argc, argv, "")) != -1)
+ {
+ switch (opt)
+ {
+ default:
+ help(argv[0]);
+ }
+ }
+
+ if (optind+1 == argc) {
+ fin = fopen(argv[optind], "r");
+ if (fin == nullptr) {
+ perror("Can't open input file");
+ exit(1);
+ }
+ fout = stdout;
+ } else
+ if (optind+2 == argc) {
+ fin = fopen(argv[optind], "r");
+ if (fin == nullptr) {
+ perror("Can't open input file");
+ exit(1);
+ }
+ fout = fopen(argv[optind+1], "w");
+ if (fout == nullptr) {
+ perror("Can't open output file");
+ exit(1);
+ }
+ } else
+ help(argv[0]);
+
+ printf("// Reading input .txt file..\n");
+ read_config();
+
+ printf("// Reading chipdb file..\n");
+ read_chipdb();
+
+ for (int net : used_nets)
+ for (auto &seg : net_to_segments[net])
+ make_seg_cell(net, seg);
+
+ for (auto &seg : interconn_src)
+ make_interconn(seg);
+
+ fprintf(fout, "module chip;\n");
+
+ for (int net : declared_nets)
+ fprintf(fout, " (* keep *) wire net_%d;\n", net);
+
+ for (auto &str : extra_vlog)
+ fprintf(fout, "%s", str.c_str());
+
+ for (auto it : netlist_cell_types) {
+ const char *sep = "";
+ fprintf(fout, " %s %s (", it.second.c_str(), it.first.c_str());
+ for (auto port : netlist_cells[it.first]) {
+ fprintf(fout, "%s\n .%s(%s)", sep, port.first.c_str(), port.second.c_str());
+ sep = ",";
+ }
+ fprintf(fout, "\n );\n");
+ }
+
+ fprintf(fout, "endmodule\n");
+
+ return 0;
+}