diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 83cfed09b..34c17b7f3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,7 +3,6 @@ name: Test # Run CI on push, PR, and weekly. on: - push: pull_request: schedule: - cron: "0 0 * * 0 " # weekly diff --git a/.github/workflows/cell_lib_test.yml b/.github/workflows/cell_lib_test.yml index 7d5b08984..3a472af3a 100644 --- a/.github/workflows/cell_lib_test.yml +++ b/.github/workflows/cell_lib_test.yml @@ -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 diff --git a/.github/workflows/format.yaml b/.github/workflows/format.yaml index 273c1122c..e4c84320e 100644 --- a/.github/workflows/format.yaml +++ b/.github/workflows/format.yaml @@ -3,7 +3,6 @@ name: Code Format # Run CI on push, PR, and weekly. on: - push: pull_request: schedule: - cron: "0 0 * * 0 " # weekly diff --git a/openfpga/src/repack/build_physical_truth_table.cpp b/openfpga/src/repack/build_physical_truth_table.cpp index 86a2c7aa4..67f258c34 100644 --- a/openfpga/src/repack/build_physical_truth_table.cpp +++ b/openfpga/src/repack/build_physical_truth_table.cpp @@ -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( diff --git a/openfpga/src/repack/lb_router_utils.cpp b/openfpga/src/repack/lb_router_utils.cpp index 45b1fce24..25c4399eb 100644 --- a/openfpga/src/repack/lb_router_utils.cpp +++ b/openfpga/src/repack/lb_router_utils.cpp @@ -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)) { diff --git a/openfpga/src/repack/repack.cpp b/openfpga/src/repack/repack.cpp index 35f45d7a1..4f3dc460a 100644 --- a/openfpga/src/repack/repack.cpp +++ b/openfpga/src/repack/repack.cpp @@ -304,6 +304,33 @@ static std::vector 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 find_pb_routes_by_atom_net_among_top_pb_pins( + const t_pb* pb, const AtomNetId& atom_net_id) { + std::vector pb_route_indices; + + std::vector 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 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; } diff --git a/openfpga/src/utils/physical_pb_utils.cpp b/openfpga/src/utils/physical_pb_utils.cpp index 12d5572e3..ddb8c954f 100644 --- a/openfpga/src/utils/physical_pb_utils.cpp +++ b/openfpga/src/utils/physical_pb_utils.cpp @@ -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; } diff --git a/openfpga_flow/benchmarks/micro_benchmark/rst_on_lut_4bit/rst_on_lut_4bit.v b/openfpga_flow/benchmarks/micro_benchmark/rst_on_lut_4bit/rst_on_lut_4bit.v new file mode 100644 index 000000000..33a8db5f3 --- /dev/null +++ b/openfpga_flow/benchmarks/micro_benchmark/rst_on_lut_4bit/rst_on_lut_4bit.v @@ -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 diff --git a/openfpga_flow/benchmarks/micro_benchmark/rst_on_lut_8bit/rst_on_lut_8bit.v b/openfpga_flow/benchmarks/micro_benchmark/rst_on_lut_8bit/rst_on_lut_8bit.v new file mode 100644 index 000000000..30c97205a --- /dev/null +++ b/openfpga_flow/benchmarks/micro_benchmark/rst_on_lut_8bit/rst_on_lut_8bit.v @@ -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 diff --git a/openfpga_flow/regression_test_scripts/fpga_bitstream_reg_test.sh b/openfpga_flow/regression_test_scripts/fpga_bitstream_reg_test.sh index 32b6c7147..174b4cabe 100755 --- a/openfpga_flow/regression_test_scripts/fpga_bitstream_reg_test.sh +++ b/openfpga_flow/regression_test_scripts/fpga_bitstream_reg_test.sh @@ -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 $@ diff --git a/openfpga_flow/tasks/fpga_bitstream/repack_ignore_nets/config/rst_on_lut_repack_dc.xml b/openfpga_flow/tasks/fpga_bitstream/repack_ignore_nets/config/rst_on_lut_repack_dc.xml index 71153e425..748e23269 100644 --- a/openfpga_flow/tasks/fpga_bitstream/repack_ignore_nets/config/rst_on_lut_repack_dc.xml +++ b/openfpga_flow/tasks/fpga_bitstream/repack_ignore_nets/config/rst_on_lut_repack_dc.xml @@ -2,7 +2,7 @@ - + diff --git a/openfpga_flow/tasks/fpga_bitstream/repack_ignore_nets/config/task.conf b/openfpga_flow/tasks/fpga_bitstream/repack_ignore_nets/config/task.conf index 63ffd257c..6076c364f 100644 --- a/openfpga_flow/tasks/fpga_bitstream/repack_ignore_nets/config/task.conf +++ b/openfpga_flow/tasks/fpga_bitstream/repack_ignore_nets/config/task.conf @@ -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=