diff options
-rw-r--r-- | icefuzz/pinloc/.gitignore | 5 | ||||
-rw-r--r-- | icetime/.gitignore | 3 | ||||
-rw-r--r-- | icetime/Makefile | 24 | ||||
-rw-r--r-- | icetime/cells.v | 686 | ||||
-rw-r--r-- | icetime/icetime.cc | 653 |
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; +} |