mirror of https://github.com/YosysHQ/icestorm.git
icetime progress
This commit is contained in:
parent
d939d1b92f
commit
0cfb6eed91
8
Makefile
8
Makefile
|
|
@ -6,7 +6,7 @@ all:
|
|||
$(MAKE) -C iceprog
|
||||
$(MAKE) -C icemulti
|
||||
$(MAKE) -C icepll
|
||||
# $(MAKE) -C icetime
|
||||
$(MAKE) -C icetime
|
||||
|
||||
clean:
|
||||
$(MAKE) -C icebox clean
|
||||
|
|
@ -14,7 +14,7 @@ clean:
|
|||
$(MAKE) -C iceprog clean
|
||||
$(MAKE) -C icemulti clean
|
||||
$(MAKE) -C icepll clean
|
||||
# $(MAKE) -C icetime clean
|
||||
$(MAKE) -C icetime clean
|
||||
|
||||
install:
|
||||
$(MAKE) -C icebox install
|
||||
|
|
@ -22,7 +22,7 @@ install:
|
|||
$(MAKE) -C iceprog install
|
||||
$(MAKE) -C icemulti install
|
||||
$(MAKE) -C icepll install
|
||||
# $(MAKE) -C icetime install
|
||||
$(MAKE) -C icetime install
|
||||
|
||||
uninstall:
|
||||
$(MAKE) -C icebox uninstall
|
||||
|
|
@ -30,7 +30,7 @@ uninstall:
|
|||
$(MAKE) -C iceprog uninstall
|
||||
$(MAKE) -C icemulti uninstall
|
||||
$(MAKE) -C icepll uninstall
|
||||
# $(MAKE) -C icetime uninstall
|
||||
$(MAKE) -C icetime uninstall
|
||||
|
||||
.PHONY: all clean install uninstall
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
icetime
|
||||
timings.inc
|
||||
test[0-9]*
|
||||
*.d
|
||||
*.o
|
||||
|
|
|
|||
|
|
@ -6,6 +6,12 @@ all: icetime
|
|||
|
||||
icetime: icetime.o
|
||||
|
||||
icetime.o: icetime.cc timings.inc
|
||||
|
||||
timings.inc: timings.py
|
||||
python3 timings.py > timings.inc.new
|
||||
mv timings.inc.new timings.inc
|
||||
|
||||
install: all
|
||||
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
||||
cp icetime $(DESTDIR)$(PREFIX)/bin/icetime
|
||||
|
|
@ -24,7 +30,7 @@ test0 test1 test2 test3 test4 test5 test6 test7 test8 test9: icetime
|
|||
yosys $@.ys
|
||||
|
||||
run0 run1 run2 run3 run4 run5 run6 run7 run8 run9: icetime
|
||||
./icetime -P tq144 -p $(subst run,test,$@).pcf $(subst run,test,$@).asc $(subst run,test,$@)_out.v
|
||||
./icetime -t -P tq144 -p $(subst run,test,$@).pcf $(subst run,test,$@).asc $(subst run,test,$@)_out.v
|
||||
|
||||
show0 show1 show2 show3 show4 show5 show6 show7 show8 show9: icetime
|
||||
bash show.sh $(subst show,test,$@)
|
||||
|
|
@ -35,7 +41,7 @@ test: test0 test1 test2 test3 test4 test5 test6 test7 test8 test9
|
|||
show: show0 show1 show2 show3 show4 show5 show6 show7 show8 show9
|
||||
|
||||
clean:
|
||||
rm -f icetime *.o *.d
|
||||
rm -f icetime timings.inc *.o *.d
|
||||
rm -rf test[0-9]*
|
||||
|
||||
-include *.d
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#define MAX_SPAN_HACK 1
|
||||
|
||||
FILE *fin, *fout;
|
||||
bool verbose = false;
|
||||
|
||||
std::string config_device, selected_package;
|
||||
std::vector<std::vector<std::string>> config_tile_type;
|
||||
|
|
@ -460,28 +461,43 @@ void read_chipdb()
|
|||
std::pair<int, int>(x, y);
|
||||
}
|
||||
|
||||
|
||||
#if 1
|
||||
for (int net : used_nets)
|
||||
if (verbose)
|
||||
{
|
||||
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);
|
||||
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
|
||||
}
|
||||
|
||||
bool is_primary(std::string cell_name, std::string out_port)
|
||||
{
|
||||
auto cell_type = netlist_cell_types[cell_name];
|
||||
|
||||
if (cell_type == "SB_RAM40_4K")
|
||||
return true;
|
||||
|
||||
if (cell_type == "LogicCell40" && out_port == "lcout")
|
||||
{
|
||||
// SEQ_MODE = "4'bX...";
|
||||
bool dff_enable = netlist_cell_params[cell_name]["SEQ_MODE"][3] == '1';
|
||||
return dff_enable;
|
||||
}
|
||||
|
||||
if (cell_type == "PRE_IO")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -556,7 +572,7 @@ const std::set<std::string> &get_inports(std::string cell_type)
|
|||
inports_map["ICE_CARRY_IN_MUX"] = { "carryinitin" };
|
||||
|
||||
inports_map["LogicCell40"] = { "clk", "carryin", "in0", "in1", "in2", "in3", "sr", "ce" };
|
||||
inports_map["PRE_IO"] = { "INPUTCLK", "OUTPUTCLK", "LATCHINPUTVALUE", "CLOCKENABLE", "OUTPUTENABLE", "DOUT1", "DOUT0" };
|
||||
inports_map["PRE_IO"] = { "INPUTCLK", "OUTPUTCLK", "LATCHINPUTVALUE", "CLOCKENABLE", "OUTPUTENABLE", "DOUT1", "DOUT0", "PADIN" };
|
||||
|
||||
inports_map["SB_RAM40_4K"] = { "RCLK", "RCLKE", "RE", "WCLK", "WCLKE", "WE" };
|
||||
|
||||
|
|
@ -569,6 +585,8 @@ const std::set<std::string> &get_inports(std::string cell_type)
|
|||
inports_map["SB_RAM40_4K"].insert(stringf("RADDR[%d]", i));
|
||||
inports_map["SB_RAM40_4K"].insert(stringf("WADDR[%d]", i));
|
||||
}
|
||||
|
||||
inports_map["INTERCONN"] = { "I" };
|
||||
}
|
||||
|
||||
if (inports_map.count(cell_type) == 0) {
|
||||
|
|
@ -579,9 +597,21 @@ const std::set<std::string> &get_inports(std::string cell_type)
|
|||
return inports_map.at(cell_type);
|
||||
}
|
||||
|
||||
#include "timings.inc"
|
||||
|
||||
double get_delay(std::string cell_type, std::string in_port, std::string out_port)
|
||||
{
|
||||
return 1.0;
|
||||
if (cell_type == "INTERCONN")
|
||||
return 0;
|
||||
|
||||
if (config_device == "1k")
|
||||
return get_delay_1k(cell_type, in_port, out_port);
|
||||
|
||||
if (config_device == "8k")
|
||||
return get_delay_8k(cell_type, in_port, out_port);
|
||||
|
||||
fprintf(stderr, "No built-in timing database for '%s' devices!\n", config_device.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct TimingAnalysis
|
||||
|
|
@ -589,6 +619,9 @@ struct TimingAnalysis
|
|||
// net_driver[<net_name>] = { <cell_name>, <cell_port> }
|
||||
std::map<std::string, std::pair<std::string, std::string>> net_driver;
|
||||
|
||||
// net_max_setup[<net_name>] = { <setup_time>, <cell_name>, <cell_port> }
|
||||
std::map<std::string, std::tuple<double, std::string, std::string>> net_max_setup;
|
||||
|
||||
// net_max_path_parent[<net_name>] = { <parent_net>, <cell_name>, <inport>, <outport>, <delay> }
|
||||
std::map<std::string, std::tuple<std::string, std::string, std::string, std::string, double>> net_max_path_parent;
|
||||
|
||||
|
|
@ -609,20 +642,28 @@ struct TimingAnalysis
|
|||
|
||||
auto &driver_cell = net_driver.at(net).first;
|
||||
auto &driver_port = net_driver.at(net).second;
|
||||
auto &driver_type = netlist_cell_types.at(driver_cell);
|
||||
|
||||
if (is_primary(driver_cell, driver_port)) {
|
||||
net_max_path_delay[net] = 0;
|
||||
net_max_path_delay[net] = get_delay(driver_type, "*clkedge*", driver_port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto &driver_type = netlist_cell_types.at(driver_cell);
|
||||
auto &driver_inputs = get_inports(driver_type);
|
||||
|
||||
for (auto &inport : driver_inputs)
|
||||
for (auto &inport : get_inports(driver_type))
|
||||
{
|
||||
if (inport == "clk" || inport == "INPUTCLK" || inport == "OUTPUTCLK")
|
||||
if (inport == "clk" || inport == "INPUTCLK" || inport == "OUTPUTCLK" || inport == "PADIN")
|
||||
continue;
|
||||
|
||||
if (driver_type == "LogicCell40" && driver_port == "carryout") {
|
||||
if (inport == "in0" || inport == "in3")
|
||||
continue;
|
||||
}
|
||||
|
||||
if (driver_type == "LogicCell40" && (driver_port == "ltout" || driver_port == "lcout")) {
|
||||
if (inport == "carryin")
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string *in_net = &netlist_cell_ports.at(driver_cell).at(inport);
|
||||
while (net_assignments.count(*in_net))
|
||||
in_net = &net_assignments.at(*in_net);
|
||||
|
|
@ -657,8 +698,20 @@ struct TimingAnalysis
|
|||
if (net_name == "")
|
||||
continue;
|
||||
|
||||
if (get_inports(netlist_cell_types.at(cell_name)).count(port_name))
|
||||
auto &cell_type = netlist_cell_types.at(cell_name);
|
||||
|
||||
if (get_inports(cell_type).count(port_name)) {
|
||||
std::string n = net_name;
|
||||
while (1) {
|
||||
double setup_time = get_delay(cell_type, port_name, "*setup*");
|
||||
if (setup_time >= std::get<0>(net_max_setup[n]))
|
||||
net_max_setup[n] = std::make_tuple(setup_time, cell_name, port_name);
|
||||
if (net_assignments.count(n) == 0)
|
||||
break;
|
||||
n = net_assignments.at(n);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
net_driver[net_name] = { cell_name, port_name };
|
||||
all_nets.insert(net_name);
|
||||
|
|
@ -667,7 +720,7 @@ struct TimingAnalysis
|
|||
global_max_path_delay = 0;
|
||||
|
||||
for (auto &net : all_nets) {
|
||||
double d = calc_net_max_path_delay(net);
|
||||
double d = calc_net_max_path_delay(net) + std::get<0>(net_max_setup[net]);
|
||||
if (d > global_max_path_delay) {
|
||||
global_max_path_delay = d;
|
||||
global_max_path_net = net;
|
||||
|
|
@ -675,18 +728,47 @@ struct TimingAnalysis
|
|||
}
|
||||
}
|
||||
|
||||
void report()
|
||||
void report(std::string n = std::string())
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
std::set<std::string> visited_nets;
|
||||
|
||||
std::string n = global_max_path_net;
|
||||
if (n.empty()) {
|
||||
n = global_max_path_net;
|
||||
printf("Report for longest path:\n\n");
|
||||
} else {
|
||||
printf("Requested report for net %s:\n\n", n.c_str());
|
||||
}
|
||||
|
||||
if (net_max_path_delay.count(n) == 0) {
|
||||
printf("Net not found: %s\n", n.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
double delay = net_max_path_delay.at(n);
|
||||
|
||||
int logic_levels = 0;
|
||||
bool last_line = true;
|
||||
|
||||
auto &user = net_max_setup[n];
|
||||
|
||||
if (!std::get<1>(user).empty()) {
|
||||
lines.push_back(stringf(" %s (%s) %s [setup]: %.3f ns", std::get<1>(user).c_str(),
|
||||
netlist_cell_types.at(std::get<1>(user)).c_str(), std::get<2>(user).c_str(), std::get<0>(user)));
|
||||
delay += std::get<0>(user);
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (net_max_path_parent.count(n) == 0) {
|
||||
if (net_max_path_parent.count(n) == 0)
|
||||
{
|
||||
lines.push_back(stringf("%10.3f ns %s", calc_net_max_path_delay(n), n.c_str()));
|
||||
|
||||
auto &driver_cell = net_driver.at(n).first;
|
||||
auto &driver_port = net_driver.at(n).second;
|
||||
auto &driver_type = netlist_cell_types.at(driver_cell);
|
||||
lines.push_back(stringf(" %s (%s) [clkedge] -> %s: %.3f ns", driver_cell.c_str(),
|
||||
driver_type.c_str(), driver_port.c_str(), calc_net_max_path_delay(n)));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -697,8 +779,10 @@ struct TimingAnalysis
|
|||
|
||||
auto &entry = net_max_path_parent.at(n);
|
||||
|
||||
if (last_line || netlist_cell_types.at(std::get<1>(entry)) == "LogicCell40")
|
||||
if (last_line || netlist_cell_types.at(std::get<1>(entry)) == "LogicCell40") {
|
||||
lines.push_back(stringf("%10.3f ns %s", calc_net_max_path_delay(n), n.c_str()));
|
||||
logic_levels++;
|
||||
}
|
||||
|
||||
lines.push_back(stringf(" %s (%s) %s -> %s: %.3f ns", std::get<1>(entry).c_str(),
|
||||
netlist_cell_types.at(std::get<1>(entry)).c_str(), std::get<2>(entry).c_str(),
|
||||
|
|
@ -711,6 +795,11 @@ struct TimingAnalysis
|
|||
|
||||
for (int i = int(lines.size())-1; i >= 0; i--)
|
||||
printf("%s\n", lines[i].c_str());
|
||||
|
||||
printf("\n");
|
||||
printf("Total number of logic levels: %d\n", logic_levels);
|
||||
printf("Total path delay: %.2f ns (%.2f MHz)\n", delay, 1000.0 / delay);
|
||||
printf("\n");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1517,27 +1606,28 @@ void make_interconn(const net_segment_t &src, FILE *graph_f)
|
|||
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);
|
||||
if (worker.seg_tree.count(seg)) {
|
||||
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);
|
||||
} else {
|
||||
printf("// %*s DEAD_END (!)\n", indent, "");
|
||||
}
|
||||
};
|
||||
print_net_tree(src.net, 2);
|
||||
print_seg_tree(src, 2, false);
|
||||
#endif
|
||||
if (verbose)
|
||||
{
|
||||
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);
|
||||
if (worker.seg_tree.count(seg)) {
|
||||
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);
|
||||
} else {
|
||||
printf("// %*s DEAD_END (!)\n", indent, "");
|
||||
}
|
||||
};
|
||||
print_net_tree(src.net, 2);
|
||||
print_seg_tree(src, 2, false);
|
||||
}
|
||||
|
||||
for (auto &seg : worker.target_segs) {
|
||||
net_assignments[net_name(seg.net)] = seg_name(seg);
|
||||
|
|
@ -1564,13 +1654,26 @@ void help(const char *cmd)
|
|||
printf(" write a graphviz description of the interconnect tree\n");
|
||||
printf(" that includes the given net to 'icetime_graph.dot'.\n");
|
||||
printf("\n");
|
||||
printf(" -t\n");
|
||||
printf(" print a timing estimate (based on topological timing\n");
|
||||
printf(" analysis)\n");
|
||||
printf("\n");
|
||||
printf(" -T <net_name>\n");
|
||||
printf(" print a timing estimate for the specified net\n");
|
||||
printf("\n");
|
||||
printf(" -v\n");
|
||||
printf(" verbose mode (print all interconnect trees)\n");
|
||||
printf("\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
bool print_timing = false;
|
||||
std::vector<std::string> print_timing_nets;
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "p:P:g:")) != -1)
|
||||
while ((opt = getopt(argc, argv, "p:P:g:tT:v")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
|
|
@ -1584,6 +1687,15 @@ int main(int argc, char **argv)
|
|||
case 'g':
|
||||
graph_nets.insert(atoi(optarg));
|
||||
break;
|
||||
case 't':
|
||||
print_timing = true;
|
||||
break;
|
||||
case 'T':
|
||||
print_timing_nets.push_back(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
default:
|
||||
help(argv[0]);
|
||||
}
|
||||
|
|
@ -1595,7 +1707,7 @@ int main(int argc, char **argv)
|
|||
perror("Can't open input file");
|
||||
exit(1);
|
||||
}
|
||||
fout = stdout;
|
||||
fout = nullptr;
|
||||
} else
|
||||
if (optind+2 == argc) {
|
||||
fin = fopen(argv[optind], "r");
|
||||
|
|
@ -1603,10 +1715,14 @@ int main(int argc, char **argv)
|
|||
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);
|
||||
if (std::string(argv[optind+1]) == "-") {
|
||||
fout = stdout;
|
||||
} else {
|
||||
fout = fopen(argv[optind+1], "w");
|
||||
if (fout == nullptr) {
|
||||
perror("Can't open output file");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
} else
|
||||
help(argv[0]);
|
||||
|
|
@ -1731,84 +1847,102 @@ int main(int argc, char **argv)
|
|||
extra_wires.insert(port.second);
|
||||
}
|
||||
|
||||
fprintf(fout, "module chip (");
|
||||
const char *io_sep = "";
|
||||
for (auto io : io_names) {
|
||||
fprintf(fout, "%s%s", io_sep, io.c_str());
|
||||
io_sep = ", ";
|
||||
}
|
||||
fprintf(fout, ");\n");
|
||||
|
||||
for (int net : declared_nets)
|
||||
fprintf(fout, " wire net_%d;\n", net);
|
||||
|
||||
for (auto net : extra_wires)
|
||||
fprintf(fout, " wire %s;\n", net.c_str());
|
||||
|
||||
for (auto &it : net_assignments)
|
||||
fprintf(fout, " assign %s = %s;\n", it.first.c_str(), it.second.c_str());
|
||||
|
||||
fprintf(fout, " wire gnd, vcc;\n");
|
||||
fprintf(fout, " GND gnd_cell (.Y(gnd));\n");
|
||||
fprintf(fout, " VCC vcc_cell (.Y(vcc));\n");
|
||||
|
||||
for (auto &str : extra_vlog)
|
||||
fprintf(fout, "%s", str.c_str());
|
||||
|
||||
for (auto it : netlist_cell_types)
|
||||
if (fout != NULL)
|
||||
{
|
||||
const char *sep = "";
|
||||
fprintf(fout, " %s ", it.second.c_str());
|
||||
if (netlist_cell_params.count(it.first)) {
|
||||
fprintf(fout, "#(");
|
||||
for (auto port : netlist_cell_params[it.first]) {
|
||||
fprintf(fout, "module chip (");
|
||||
const char *io_sep = "";
|
||||
for (auto io : io_names) {
|
||||
fprintf(fout, "%s%s", io_sep, io.c_str());
|
||||
io_sep = ", ";
|
||||
}
|
||||
fprintf(fout, ");\n");
|
||||
|
||||
for (int net : declared_nets)
|
||||
fprintf(fout, " wire net_%d;\n", net);
|
||||
|
||||
for (auto net : extra_wires)
|
||||
fprintf(fout, " wire %s;\n", net.c_str());
|
||||
|
||||
for (auto &it : net_assignments)
|
||||
fprintf(fout, " assign %s = %s;\n", it.first.c_str(), it.second.c_str());
|
||||
|
||||
fprintf(fout, " wire gnd, vcc;\n");
|
||||
fprintf(fout, " GND gnd_cell (.Y(gnd));\n");
|
||||
fprintf(fout, " VCC vcc_cell (.Y(vcc));\n");
|
||||
|
||||
for (auto &str : extra_vlog)
|
||||
fprintf(fout, "%s", str.c_str());
|
||||
|
||||
for (auto it : netlist_cell_types)
|
||||
{
|
||||
const char *sep = "";
|
||||
fprintf(fout, " %s ", it.second.c_str());
|
||||
if (netlist_cell_params.count(it.first)) {
|
||||
fprintf(fout, "#(");
|
||||
for (auto port : netlist_cell_params[it.first]) {
|
||||
fprintf(fout, "%s\n .%s(%s)", sep, port.first.c_str(), port.second.c_str());
|
||||
sep = ",";
|
||||
}
|
||||
fprintf(fout, "\n ) ");
|
||||
sep = "";
|
||||
}
|
||||
|
||||
fprintf(fout, "%s (", it.first.c_str());
|
||||
std::map<std::string, std::vector<std::string>> multibit_ports;
|
||||
|
||||
for (auto port : netlist_cell_ports[it.first])
|
||||
{
|
||||
size_t open_bracket_pos = port.first.find('[');
|
||||
if (open_bracket_pos != std::string::npos) {
|
||||
std::string base_name = port.first.substr(0, open_bracket_pos);
|
||||
int bit_index = atoi(port.first.substr(open_bracket_pos+1).c_str());
|
||||
if (multibit_ports[base_name].size() <= bit_index)
|
||||
multibit_ports[base_name].resize(bit_index+1);
|
||||
multibit_ports[base_name][bit_index] = port.second;
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf(fout, "%s\n .%s(%s)", sep, port.first.c_str(), port.second.c_str());
|
||||
sep = ",";
|
||||
}
|
||||
fprintf(fout, "\n ) ");
|
||||
sep = "";
|
||||
}
|
||||
|
||||
fprintf(fout, "%s (", it.first.c_str());
|
||||
std::map<std::string, std::vector<std::string>> multibit_ports;
|
||||
for (auto it : multibit_ports)
|
||||
{
|
||||
fprintf(fout, "%s\n .%s({", sep, it.first.c_str());
|
||||
sep = ",";
|
||||
|
||||
for (auto port : netlist_cell_ports[it.first])
|
||||
{
|
||||
size_t open_bracket_pos = port.first.find('[');
|
||||
if (open_bracket_pos != std::string::npos) {
|
||||
std::string base_name = port.first.substr(0, open_bracket_pos);
|
||||
int bit_index = atoi(port.first.substr(open_bracket_pos+1).c_str());
|
||||
if (multibit_ports[base_name].size() <= bit_index)
|
||||
multibit_ports[base_name].resize(bit_index+1);
|
||||
multibit_ports[base_name][bit_index] = port.second;
|
||||
continue;
|
||||
const char *sepsep = "";
|
||||
for (int i = int(it.second.size())-1; i >= 0; i--) {
|
||||
std::string wire_name = it.second[i];
|
||||
fprintf(fout, "%s%s", sepsep, wire_name.c_str());
|
||||
sepsep = ", ";
|
||||
}
|
||||
fprintf(fout, "})");
|
||||
}
|
||||
|
||||
fprintf(fout, "%s\n .%s(%s)", sep, port.first.c_str(), port.second.c_str());
|
||||
sep = ",";
|
||||
fprintf(fout, "\n );\n");
|
||||
}
|
||||
|
||||
for (auto it : multibit_ports)
|
||||
{
|
||||
fprintf(fout, "%s\n .%s({", sep, it.first.c_str());
|
||||
sep = ",";
|
||||
|
||||
const char *sepsep = "";
|
||||
for (int i = int(it.second.size())-1; i >= 0; i--) {
|
||||
std::string wire_name = it.second[i];
|
||||
fprintf(fout, "%s%s", sepsep, wire_name.c_str());
|
||||
sepsep = ", ";
|
||||
}
|
||||
fprintf(fout, "})");
|
||||
}
|
||||
|
||||
fprintf(fout, "\n );\n");
|
||||
fprintf(fout, "endmodule\n");
|
||||
}
|
||||
|
||||
fprintf(fout, "endmodule\n");
|
||||
if (print_timing || !print_timing_nets.empty())
|
||||
{
|
||||
printf("\n");
|
||||
printf("icetime topological timing analysis report\n");
|
||||
printf("==========================================\n");
|
||||
printf("\n");
|
||||
|
||||
TimingAnalysis ta;
|
||||
ta.report();
|
||||
TimingAnalysis ta;
|
||||
for (auto &n : print_timing_nets)
|
||||
ta.report(n);
|
||||
ta.report();
|
||||
}
|
||||
else
|
||||
{
|
||||
TimingAnalysis ta;
|
||||
printf("// Timing estimate: %.2f ns (%.2f MHz)\n", ta.global_max_path_delay, 1000.0 / ta.global_max_path_delay);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ with open("%s.ys" % sys.argv[1], "w") as f:
|
|||
print("equiv_status -assert", file=f)
|
||||
|
||||
assert os.system("bash ../icefuzz/icecube.sh %s.v" % sys.argv[1]) == 0
|
||||
os.rename("%s.tmp/outputs/netlist/top_timing.rpt" % sys.argv[1], "%s.rpt" % sys.argv[1])
|
||||
os.rename("%s.v" % sys.argv[1], "%s_in.v" % sys.argv[1])
|
||||
|
||||
if False:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import re
|
||||
|
||||
print("// auto-generated by timings.py from ../icefuzz/timings_*.txt")
|
||||
|
||||
def timings_to_c(chip, f):
|
||||
print("")
|
||||
print("double get_delay_%s(std::string cell_type, std::string in_port, std::string out_port)" % chip)
|
||||
print("{")
|
||||
|
||||
in_cell = False
|
||||
|
||||
for line in f:
|
||||
fields = line.split()
|
||||
if len(fields) == 0:
|
||||
continue
|
||||
|
||||
if fields[0] == "CELL":
|
||||
if in_cell:
|
||||
print(" }")
|
||||
print(" if (cell_type == \"%s\") {" % fields[1])
|
||||
in_cell = True
|
||||
|
||||
if fields[0] == "SETUP":
|
||||
inport = fields[1].split(":")[1]
|
||||
delay = max([0 if s == "*" else float(s) / 1000 for s in fields[3].split(":")])
|
||||
print(" if (in_port == \"%s\" && out_port == \"*setup*\") return %.5f;" % (inport, delay))
|
||||
|
||||
if fields[0] == "IOPATH":
|
||||
if fields[1].startswith("posedge:") or fields[1].startswith("negedge:"):
|
||||
fields[1] = "*clkedge*"
|
||||
delay = max([0 if s == "*" else float(s) / 1000 for s in fields[3].split(":") + fields[4].split(":")])
|
||||
print(" if (in_port == \"%s\" && out_port == \"%s\") return %.5f;" % (fields[1], fields[2], delay))
|
||||
|
||||
|
||||
if in_cell:
|
||||
print(" }")
|
||||
print(" if (in_port == \"*clkedge*\"|| out_port == \"*setup*\") return 0;")
|
||||
print(" fprintf(stderr, \"Unable to resolve delay for path %s -> %s in cell type %s!\\n\", in_port.c_str(), out_port.c_str(), cell_type.c_str());")
|
||||
print(" exit(1);")
|
||||
print("}")
|
||||
|
||||
with open("../icefuzz/timings_1k.txt", "r") as f:
|
||||
timings_to_c("1k", f);
|
||||
|
||||
with open("../icefuzz/timings_8k.txt", "r") as f:
|
||||
timings_to_c("8k", f);
|
||||
|
||||
Loading…
Reference in New Issue