mirror of https://github.com/YosysHQ/icestorm.git
Merge pull request #119 from daveshah1/up5k_improve
UltraPlus Timing Analysis Improvements
This commit is contained in:
commit
722790ad3c
|
|
@ -11,3 +11,4 @@ bitdata_*.txt
|
||||||
data_*.txt
|
data_*.txt
|
||||||
database_*.txt
|
database_*.txt
|
||||||
timings_*.html
|
timings_*.html
|
||||||
|
tmedges_unrenamed.tmp
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ endif
|
||||||
timings:
|
timings:
|
||||||
ifeq ($(DEVICECLASS),5k)
|
ifeq ($(DEVICECLASS),5k)
|
||||||
cp tmedges.txt tmedges.tmp
|
cp tmedges.txt tmedges.tmp
|
||||||
set -e; for f in work_$(DEVICECLASS)_*/*.vsb; do echo $$f; sed '/defparam/d' < $$f > $$f.fixed; yosys -q -f verilog -s tmedges.ys $$f.fixed; done
|
set -e; for f in work_$(DEVICECLASS)_*/*.vsb; do echo $$f; sed '/defparam/d' < $$f > $$f.fixed; yosys -q -f verilog -s tmedges.ys $$f.fixed; python3 rename_dsps.py $$f; done
|
||||||
sort -u tmedges.tmp > tmedges.txt && rm -f tmedges.tmp
|
sort -u tmedges.tmp > tmedges.txt && rm -f tmedges.tmp
|
||||||
python3 timings.py -t timings_up5k.txt work_*/*.sdf > timings_up5k.new
|
python3 timings.py -t timings_up5k.txt work_*/*.sdf > timings_up5k.new
|
||||||
mv timings_up5k.new timings_up5k.txt
|
mv timings_up5k.new timings_up5k.txt
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,10 @@ case "${ICEDEV:-hx1k-tq144}" in
|
||||||
iCEPACKAGE="SG48"
|
iCEPACKAGE="SG48"
|
||||||
iCE40DEV="iCE40UP5K"
|
iCE40DEV="iCE40UP5K"
|
||||||
;;
|
;;
|
||||||
|
up5k-uwg30)
|
||||||
|
iCEPACKAGE="UWG30"
|
||||||
|
iCE40DEV="iCE40UP5K"
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo "ERROR: Invalid \$ICEDEV device config '$ICEDEV'."
|
echo "ERROR: Invalid \$ICEDEV device config '$ICEDEV'."
|
||||||
exit 1
|
exit 1
|
||||||
|
|
@ -379,8 +383,8 @@ cat > foobar_sbt.project << EOT
|
||||||
Implementations=foobar_Implmnt
|
Implementations=foobar_Implmnt
|
||||||
|
|
||||||
[foobar_Implmnt]
|
[foobar_Implmnt]
|
||||||
DeviceFamily=$( echo $iCE40DEV | sed -re 's,(HX).*,,'; )
|
DeviceFamily=$( echo $iCE40DEV | sed -re 's,(HX|5K).*,,'; )
|
||||||
Device=$( echo $iCE40DEV | sed -re 's,iCE40,,'; )
|
Device=$( echo $iCE40DEV | sed -re 's,iCE40(UP)?,,'; )
|
||||||
DevicePackage=$iCEPACKAGE
|
DevicePackage=$iCEPACKAGE
|
||||||
Devicevoltage=1.14
|
Devicevoltage=1.14
|
||||||
DevicevoltagePerformance=+/-5%(datasheet default)
|
DevicevoltagePerformance=+/-5%(datasheet default)
|
||||||
|
|
@ -419,4 +423,3 @@ fi
|
||||||
|
|
||||||
export LD_LIBRARY_PATH=""
|
export LD_LIBRARY_PATH=""
|
||||||
$scriptdir/../icepack/iceunpack "$1.bin" "$1.asc"
|
$scriptdir/../icepack/iceunpack "$1.bin" "$1.asc"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,14 +19,41 @@ def randbin(n):
|
||||||
#Only certain combinations are allowed in icecube, list them here
|
#Only certain combinations are allowed in icecube, list them here
|
||||||
#This is not a complete set, but enough to cover all bits except cbit13, which
|
#This is not a complete set, but enough to cover all bits except cbit13, which
|
||||||
#is not set in any allowed config (?)
|
#is not set in any allowed config (?)
|
||||||
allowed_configs = ["0010000010000001001110110", "1110000010000001001110110", "0010000010000001000000000", "1110000010000001000000000",
|
allowed_configs = [("0010000010000001001110110", "SB_MAC16_MUL_U_8X8_ALL_PIPELINE"),
|
||||||
"0000000011000001111110110", "1100000011000001111110110", "0000000011000001110000110", "0010000101000010111111111",
|
("1110000010000001001110110", "SB_MAC16_MUL_S_8X8_ALL_PIPELINE"),
|
||||||
"0000001001100100111111111", "0001001001100100111111111", "0001101001100100111111111", "0001111000101100000000000"]
|
("0010000010000001000000000", "SB_MAC16_MUL_U_8X8_BYPASS"),
|
||||||
|
("1110000010000001000000000", "SB_MAC16_MUL_S_8X8_BYPASS"),
|
||||||
|
("0000000011000001111110110", "SB_MAC16_MUL_U_16X16_ALL_PIPELINE"),
|
||||||
|
("1100000011000001111110110", "SB_MAC16_MUL_S_16X16_ALL_PIPELINE"),
|
||||||
|
("0000000011000001110000110", "SB_MAC16_MUL_U_16X16_IM_BYPASS"),
|
||||||
|
("1100000011000001110000110", "SB_MAC16_MUL_S_16X16_IM_BYPASS"),
|
||||||
|
("0000000011000001100000000", "SB_MAC16_MUL_U_16X16_BYPASS"),
|
||||||
|
("1100000011000001100000000", "SB_MAC16_MUL_S_16X16_BYPASS"),
|
||||||
|
("0010000101000010111111111", "SB_MAC16_MAC_U_8X8_ALL_PIPELINE"),
|
||||||
|
("0010000101000010100001111", "SB_MAC16_MAC_U_8X8_IM_BYPASS"),
|
||||||
|
("0010000101000010100000000", "SB_MAC16_MAC_U_8X8_BYPASS"),
|
||||||
|
("0000001001100100111111111", "SB_MAC16_MAC_U_16X16_ALL_PIPELINE"),
|
||||||
|
("0001001001100100111111111", "SB_MAC16_MAC_U_16X16_CASC_ALL_PIPELINE"),
|
||||||
|
("0001101001100100111111111", "SB_MAC16_MAC_U_16X16_CIN_ALL_PIPELINE"),
|
||||||
|
("0000001001100100110001111", "SB_MAC16_MAC_U_16X16_IM_BYPASS"),
|
||||||
|
("0000001001100100100000000", "SB_MAC16_MAC_U_16X16_BYPASS"),
|
||||||
|
("1100001001100100110001111", "SB_MAC16_MAC_S_16X16_IM_BYPASS"),
|
||||||
|
("0010000001000000100001111", "SB_MAC16_ACC_U_16P16_ALL_PIPELINE"),
|
||||||
|
("0010000001000000100000000", "SB_MAC16_ACC_U_16P16_BYPASS"),
|
||||||
|
("0010000001100000100001111", "SB_MAC16_ACC_U_32P32_ALL_PIPELINE"),
|
||||||
|
("0010000001100000100000000", "SB_MAC16_ACC_U_32P32_BYPASS"),
|
||||||
|
("0010010001001000100001111", "SB_MAC16_ADS_U_16P16_ALL_PIPELINE"),
|
||||||
|
("0010010000001000000000000", "SB_MAC16_ADS_U_16P16_BYPASS"),
|
||||||
|
("0010010001101000100001111", "SB_MAC16_ADS_U_32P32_ALL_PIPELINE"),
|
||||||
|
("0010010000101000000000000", "SB_MAC16_ADS_U_32P32_BYPASS"),
|
||||||
|
("0010010101001010111111111", "SB_MAC16_MAS_U_8X8_ALL_PIPELINE")]
|
||||||
|
|
||||||
|
|
||||||
coverage = set()
|
coverage = set()
|
||||||
for c in allowed_configs:
|
for c in allowed_configs:
|
||||||
|
cfg, name = c
|
||||||
for i in range(25):
|
for i in range(25):
|
||||||
if c[i] == "1":
|
if cfg[i] == "1":
|
||||||
coverage.add(i)
|
coverage.add(i)
|
||||||
|
|
||||||
assert len(coverage) >= 24
|
assert len(coverage) >= 24
|
||||||
|
|
@ -37,6 +64,13 @@ assert len(coverage) >= 24
|
||||||
for idx in range(num):
|
for idx in range(num):
|
||||||
with open(working_dir + "/dsp_%02d.v" % idx, "w") as f:
|
with open(working_dir + "/dsp_%02d.v" % idx, "w") as f:
|
||||||
glbs = ["glb[%d]" % i for i in range(np.random.randint(8)+1)]
|
glbs = ["glb[%d]" % i for i in range(np.random.randint(8)+1)]
|
||||||
|
|
||||||
|
config = allowed_configs[np.random.randint(len(allowed_configs))]
|
||||||
|
params, cfgname = config
|
||||||
|
with open(working_dir + "/dsp_%02d.dsp" % idx, "w") as dspf:
|
||||||
|
dspf.write(cfgname + "\n")
|
||||||
|
params = params[::-1]
|
||||||
|
|
||||||
# TODO: ce should be on this list, but causes routing failures
|
# TODO: ce should be on this list, but causes routing failures
|
||||||
glbs_choice = ["clk", "a", "b", "c", "d,", "ah", "bh", "ch", "dh", "irt", "irb", "ort", "orb", "olt", "olb", "ast", "asb", "oht", "ohb", "sei"]
|
glbs_choice = ["clk", "a", "b", "c", "d,", "ah", "bh", "ch", "dh", "irt", "irb", "ort", "orb", "olt", "olb", "ast", "asb", "oht", "ohb", "sei"]
|
||||||
print("""
|
print("""
|
||||||
|
|
@ -118,8 +152,7 @@ for idx in range(num):
|
||||||
bits_d = "{%s}" % ", ".join(bits_d)
|
bits_d = "{%s}" % ", ".join(bits_d)
|
||||||
|
|
||||||
negclk = randbin(1)
|
negclk = randbin(1)
|
||||||
params = np.random.choice(allowed_configs)
|
|
||||||
params = params[::-1]
|
|
||||||
print("""
|
print("""
|
||||||
wire [34:0] out_%d;
|
wire [34:0] out_%d;
|
||||||
SB_MAC16 #(
|
SB_MAC16 #(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys, os
|
||||||
|
|
||||||
|
dsptype = None
|
||||||
|
dsppath = sys.argv[1].replace(".vsb", ".dsp")
|
||||||
|
|
||||||
|
if os.path.exists(dsppath):
|
||||||
|
with open(dsppath, 'r') as f:
|
||||||
|
dsptype = f.readline().strip()
|
||||||
|
|
||||||
|
with open("tmedges.tmp", "a") as outfile:
|
||||||
|
with open("tmedges_unrenamed.tmp", "r") as infile:
|
||||||
|
for line in infile:
|
||||||
|
if "SB_MAC16" in line:
|
||||||
|
if dsptype is not None:
|
||||||
|
outfile.write(line.replace("SB_MAC16", dsptype))
|
||||||
|
else:
|
||||||
|
outfile.write(line)
|
||||||
|
|
@ -227,6 +227,12 @@ for filename in sdf_inputs:
|
||||||
for stmt in cell:
|
for stmt in cell:
|
||||||
if stmt[0] == "CELLTYPE":
|
if stmt[0] == "CELLTYPE":
|
||||||
celltype = rewrite_celltype(stmt[1][1:-1])
|
celltype = rewrite_celltype(stmt[1][1:-1])
|
||||||
|
if celltype == "SB_MAC16":
|
||||||
|
try:
|
||||||
|
with open(filename.replace(".sdf", ".dsp"), "r") as dspf:
|
||||||
|
celltype = dspf.readline().strip()
|
||||||
|
except:
|
||||||
|
break
|
||||||
database.setdefault(celltype, set())
|
database.setdefault(celltype, set())
|
||||||
|
|
||||||
if stmt[0] == "DELAY":
|
if stmt[0] == "DELAY":
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
while true; do
|
||||||
|
rm -rf data_5k_*.txt work_5k_*
|
||||||
|
make DEVICECLASS=5k -j3
|
||||||
|
make DEVICECLASS=5k timings
|
||||||
|
done
|
||||||
16416
icefuzz/timings_up5k.txt
16416
icefuzz/timings_up5k.txt
File diff suppressed because it is too large
Load Diff
5043
icefuzz/tmedges.txt
5043
icefuzz/tmedges.txt
File diff suppressed because it is too large
Load Diff
|
|
@ -29,4 +29,4 @@ hierarchy -generate gio2CtrlBuf i:I o:O
|
||||||
hierarchy -generate CascadeBuf i:I o:O
|
hierarchy -generate CascadeBuf i:I o:O
|
||||||
|
|
||||||
hierarchy -check
|
hierarchy -check
|
||||||
tee -a tmedges.tmp edgetypes
|
tee -o tmedges_unrenamed.tmp edgetypes
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,11 @@ std::set<int> declared_nets;
|
||||||
int dangling_cnt = 0;
|
int dangling_cnt = 0;
|
||||||
|
|
||||||
std::map<std::string, std::vector<std::pair<int, int>>> logic_tile_bits,
|
std::map<std::string, std::vector<std::pair<int, int>>> logic_tile_bits,
|
||||||
io_tile_bits, ramb_tile_bits, ramt_tile_bits;
|
io_tile_bits, ramb_tile_bits, ramt_tile_bits, ipcon_tile_bits, dsp0_tile_bits,
|
||||||
|
dsp1_tile_bits, dsp2_tile_bits, dsp3_tile_bits;
|
||||||
|
|
||||||
|
std::map<std::tuple<std::string, int, int, int>,
|
||||||
|
std::map<std::string, std::tuple<int, int, std::string>>> extra_cells;
|
||||||
|
|
||||||
std::string vstringf(const char *fmt, va_list ap)
|
std::string vstringf(const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
|
|
@ -328,8 +332,9 @@ void read_chipdb()
|
||||||
|
|
||||||
std::string mode;
|
std::string mode;
|
||||||
int current_net = -1;
|
int current_net = -1;
|
||||||
int tile_x = -1, tile_y = -1;
|
int tile_x = -1, tile_y = -1, cell_z = -1;
|
||||||
std::string thiscfg;
|
std::string thiscfg;
|
||||||
|
std::string cellname;
|
||||||
|
|
||||||
std::vector<std::vector<int>> gbufin;
|
std::vector<std::vector<int>> gbufin;
|
||||||
std::vector<std::vector<int>> gbufpin;
|
std::vector<std::vector<int>> gbufpin;
|
||||||
|
|
@ -377,6 +382,22 @@ void read_chipdb()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mode == ".extra_cell") {
|
||||||
|
tile_x = atoi(strtok(nullptr, " \t\r\n"));
|
||||||
|
tile_y = atoi(strtok(nullptr, " \t\r\n"));
|
||||||
|
// For legacy reasons, extra_cell may be X Y name or X Y Z name
|
||||||
|
const char *z_or_name = strtok(nullptr, " \t\r\n");
|
||||||
|
if(isdigit(z_or_name[0])) {
|
||||||
|
cell_z = atoi(z_or_name);
|
||||||
|
cellname = std::string(strtok(nullptr, " \t\r\n"));
|
||||||
|
} else {
|
||||||
|
cell_z = 0;
|
||||||
|
cellname = std::string(z_or_name);
|
||||||
|
}
|
||||||
|
extra_cells[std::make_tuple(cellname, tile_x, tile_y, cell_z)] = {};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -432,7 +453,8 @@ void read_chipdb()
|
||||||
gbufpin.push_back(items);
|
gbufpin.push_back(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == ".logic_tile_bits" || mode == ".io_tile_bits" || mode == ".ramb_tile_bits" || mode == ".ramt_tile_bits") {
|
if (mode == ".logic_tile_bits" || mode == ".io_tile_bits" || mode == ".ramb_tile_bits" || mode == ".ramt_tile_bits" ||
|
||||||
|
mode == ".ipcon_tile_bits" || mode == ".dsp0_tile_bits" || mode == ".dsp1_tile_bits" || mode == ".dsp2_tile_bits" || mode == ".dsp3_tile_bits") {
|
||||||
std::vector<std::pair<int, int>> items;
|
std::vector<std::pair<int, int>> items;
|
||||||
while (1) {
|
while (1) {
|
||||||
const char *s = strtok(nullptr, " \t\r\n");
|
const char *s = strtok(nullptr, " \t\r\n");
|
||||||
|
|
@ -451,6 +473,16 @@ void read_chipdb()
|
||||||
ramb_tile_bits[tok] = items;
|
ramb_tile_bits[tok] = items;
|
||||||
if (mode == ".ramt_tile_bits")
|
if (mode == ".ramt_tile_bits")
|
||||||
ramt_tile_bits[tok] = items;
|
ramt_tile_bits[tok] = items;
|
||||||
|
if (mode == ".ipcon_tile_bits")
|
||||||
|
ipcon_tile_bits[tok] = items;
|
||||||
|
if (mode == ".dsp0_tile_bits")
|
||||||
|
dsp0_tile_bits[tok] = items;
|
||||||
|
if (mode == ".dsp1_tile_bits")
|
||||||
|
dsp1_tile_bits[tok] = items;
|
||||||
|
if (mode == ".dsp2_tile_bits")
|
||||||
|
dsp2_tile_bits[tok] = items;
|
||||||
|
if (mode == ".dsp3_tile_bits")
|
||||||
|
dsp3_tile_bits[tok] = items;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == ".extra_bits") {
|
if (mode == ".extra_bits") {
|
||||||
|
|
@ -461,6 +493,17 @@ void read_chipdb()
|
||||||
if (extra_bits.count(key))
|
if (extra_bits.count(key))
|
||||||
extrabitfunc.insert(tok);
|
extrabitfunc.insert(tok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(mode == ".extra_cell") {
|
||||||
|
std::string key = std::string(tok);
|
||||||
|
if(key != "LOCKED") {
|
||||||
|
int x = atoi(strtok(nullptr, " \t\r\n"));
|
||||||
|
int y = atoi(strtok(nullptr, " \t\r\n"));
|
||||||
|
std::string name = std::string(strtok(nullptr, " \t\r\n"));
|
||||||
|
extra_cells[make_tuple(cellname, tile_x, tile_y, cell_z)][key] = make_tuple(x, y, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fdb);
|
fclose(fdb);
|
||||||
|
|
@ -559,6 +602,14 @@ bool is_primary(std::string cell_name, std::string out_port)
|
||||||
if (cell_type == "PRE_IO")
|
if (cell_type == "PRE_IO")
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (cell_type == "SB_SPRAM256KA")
|
||||||
|
return true;
|
||||||
|
|
||||||
|
std::string dsp_prefix = "SB_MAC16";
|
||||||
|
if(cell_type.substr(0, dsp_prefix.length()) == dsp_prefix)
|
||||||
|
return (cell_type != "SB_MAC16_MUL_U_16X16_BYPASS" && cell_type != "SB_MAC16_MUL_U_8X8_BYPASS"
|
||||||
|
&& cell_type != "SB_MAC16_ADS_U_16P16_BYPASS" && cell_type != "SB_MAC16_ADS_U_32P32_BYPASS");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -647,14 +698,42 @@ const std::set<std::string> &get_inports(std::string cell_type)
|
||||||
inports_map["SB_RAM40_4K"].insert(stringf("WADDR[%d]", i));
|
inports_map["SB_RAM40_4K"].insert(stringf("WADDR[%d]", i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inports_map["SB_MAC16"] = { "CLK", "CE", "AHOLD", "BHOLD", "CHOLD", "DHOLD", "IRSTTOP", "IRSTBOT", "ORSTTOP", "ORSTBOT",
|
||||||
|
"OLOADTOP", "OLOADBOT", "ADDSUBTOP", "ADDSUBBOT", "OHOLDTOP", "OHOLDBOT", "CI", "ACCUMCI",
|
||||||
|
"SIGNEXTIN"};
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
inports_map["SB_MAC16"].insert(stringf("C[%d]", i));
|
||||||
|
inports_map["SB_MAC16"].insert(stringf("A[%d]", i));
|
||||||
|
inports_map["SB_MAC16"].insert(stringf("B[%d]", i));
|
||||||
|
inports_map["SB_MAC16"].insert(stringf("D[%d]", i));
|
||||||
|
}
|
||||||
|
|
||||||
|
inports_map["SB_SPRAM256KA"] = { "WREN", "CHIPSELECT", "CLOCK", "STANDBY", "SLEEP", "POWEROFF",
|
||||||
|
"MASKWREN[0]", "MASKWREN[1]", "MASKWREN[2]", "MASKWREN[3]"};
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
inports_map["SB_SPRAM256KA"].insert(stringf("DATAIN[%d]", i));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 14; i++) {
|
||||||
|
inports_map["SB_SPRAM256KA"].insert(stringf("ADDRESS[%d]", i));
|
||||||
|
}
|
||||||
|
|
||||||
inports_map["INTERCONN"] = { "I" };
|
inports_map["INTERCONN"] = { "I" };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string dsp_prefix = "SB_MAC16";
|
||||||
|
|
||||||
|
if(cell_type.substr(0, dsp_prefix.length()) == dsp_prefix)
|
||||||
|
cell_type = "SB_MAC16";
|
||||||
|
|
||||||
if (inports_map.count(cell_type) == 0) {
|
if (inports_map.count(cell_type) == 0) {
|
||||||
fprintf(stderr, "Missing entry in inports_map for cell type %s!\n", cell_type.c_str());
|
fprintf(stderr, "Missing entry in inports_map for cell type %s!\n", cell_type.c_str());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return inports_map.at(cell_type);
|
return inports_map.at(cell_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -679,7 +758,7 @@ double get_delay(std::string cell_type, std::string in_port, std::string out_por
|
||||||
|
|
||||||
if (device_type == "hx8k")
|
if (device_type == "hx8k")
|
||||||
return get_delay_hx8k(cell_type, in_port, out_port);
|
return get_delay_hx8k(cell_type, in_port, out_port);
|
||||||
|
|
||||||
if (device_type == "up5k")
|
if (device_type == "up5k")
|
||||||
return get_delay_up5k(cell_type, in_port, out_port);
|
return get_delay_up5k(cell_type, in_port, out_port);
|
||||||
fprintf(stderr, "No built-in timing database for '%s' devices!\n", device_type.c_str());
|
fprintf(stderr, "No built-in timing database for '%s' devices!\n", device_type.c_str());
|
||||||
|
|
@ -1182,6 +1261,174 @@ std::string make_lc40(int x, int y, int z)
|
||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool get_dsp_ip_cbit(std::tuple<int, int, std::string> cbit) {
|
||||||
|
std::string name = "IpConfig." + std::get<2>(cbit);
|
||||||
|
// DSP0 contains all CBITs, the same as any DSP/IP tile
|
||||||
|
if(dsp0_tile_bits.count(name)) {
|
||||||
|
auto bitpos = dsp0_tile_bits.at(name)[0];
|
||||||
|
return config_bits[std::get<0>(cbit)][std::get<1>(cbit)][bitpos.first][bitpos.second];
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ecnetname_to_vlog(std::string ec_name)
|
||||||
|
{
|
||||||
|
// Convert a net name from the form A_0 used in the chipdb for extra cells to
|
||||||
|
// verilog form A[0]
|
||||||
|
size_t last_ = ec_name.find_last_of('_');
|
||||||
|
if(last_ == std::string::npos)
|
||||||
|
return ec_name;
|
||||||
|
|
||||||
|
std::string base = ec_name.substr(0, last_);
|
||||||
|
std::string end = ec_name.substr(last_+1);
|
||||||
|
size_t nidx = 0;
|
||||||
|
|
||||||
|
int num = std::stoi(end, &nidx, 10);
|
||||||
|
if(nidx == end.length()) {
|
||||||
|
return base + "[" + std::to_string(num) + "]";
|
||||||
|
} else {
|
||||||
|
return ec_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string make_dsp_ip(int x, int y, std::string net, std::string &primnet)
|
||||||
|
{
|
||||||
|
std::tuple<int, int, std::string> ecnet(x, y, net);
|
||||||
|
std::tuple<std::string, int, int, int> key("", -1, -1, -1);
|
||||||
|
bool found = false;
|
||||||
|
for(auto ec : extra_cells) {
|
||||||
|
for(auto entry : ec.second) {
|
||||||
|
if(entry.second == ecnet) {
|
||||||
|
key = ec.first;
|
||||||
|
primnet = ecnetname_to_vlog(entry.first);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!found) {
|
||||||
|
fprintf(stderr, "Error: net (%d, %d, '%s') does not correspond to any IP\n", x, y, net.c_str());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
int cx, cy, cz;
|
||||||
|
std::string ectype;
|
||||||
|
std::tie(ectype, cx, cy, cz) = key;
|
||||||
|
|
||||||
|
auto cell = stringf("%s_%d_%d_%d", ectype.c_str(), cx, cy, cz);
|
||||||
|
|
||||||
|
if (netlist_cell_types.count(cell))
|
||||||
|
return cell;
|
||||||
|
|
||||||
|
if(ectype == "MAC16") {
|
||||||
|
// Given the few actual unique timing possibilites, only look at a subset
|
||||||
|
// of the CBITs to pick the closest cell type from a timing point of view
|
||||||
|
std::string dsptype = "";
|
||||||
|
bool mode_8x8 = get_dsp_ip_cbit(extra_cells[key].at("MODE_8x8"));
|
||||||
|
// It seems no different between any pipeline mode, so pick pipelining based
|
||||||
|
// on one of the bits
|
||||||
|
bool pipeline = get_dsp_ip_cbit(extra_cells[key].at("A_REG"));
|
||||||
|
int botout = (get_dsp_ip_cbit(extra_cells[key].at("BOTOUTPUT_SELECT_1")) << 1) | get_dsp_ip_cbit(extra_cells[key].at("BOTOUTPUT_SELECT_0"));
|
||||||
|
int botlwrin = (get_dsp_ip_cbit(extra_cells[key].at("BOTADDSUB_LOWERINPUT_1")) << 1) | get_dsp_ip_cbit(extra_cells[key].at("BOTADDSUB_LOWERINPUT_0"));
|
||||||
|
bool botuprin = get_dsp_ip_cbit(extra_cells[key].at("BOTADDSUB_UPPERINPUT"));
|
||||||
|
int topcarry = (get_dsp_ip_cbit(extra_cells[key].at("TOPADDSUB_CARRYSELECT_1")) << 1) | get_dsp_ip_cbit(extra_cells[key].at("TOPADDSUB_CARRYSELECT_0"));
|
||||||
|
// Worst case default
|
||||||
|
std::string basename = "SB_MAC16_MUL_U_16X16";
|
||||||
|
// Note: signedness is ignored as it seems to have no effect
|
||||||
|
if(mode_8x8 && !botuprin && (botlwrin == 0) && (botout == 2)) {
|
||||||
|
basename = "SB_MAC16_MUL_U_8X8";
|
||||||
|
} else if (!mode_8x8 && !botuprin && (botlwrin == 0) && (botout == 3)) {
|
||||||
|
basename = "SB_MAC16_MUL_U_16X16";
|
||||||
|
} else if (mode_8x8 && !botuprin && (botlwrin == 1) && (botout == 1)) {
|
||||||
|
basename = "SB_MAC16_MAC_U_8X8";
|
||||||
|
} else if (!mode_8x8 && !botuprin && (botlwrin == 2) && (botout == 1)) {
|
||||||
|
basename = "SB_MAC16_MAC_U_16X16";
|
||||||
|
} else if (mode_8x8 && !botuprin && (botlwrin == 0) && (botout == 1) && (topcarry == 0)) {
|
||||||
|
basename = "SB_MAC16_ACC_U_16P16";
|
||||||
|
} else if (mode_8x8 && !botuprin && (botlwrin == 0) && (botout == 1) && (topcarry == 2)) {
|
||||||
|
basename = "SB_MAC16_ACC_U_32P32";
|
||||||
|
} else if (mode_8x8 && botuprin && (botlwrin == 0) && (topcarry == 0)) {
|
||||||
|
basename = "SB_MAC16_ADS_U_16P16";
|
||||||
|
} else if (mode_8x8 && botuprin && (botlwrin == 0) && (topcarry == 2)) {
|
||||||
|
basename = "SB_MAC16_ADS_U_32P32";
|
||||||
|
} else if (mode_8x8 && botuprin && (botlwrin == 1)) {
|
||||||
|
basename = "SB_MAC16_MAS_U_8X8";
|
||||||
|
} else if (!mode_8x8 && botuprin && (botlwrin == 2)) {
|
||||||
|
basename = "SB_MAC16_MAS_U_16X16";
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Warning: detected unknown/unsupported DSP config, defaulting to 16x16 MUL.\n");
|
||||||
|
}
|
||||||
|
dsptype = basename + (pipeline ? "_ALL_PIPELINE" : "_BYPASS");
|
||||||
|
netlist_cell_types[cell] = dsptype;
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
netlist_cell_ports[cell][stringf("C[%d]", i)] = "gnd";
|
||||||
|
netlist_cell_ports[cell][stringf("A[%d]", i)] = "gnd";
|
||||||
|
netlist_cell_ports[cell][stringf("B[%d]", i)] = "gnd";
|
||||||
|
netlist_cell_ports[cell][stringf("D[%d]", i)] = "gnd";
|
||||||
|
}
|
||||||
|
|
||||||
|
netlist_cell_ports[cell]["CLK"] = "";
|
||||||
|
netlist_cell_ports[cell]["CE"] = "";
|
||||||
|
netlist_cell_ports[cell]["AHOLD"] = "gnd";
|
||||||
|
netlist_cell_ports[cell]["BHOLD"] = "gnd";
|
||||||
|
netlist_cell_ports[cell]["CHOLD"] = "gnd";
|
||||||
|
netlist_cell_ports[cell]["DHOLD"] = "gnd";
|
||||||
|
|
||||||
|
netlist_cell_ports[cell]["IRSTTOP"] = "";
|
||||||
|
netlist_cell_ports[cell]["IRSTBOT"] = "";
|
||||||
|
netlist_cell_ports[cell]["ORSTTOP"] = "";
|
||||||
|
netlist_cell_ports[cell]["ORSTBOT"] = "";
|
||||||
|
|
||||||
|
netlist_cell_ports[cell]["OLOADTOP"] = "gnd";
|
||||||
|
netlist_cell_ports[cell]["OLOADBOT"] = "gnd";
|
||||||
|
netlist_cell_ports[cell]["ADDSUBTOP"] = "gnd";
|
||||||
|
netlist_cell_ports[cell]["ADDSUBBOT"] = "gnd";
|
||||||
|
netlist_cell_ports[cell]["OHOLDTOP"] = "gnd";
|
||||||
|
netlist_cell_ports[cell]["OHOLDBOT"] = "gnd";
|
||||||
|
netlist_cell_ports[cell]["CI"] = "gnd";
|
||||||
|
netlist_cell_ports[cell]["ACCUMCI"] = "";
|
||||||
|
netlist_cell_ports[cell]["SIGNEXTIN"] = "";
|
||||||
|
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
netlist_cell_ports[cell][stringf("O[%d]", i)] = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
netlist_cell_ports[cell]["ACCUMCO"] = "";
|
||||||
|
netlist_cell_ports[cell]["SIGNEXTOUT"] = "";
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
} else if(ectype == "SPRAM") {
|
||||||
|
netlist_cell_types[cell] = "SB_SPRAM256KA";
|
||||||
|
|
||||||
|
for (int i = 0; i < 14; i++) {
|
||||||
|
netlist_cell_ports[cell][stringf("ADDRESS[%d]", i)] = "gnd";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
netlist_cell_ports[cell][stringf("DATAIN[%d]", i)] = "gnd";
|
||||||
|
netlist_cell_ports[cell][stringf("DATAOUT[%d]", i)] = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
netlist_cell_ports[cell]["MASKWREN[3]"] = "gnd";
|
||||||
|
netlist_cell_ports[cell]["MASKWREN[2]"] = "gnd";
|
||||||
|
netlist_cell_ports[cell]["MASKWREN[1]"] = "gnd";
|
||||||
|
netlist_cell_ports[cell]["MASKWREN[0]"] = "gnd";
|
||||||
|
|
||||||
|
netlist_cell_ports[cell]["WREN"] = "gnd";
|
||||||
|
netlist_cell_ports[cell]["CHIPSELECT"] = "gnd";
|
||||||
|
netlist_cell_ports[cell]["CLOCK"] = "";
|
||||||
|
netlist_cell_ports[cell]["STANDBY"] = "gnd";
|
||||||
|
netlist_cell_ports[cell]["SLEEP"] = "gnd";
|
||||||
|
netlist_cell_ports[cell]["POWEROFF"] = "gnd";
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
} else {
|
||||||
|
netlist_cell_types[cell] = "SB_" + ectype;
|
||||||
|
fprintf(stderr, "Warning: timing analysis not supported for cell type %s\n", ectype.c_str());
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string make_ram(int x, int y)
|
std::string make_ram(int x, int y)
|
||||||
{
|
{
|
||||||
auto cell = stringf("ram_%d_%d", x, y);
|
auto cell = stringf("ram_%d_%d", x, y);
|
||||||
|
|
@ -1316,14 +1563,26 @@ void make_seg_cell(int net, const net_segment_t &seg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sscanf(seg.name.c_str(), "lutff_%d/in_%d", &a, &b) == 2) {
|
if (sscanf(seg.name.c_str(), "lutff_%d/in_%d", &a, &b) == 2) {
|
||||||
auto cell = make_lc40(seg.x, seg.y, a);
|
//"logic" wires at the side of the device are actually IP or DSP
|
||||||
if (b == 2) {
|
if(device_type == "up5k" && ((seg.x == 0) || (seg.x == config_tile_type.size() - 1))) {
|
||||||
// Lattice tools always put a CascadeMux on in2
|
std::string primnet;
|
||||||
netlist_cell_ports[cell][stringf("in%d", b)] = cascademuxed(net_name(net));
|
auto cell = make_dsp_ip(seg.x, seg.y, seg.name, primnet);
|
||||||
|
netlist_cell_ports[cell][primnet] = net_name(net);
|
||||||
|
if(cell != "") {
|
||||||
|
make_inmux(seg.x, seg.y, net);
|
||||||
|
}
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
netlist_cell_ports[cell][stringf("in%d", b)] = net_name(net);
|
auto cell = make_lc40(seg.x, seg.y, a);
|
||||||
|
if (b == 2) {
|
||||||
|
// Lattice tools always put a CascadeMux on in2
|
||||||
|
netlist_cell_ports[cell][stringf("in%d", b)] = cascademuxed(net_name(net));
|
||||||
|
} else {
|
||||||
|
netlist_cell_ports[cell][stringf("in%d", b)] = net_name(net);
|
||||||
|
}
|
||||||
|
make_inmux(seg.x, seg.y, net);
|
||||||
}
|
}
|
||||||
make_inmux(seg.x, seg.y, net);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1345,6 +1604,28 @@ void make_seg_cell(int net, const net_segment_t &seg)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sscanf(seg.name.c_str(), "slf_op_%d", &a) == 1)
|
||||||
|
{
|
||||||
|
std::string primnet;
|
||||||
|
auto cell = make_dsp_ip(seg.x, seg.y, seg.name, primnet);
|
||||||
|
if(cell != "") {
|
||||||
|
netlist_cell_ports[cell][primnet] = net_name(net);
|
||||||
|
make_odrv(seg.x, seg.y, net);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sscanf(seg.name.c_str(), "mult/O_%d", &a) == 1)
|
||||||
|
{
|
||||||
|
std::string primnet;
|
||||||
|
auto cell = make_dsp_ip(seg.x, seg.y, seg.name, primnet);
|
||||||
|
if(cell != "") {
|
||||||
|
netlist_cell_ports[cell][primnet] = net_name(net);
|
||||||
|
make_odrv(seg.x, seg.y, net);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (sscanf(seg.name.c_str(), "lutff_%d/cou%c", &a, &c) == 2 && c == 't')
|
if (sscanf(seg.name.c_str(), "lutff_%d/cou%c", &a, &c) == 2 && c == 't')
|
||||||
{
|
{
|
||||||
auto cell = make_lc40(seg.x, seg.y, a);
|
auto cell = make_lc40(seg.x, seg.y, a);
|
||||||
|
|
@ -2025,7 +2306,10 @@ int main(int argc, char **argv)
|
||||||
read_config();
|
read_config();
|
||||||
|
|
||||||
if (device_type.empty()) {
|
if (device_type.empty()) {
|
||||||
device_type = "lp" + config_device;
|
if(config_device == "5k")
|
||||||
|
device_type = "up" + config_device;
|
||||||
|
else
|
||||||
|
device_type = "lp" + config_device;
|
||||||
printf("// Warning: Missing -d parameter. Assuming '%s' device.\n", device_type.c_str());
|
printf("// Warning: Missing -d parameter. Assuming '%s' device.\n", device_type.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ def timings_to_c(chip, f):
|
||||||
print("{")
|
print("{")
|
||||||
|
|
||||||
in_cell = False
|
in_cell = False
|
||||||
|
last_cell = ""
|
||||||
for line in f:
|
for line in f:
|
||||||
fields = line.split()
|
fields = line.split()
|
||||||
if len(fields) == 0:
|
if len(fields) == 0:
|
||||||
|
|
@ -18,8 +18,14 @@ def timings_to_c(chip, f):
|
||||||
|
|
||||||
if fields[0] == "CELL":
|
if fields[0] == "CELL":
|
||||||
if in_cell:
|
if in_cell:
|
||||||
|
if last_cell.startswith("SB_MAC16"):
|
||||||
|
# DSPs have incomplete timing specification, as some paths
|
||||||
|
# don't mathematically exist - e.g. there is no path from
|
||||||
|
# A[1] to O[0]
|
||||||
|
print(" if (in_port != \"*clkedge*\" && out_port != \"*setup*\") return 0.0;")
|
||||||
print(" }")
|
print(" }")
|
||||||
print(" if (cell_type == \"%s\") {" % fields[1])
|
print(" if (cell_type == \"%s\") {" % fields[1])
|
||||||
|
last_cell = fields[1]
|
||||||
in_cell = True
|
in_cell = True
|
||||||
|
|
||||||
if fields[0] == "SETUP":
|
if fields[0] == "SETUP":
|
||||||
|
|
@ -44,4 +50,3 @@ def timings_to_c(chip, f):
|
||||||
for db in "lp384 lp1k lp8k hx1k hx8k up5k".split():
|
for db in "lp384 lp1k lp8k hx1k hx8k up5k".split():
|
||||||
with open("../icefuzz/timings_%s.txt" % db, "r") as f:
|
with open("../icefuzz/timings_%s.txt" % db, "r") as f:
|
||||||
timings_to_c(db, f);
|
timings_to_c(db, f);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue