Merge pull request #1688 from lnis-uofu/xt_wlut

Fixed a critical bug on repacker where global nets are ignored even there is only 1 valid routing trace
This commit is contained in:
tangxifan 2024-06-02 16:16:28 -07:00 committed by GitHub
commit 0fe94fbe9c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 197 additions and 29 deletions

View File

@ -3,7 +3,6 @@ name: Test
# Run CI on push, PR, and weekly.
on:
push:
pull_request:
schedule:
- cron: "0 0 * * 0 " # weekly

View File

@ -3,7 +3,6 @@ name: Cell Library Tests
# Run CI on push, PR, and weekly.
on:
push:
pull_request:
schedule:
- cron: "0 0 * * 0 " # weekly

View File

@ -3,7 +3,6 @@ name: Code Format
# Run CI on push, PR, and weekly.
on:
push:
pull_request:
schedule:
- cron: "0 0 * * 0 " # weekly

View File

@ -138,8 +138,13 @@ static void build_physical_pb_lut_truth_tables(
size_t(lut_pb_id), output_pin->to_string().c_str());
VTR_LOGV(verbose, "Input nets:\n");
for (auto input_net : input_nets) {
VTR_LOGV(verbose, "\t%s\n",
atom_ctx.nlist.net_name(input_net).c_str());
if (AtomNetId::INVALID() == input_net) {
VTR_LOGV(verbose, "\tunconn\n");
} else {
VTR_ASSERT(AtomNetId::INVALID() != input_net);
VTR_LOGV(verbose, "\t%s\n",
atom_ctx.nlist.net_name(input_net).c_str());
}
}
VTR_LOGV(verbose, "Output nets:\n");
VTR_LOGV(verbose, "\t%s\n",
@ -236,6 +241,10 @@ void build_physical_lut_truth_tables(
for (auto blk_id : cluster_ctx.clb_nlist.blocks()) {
PhysicalPb& physical_pb = cluster_annotation.mutable_physical_pb(blk_id);
VTR_LOGV(
verbose,
"Build truth tables for physical LUTs under clustered block '%s'...\n",
cluster_ctx.clb_nlist.block_name(blk_id).c_str());
/* Find the LUT physical pb id */
for (const PhysicalPbId& primitive_pb : physical_pb.primitive_pbs()) {
CircuitModelId circuit_model = device_annotation.pb_type_circuit_model(

View File

@ -92,10 +92,9 @@ void save_lb_router_results_to_physical_pb(PhysicalPb& phy_pb,
const AtomNetId& atom_net = lb_router.net_atom_net_id(net);
/* Print info to help debug */
VTR_LOGV(verbose, "Save net '%s' to physical pb_graph_pin '%s.%s[%d]'\n",
VTR_LOGV(verbose, "Save net '%s' to physical pb_graph_pin '%s'\n",
atom_netlist.net_name(atom_net).c_str(),
pb_graph_pin->parent_node->pb_type->name,
pb_graph_pin->port->name, pb_graph_pin->pin_number);
pb_graph_pin->to_string().c_str());
if (AtomNetId::INVALID() ==
phy_pb.pb_graph_pin_atom_net(pb_id, pb_graph_pin)) {

View File

@ -304,6 +304,33 @@ static std::vector<int> find_pb_route_by_atom_net(
return pb_route_indices;
}
/***************************************************************************************
* This function will find the actual routing traces of the demanded net
* There is a specific search space applied when searching the routing traces:
* - ONLY applicable to the pb_pin of top-level pb_graph_node
***************************************************************************************/
static std::vector<int> find_pb_routes_by_atom_net_among_top_pb_pins(
const t_pb* pb, const AtomNetId& atom_net_id) {
std::vector<int> pb_route_indices;
std::vector<int> candidate_pool;
for (int pin = 0; pin < pb->pb_graph_node->total_pb_pins; ++pin) {
/* Bypass unused pins */
if ((0 == pb->pb_route.count(pin)) ||
(AtomNetId::INVALID() == pb->pb_route.at(pin).atom_net_id)) {
continue;
}
/* Get the driver pb pin id, it must be valid */
if (atom_net_id != pb->pb_route.at(pin).atom_net_id) {
continue;
}
if (pb->pb_route.at(pin).pb_graph_pin->parent_node->is_root()) {
candidate_pool.push_back(pin);
}
}
return candidate_pool;
}
/***************************************************************************************
* This function will find the actual routing traces of the demanded net
* There is a specific search space applied when searching the routing traces:
@ -584,7 +611,6 @@ static void add_lb_router_nets(
std::string(lb_type->pb_type->name), curr_pin))) {
/* Find the net mapped to this pin in clustering results*/
AtomNetId atom_net_id = pb_pin_mapped_nets[source_pb_pin];
std::vector<int> pb_route_indices =
find_pb_route_by_atom_net(pb, source_pb_pin, atom_net_id);
VTR_ASSERT(1 == pb_route_indices.size());
@ -640,9 +666,15 @@ static void add_lb_router_nets(
BasicPort curr_pin(std::string(source_pb_pin->port->name),
source_pb_pin->pin_number, source_pb_pin->pin_number);
/* Be very careful! There is only one routing trace for the net, it should
* never be ignored! */
if ((ignored_atom_nets[atom_net_id]) &&
(find_pb_routes_by_atom_net_among_top_pb_pins(pb, atom_net_id).size() >
1) &&
(options.is_pin_ignore_global_nets(std::string(lb_type->pb_type->name),
curr_pin))) {
VTR_LOGV(verbose, "Skip net '%s' as it is global and set to be ignored\n",
atom_ctx.nlist.net_name(atom_net_id).c_str());
continue;
}

View File

@ -131,7 +131,8 @@ void alloc_physical_pb_from_pb_graph(
static void update_primitive_physical_pb_pin_atom_net(
PhysicalPb& phy_pb, const PhysicalPbId& primitive_pb,
const t_pb_graph_pin* pb_graph_pin, const t_pb_routes& pb_route,
const VprDeviceAnnotation& device_annotation) {
const VprDeviceAnnotation& device_annotation, const AtomNetlist& atom_nlist,
const bool& verbose) {
int node_index = pb_graph_pin->pin_count_in_cluster;
if (pb_route.count(node_index)) {
/* The pin is mapped to a net, find the original pin in the atom netlist */
@ -144,15 +145,11 @@ static void update_primitive_physical_pb_pin_atom_net(
device_annotation.physical_pb_graph_pin(pb_graph_pin);
VTR_ASSERT(nullptr != physical_pb_graph_pin);
/* Print info to help debug
bool verbose = true;
VTR_LOGV(verbose,
"\nSynchronize net '%lu' to physical pb_graph_pin '%s.%s[%d]'\n",
size_t(atom_net),
pb_graph_pin->parent_node->pb_type->name,
pb_graph_pin->port->name,
pb_graph_pin->pin_number);
*/
if (AtomNetId::INVALID() != atom_net) {
VTR_LOGV(verbose, "Synchronize net '%s' to physical pb_graph_pin '%s'\n",
atom_nlist.net_name(atom_net).c_str(),
pb_graph_pin->to_string().c_str());
}
/* Check if the pin has been mapped to a net.
* If yes, the atom net must be the same
@ -165,6 +162,11 @@ static void update_primitive_physical_pb_pin_atom_net(
VTR_ASSERT(atom_net == phy_pb.pb_graph_pin_atom_net(
primitive_pb, physical_pb_graph_pin));
}
} else {
VTR_LOGV(verbose,
"Skip as no valid routing traces if found on physical "
"pb_graph_pin '%s'\n",
pb_graph_pin->to_string().c_str());
}
}
@ -175,22 +177,39 @@ static void synchronize_primitive_physical_pb_atom_nets(
PhysicalPb& phy_pb, const PhysicalPbId& primitive_pb,
const t_pb_graph_node* pb_graph_node, const t_pb_routes& pb_route,
const AtomContext& atom_ctx, const AtomBlockId& atom_blk,
const VprDeviceAnnotation& device_annotation) {
const VprDeviceAnnotation& device_annotation, const bool& verbose) {
/* Iterate over all the ports: input, output and clock */
VTR_LOGV(verbose, "Synchronizing atom nets on pb_graph_node '%s'...\n",
pb_graph_node->hierarchical_type_name().c_str());
for (int iport = 0; iport < pb_graph_node->num_input_ports; ++iport) {
for (int ipin = 0; ipin < pb_graph_node->num_input_pins[iport]; ++ipin) {
/* Port exists (some LUTs may have no input and hence no port in the atom
* netlist) */
VTR_LOGV(verbose, "Synchronizing atom nets on pb_graph_pin '%s'...\n",
pb_graph_node->input_pins[iport][ipin].to_string().c_str());
t_model_ports* model_port =
pb_graph_node->input_pins[iport][ipin].port->model_port;
/* Special for LUTs, the model port is hidden under 1 level
* Do NOT do this. Net mapping on LUT inputs may be swapped during
* rerouting
* if (LUT_CLASS == pb_graph_node->pb_type->class_type) {
* VTR_ASSERT(pb_graph_node->pb_type->num_modes == 2);
* model_port = pb_graph_node->child_pb_graph_nodes[1][0][0]
* .input_pins[iport][ipin]
* .port->model_port;
* }
*/
/* It seems that LUT port are no longer built with an internal model */
if (nullptr == model_port) {
VTR_LOGV(verbose, "Skip due to empty model port\n");
continue;
}
AtomPortId atom_port =
atom_ctx.nlist.find_atom_port(atom_blk, model_port);
if (!atom_port) {
VTR_LOGV(verbose, "Skip due to invalid port\n");
continue;
}
/* Find the atom nets mapped to the pin
@ -199,7 +218,7 @@ static void synchronize_primitive_physical_pb_atom_nets(
*/
update_primitive_physical_pb_pin_atom_net(
phy_pb, primitive_pb, &(pb_graph_node->input_pins[iport][ipin]),
pb_route, device_annotation);
pb_route, device_annotation, atom_ctx.nlist, verbose);
}
}
@ -207,15 +226,29 @@ static void synchronize_primitive_physical_pb_atom_nets(
for (int ipin = 0; ipin < pb_graph_node->num_output_pins[iport]; ++ipin) {
/* Port exists (some LUTs may have no input and hence no port in the atom
* netlist) */
VTR_LOGV(verbose, "Synchronizing atom nets on pb_graph_pin '%s'...\n",
pb_graph_node->output_pins[iport][ipin].to_string().c_str());
t_model_ports* model_port =
pb_graph_node->output_pins[iport][ipin].port->model_port;
/* Special for LUTs, the model port is hidden under 1 level
* Do NOT do this. Net mapping on LUT inputs may be swapped during
* rerouting
* if (LUT_CLASS == pb_graph_node->pb_type->class_type) {
* VTR_ASSERT(pb_graph_node->pb_type->num_modes == 2);
* model_port = pb_graph_node->child_pb_graph_nodes[1][0][0]
* .output_pins[iport][ipin]
* .port->model_port;
* }
*/
if (nullptr == model_port) {
VTR_LOGV(verbose, "Skip due to empty model port\n");
continue;
}
AtomPortId atom_port =
atom_ctx.nlist.find_atom_port(atom_blk, model_port);
if (!atom_port) {
VTR_LOGV(verbose, "Skip due to invalid port\n");
continue;
}
/* Find the atom nets mapped to the pin
@ -224,7 +257,7 @@ static void synchronize_primitive_physical_pb_atom_nets(
*/
update_primitive_physical_pb_pin_atom_net(
phy_pb, primitive_pb, &(pb_graph_node->output_pins[iport][ipin]),
pb_route, device_annotation);
pb_route, device_annotation, atom_ctx.nlist, verbose);
}
}
@ -232,15 +265,19 @@ static void synchronize_primitive_physical_pb_atom_nets(
for (int ipin = 0; ipin < pb_graph_node->num_clock_pins[iport]; ++ipin) {
/* Port exists (some LUTs may have no input and hence no port in the atom
* netlist) */
VTR_LOGV(verbose, "Synchronizing atom nets on pb_graph_pin '%s'...\n",
pb_graph_node->clock_pins[iport][ipin].to_string().c_str());
t_model_ports* model_port =
pb_graph_node->clock_pins[iport][ipin].port->model_port;
if (nullptr == model_port) {
VTR_LOGV(verbose, "Skip due to empty model port\n");
continue;
}
AtomPortId atom_port =
atom_ctx.nlist.find_atom_port(atom_blk, model_port);
if (!atom_port) {
VTR_LOGV(verbose, "Skip due to invalid port\n");
continue;
}
/* Find the atom nets mapped to the pin
@ -249,7 +286,7 @@ static void synchronize_primitive_physical_pb_atom_nets(
*/
update_primitive_physical_pb_pin_atom_net(
phy_pb, primitive_pb, &(pb_graph_node->clock_pins[iport][ipin]),
pb_route, device_annotation);
pb_route, device_annotation, atom_ctx.nlist, verbose);
}
}
}
@ -280,10 +317,8 @@ static void mark_physical_pb_wired_lut_outputs(
VTR_ASSERT(nullptr != physical_pb_graph_pin);
/* Print debug info */
VTR_LOGV(
verbose, "Mark physical pb_graph pin '%s.%s[%d]' as wire LUT output\n",
physical_pb_graph_pin->parent_node->pb_type->name,
physical_pb_graph_pin->port->name, physical_pb_graph_pin->pin_number);
VTR_LOGV(verbose, "Mark physical pb_graph pin '%s' as wire LUT output\n",
physical_pb_graph_pin->to_string().c_str());
/* Label the pins in physical_pb as driven by wired LUT*/
phy_pb.set_wire_lut_output(primitive_pb, physical_pb_graph_pin, true);
@ -318,6 +353,9 @@ void rec_update_physical_pb_from_operating_pb(
VTR_ASSERT(atom_blk);
phy_pb.add_atom_block(physical_pb, atom_blk);
VTR_LOGV(verbose, "Update physical pb '%s' using atom block '%s'\n",
physical_pb_graph_node->hierarchical_type_name().c_str(),
atom_ctx.nlist.block_name(atom_blk).c_str());
/* if the operating pb type has bitstream annotation,
* bind the bitstream value from atom block to the physical pb
@ -400,7 +438,7 @@ void rec_update_physical_pb_from_operating_pb(
/* Iterate over ports and annotate the atom pins */
synchronize_primitive_physical_pb_atom_nets(
phy_pb, physical_pb, pb_graph_node, pb_route, atom_ctx, atom_blk,
device_annotation);
device_annotation, verbose);
return;
}

View File

@ -0,0 +1,35 @@
/////////////////////////////////////////
// Functionality: 4-bit version of A register driven by a combinational logic with reset signal
// Author: Xifan Tang
////////////////////////////////////////
`timescale 1ns / 1ps
module rst_on_lut_4bit(a, b0, b1, b2, b3, q, out0, out1, out2, out3, clk, rst);
input wire rst;
input wire clk;
input wire a;
input wire b0;
input wire b1;
input wire b2;
input wire b3;
output reg q;
output wire out0;
output wire out1;
output wire out2;
output wire out3;
always @(posedge rst or posedge clk) begin
if (rst) begin
q <= 0;
end else begin
q <= a;
end
end
assign out0 = b0 & ~rst;
assign out1 = b1 & ~rst;
assign out2 = b2 & ~rst;
assign out3 = b3 & ~rst;
endmodule

View File

@ -0,0 +1,47 @@
/////////////////////////////////////////
// Functionality: 8-bit version of A register driven by a combinational logic with reset signal
// Author: Xifan Tang
////////////////////////////////////////
`timescale 1ns / 1ps
module rst_on_lut_8bit(a, b0, b1, b2, b3, b4, b5, b6, b7, q, out0, out1, out2, out3, out4, out5, out6, out7, clk, rst);
input wire rst;
input wire clk;
input wire a;
input wire b0;
input wire b1;
input wire b2;
input wire b3;
input wire b4;
input wire b5;
input wire b6;
input wire b7;
output reg q;
output wire out0;
output wire out1;
output wire out2;
output wire out3;
output wire out4;
output wire out5;
output wire out6;
output wire out7;
always @(posedge rst or posedge clk) begin
if (rst) begin
q <= 0;
end else begin
q <= a;
end
end
assign out0 = b0 & ~rst;
assign out1 = b1 & ~rst;
assign out2 = b2 & ~rst;
assign out3 = b3 & ~rst;
assign out4 = b4 & ~rst;
assign out5 = b5 & ~rst;
assign out6 = b6 & ~rst;
assign out7 = b7 & ~rst;
endmodule

View File

@ -28,6 +28,7 @@ run-task fpga_bitstream/load_external_architecture_bitstream $@
echo -e "Testing repacker capability in identifying wire LUTs";
run-task fpga_bitstream/repack_wire_lut $@
run-task fpga_bitstream/repack_wire_lut_strong $@
run-task fpga_bitstream/repack_ignore_nets $@
echo -e "Testing overloading default paths for programmable interconnect when generating bitstream";
run-task fpga_bitstream/overload_mux_default_path $@

View File

@ -2,7 +2,7 @@
<pin_constraint pb_type="clb" pin="clk[0]" net="clk"/>
<pin_constraint pb_type="clb" pin="reset[0]" net="rst"/>
<ignore_net name="rst" pin="clb.I[0:11]"/>
<reset />
<!-- reset / -->
<!-- Leave lreset unconstrained as it may be mapped to any internal reset signals -->
</repack_design_constraints>

View File

@ -28,6 +28,8 @@ arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_lo
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/two_dff_inv_rst/two_dff_inv_rst.v
bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/rst_on_lut/rst_on_lut.v
bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/rst_on_lut_4bit/rst_on_lut_4bit.v
bench3=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/rst_on_lut_8bit/rst_on_lut_8bit.v
[SYNTHESIS_PARAM]
# Yosys script parameters
@ -45,6 +47,14 @@ bench1_top = rst_on_lut
bench1_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/rst_on_lut_pc.xml
bench1_openfpga_repack_design_constraint_file=${PATH:TASK_DIR}/config/rst_on_lut_repack_dc.xml
bench2_top = rst_on_lut_4bit
bench2_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/rst_on_lut_pc.xml
bench2_openfpga_repack_design_constraint_file=${PATH:TASK_DIR}/config/rst_on_lut_repack_dc.xml
bench3_top = rst_on_lut_8bit
bench3_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/rst_on_lut_pc.xml
bench3_openfpga_repack_design_constraint_file=${PATH:TASK_DIR}/config/rst_on_lut_repack_dc.xml
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
end_flow_with_test=
vpr_fpga_verilog_formal_verification_top_netlist=