Merge pull request #295 from lnis-uofu/multi_clock
Patches on multi-clock support in repacking stage
This commit is contained in:
commit
c198273378
|
@ -3,6 +3,11 @@
|
||||||
Repack Design Constraints (.xml)
|
Repack Design Constraints (.xml)
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
|
.. warning:: For the best practice, current repack design constraints only support the net remapping between pins in the same port. Pin constraints are **NOT** allowed for two separated ports.
|
||||||
|
|
||||||
|
- A legal pin constraint example: when there are two clock nets, ``clk0`` and ``clk1``, pin constraints are forced on two pins in a clock port ``clk[0:2]`` (e.g., ``clk[0] = clk0`` and ``clk[1] == clk1``).
|
||||||
|
- An **illegal** pin constraint example: when there are two clock nets, ``clk0`` and ``clk1``, pin constraints are forced on two clock ports ``clkA[0]`` and ``clkB[0]`` (e.g., ``clkA[0] = clk0`` and ``clkB[0] == clk1``).
|
||||||
|
|
||||||
An example of design constraints is shown as follows.
|
An example of design constraints is shown as follows.
|
||||||
|
|
||||||
.. code-block:: xml
|
.. code-block:: xml
|
||||||
|
|
|
@ -50,6 +50,20 @@ std::string RepackDesignConstraints::net(const RepackDesignConstraintId& repack_
|
||||||
return repack_design_constraint_nets_[repack_design_constraint_id];
|
return repack_design_constraint_nets_[repack_design_constraint_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string RepackDesignConstraints::find_constrained_pin_net(const std::string& pb_type,
|
||||||
|
const openfpga::BasicPort& pin) const {
|
||||||
|
std::string constrained_net_name;
|
||||||
|
for (const RepackDesignConstraintId& design_constraint : design_constraints()) {
|
||||||
|
/* If found a constraint, record the net name */
|
||||||
|
if ( (pb_type == repack_design_constraint_pb_types_[design_constraint])
|
||||||
|
&& (pin == repack_design_constraint_pins_[design_constraint])) {
|
||||||
|
constrained_net_name = repack_design_constraint_nets_[design_constraint];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return constrained_net_name;
|
||||||
|
}
|
||||||
|
|
||||||
bool RepackDesignConstraints::empty() const {
|
bool RepackDesignConstraints::empty() const {
|
||||||
return 0 == repack_design_constraint_ids_.size();
|
return 0 == repack_design_constraint_ids_.size();
|
||||||
}
|
}
|
||||||
|
@ -106,3 +120,11 @@ void RepackDesignConstraints::set_net(const RepackDesignConstraintId& repack_des
|
||||||
bool RepackDesignConstraints::valid_design_constraint_id(const RepackDesignConstraintId& design_constraint_id) const {
|
bool RepackDesignConstraints::valid_design_constraint_id(const RepackDesignConstraintId& design_constraint_id) const {
|
||||||
return ( size_t(design_constraint_id) < repack_design_constraint_ids_.size() ) && ( design_constraint_id == repack_design_constraint_ids_[design_constraint_id] );
|
return ( size_t(design_constraint_id) < repack_design_constraint_ids_.size() ) && ( design_constraint_id == repack_design_constraint_ids_[design_constraint_id] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RepackDesignConstraints::unconstrained_net(const std::string& net) const {
|
||||||
|
return net.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RepackDesignConstraints::unmapped_net(const std::string& net) const {
|
||||||
|
return std::string(REPACK_DESIGN_CONSTRAINT_OPEN_NET) == net;
|
||||||
|
}
|
||||||
|
|
|
@ -61,6 +61,10 @@ class RepackDesignConstraints {
|
||||||
/* Get the net to be constrained */
|
/* Get the net to be constrained */
|
||||||
std::string net(const RepackDesignConstraintId& repack_design_constraint_id) const;
|
std::string net(const RepackDesignConstraintId& repack_design_constraint_id) const;
|
||||||
|
|
||||||
|
/* Find a constrained net */
|
||||||
|
std::string find_constrained_pin_net(const std::string& pb_type,
|
||||||
|
const openfpga::BasicPort& pin) const;
|
||||||
|
|
||||||
/* Check if there are any design constraints */
|
/* Check if there are any design constraints */
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
|
|
||||||
|
@ -86,6 +90,20 @@ class RepackDesignConstraints {
|
||||||
|
|
||||||
public: /* Public invalidators/validators */
|
public: /* Public invalidators/validators */
|
||||||
bool valid_design_constraint_id(const RepackDesignConstraintId& repack_design_constraint_id) const;
|
bool valid_design_constraint_id(const RepackDesignConstraintId& repack_design_constraint_id) const;
|
||||||
|
/* Show if the net has no constraints (free to map to any pin)
|
||||||
|
* This function is used to identify the net name returned by APIs:
|
||||||
|
* - find_constrained_pin_net()
|
||||||
|
* - net()
|
||||||
|
*/
|
||||||
|
bool unconstrained_net(const std::string& net) const;
|
||||||
|
|
||||||
|
/* Show if the net is defined specifically not to map to any pin
|
||||||
|
* This function is used to identify the net name returned by APIs:
|
||||||
|
* - find_constrained_pin_net()
|
||||||
|
* - net()
|
||||||
|
*/
|
||||||
|
bool unmapped_net(const std::string& net) const;
|
||||||
|
|
||||||
private: /* Internal data */
|
private: /* Internal data */
|
||||||
/* Unique ids for each design constraint */
|
/* Unique ids for each design constraint */
|
||||||
vtr::vector<RepackDesignConstraintId, RepackDesignConstraintId> repack_design_constraint_ids_;
|
vtr::vector<RepackDesignConstraintId, RepackDesignConstraintId> repack_design_constraint_ids_;
|
||||||
|
|
|
@ -230,6 +230,38 @@ std::vector<t_pb_graph_pin*> find_routed_pb_graph_pins_atom_net(const t_pb* pb,
|
||||||
return sink_pb_pins;
|
return sink_pb_pins;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
* 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
|
||||||
|
* - candidate can be limited to a set of pb pins
|
||||||
|
***************************************************************************************/
|
||||||
|
static
|
||||||
|
std::vector<int> find_pb_route_by_atom_net(const t_pb* pb,
|
||||||
|
const t_pb_graph_pin* source_pb_pin,
|
||||||
|
const AtomNetId& atom_net_id) {
|
||||||
|
VTR_ASSERT(true == source_pb_pin->parent_node->is_root());
|
||||||
|
|
||||||
|
std::vector<int> pb_route_indices;
|
||||||
|
|
||||||
|
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 (source_pb_pin->port == pb->pb_route.at(pin).pb_graph_pin->port) {
|
||||||
|
pb_route_indices.push_back(pin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pb_route_indices;
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
* This function will find the actual source_pb_pin that is mapped by packed in the pb route
|
* This function will find the actual source_pb_pin that is mapped by packed in the pb route
|
||||||
* As the inputs of clustered block may be renamed during routing,
|
* As the inputs of clustered block may be renamed during routing,
|
||||||
|
@ -422,18 +454,7 @@ void add_lb_router_nets(LbRouter& lb_router,
|
||||||
AtomNetId atom_net_id = pb_pin_mapped_nets[source_pb_pin];
|
AtomNetId atom_net_id = pb_pin_mapped_nets[source_pb_pin];
|
||||||
|
|
||||||
/* Check if the net information is constrained or not */
|
/* Check if the net information is constrained or not */
|
||||||
std::string constrained_net_name;
|
std::string constrained_net_name = design_constraints.find_constrained_pin_net(std::string(lb_type->pb_type->name), BasicPort(std::string(source_pb_pin->port->name), source_pb_pin->pin_number, source_pb_pin->pin_number));
|
||||||
for (const RepackDesignConstraintId& design_constraint : design_constraints.design_constraints()) {
|
|
||||||
/* All the pin must have only 1 bit */
|
|
||||||
VTR_ASSERT_SAFE(1 == design_constraints.pin(design_constraint).get_width());
|
|
||||||
/* If found a constraint, record the net name */
|
|
||||||
if ( (std::string(lb_type->pb_type->name) == design_constraints.pb_type(design_constraint))
|
|
||||||
&& (std::string(source_pb_pin->port->name) == design_constraints.pin(design_constraint).get_name())
|
|
||||||
&& (size_t(source_pb_pin->pin_number) == design_constraints.pin(design_constraint).get_lsb())) {
|
|
||||||
constrained_net_name = design_constraints.net(design_constraint);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the constrained net mapped to this pin in clustering results */
|
/* Find the constrained net mapped to this pin in clustering results */
|
||||||
AtomNetId constrained_atom_net_id = AtomNetId::INVALID();
|
AtomNetId constrained_atom_net_id = AtomNetId::INVALID();
|
||||||
|
@ -443,16 +464,21 @@ void add_lb_router_nets(LbRouter& lb_router,
|
||||||
* - if this is valid net name, find the net id from atom_netlist
|
* - if this is valid net name, find the net id from atom_netlist
|
||||||
* and overwrite the atom net id to mapped
|
* and overwrite the atom net id to mapped
|
||||||
*/
|
*/
|
||||||
if (!constrained_net_name.empty()) {
|
if ( (!design_constraints.unconstrained_net(constrained_net_name))
|
||||||
if (std::string(REPACK_DESIGN_CONSTRAINT_OPEN_NET) != constrained_net_name) {
|
&& (!design_constraints.unmapped_net(constrained_net_name))) {
|
||||||
constrained_atom_net_id = atom_ctx.nlist.find_net(constrained_net_name);
|
constrained_atom_net_id = atom_ctx.nlist.find_net(constrained_net_name);
|
||||||
if (false == atom_ctx.nlist.valid_net_id(constrained_atom_net_id)) {
|
if (false == atom_ctx.nlist.valid_net_id(constrained_atom_net_id)) {
|
||||||
VTR_LOG_WARN("Invalid net '%s' to be constrained! Will drop the constraint in repacking\n",
|
VTR_LOG_WARN("Invalid net '%s' to be constrained! Will drop the constraint in repacking\n",
|
||||||
constrained_net_name.c_str());
|
constrained_net_name.c_str());
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
VTR_ASSERT_SAFE(constrained_net_name.empty());
|
VTR_ASSERT_SAFE(false == atom_ctx.nlist.valid_net_id(constrained_atom_net_id));
|
||||||
|
VTR_LOGV(verbose,
|
||||||
|
"Accept net '%s' to be constrained on pin '%s[%d]' during repacking\n",
|
||||||
|
constrained_net_name.c_str(),
|
||||||
|
source_pb_pin->port->name,
|
||||||
|
source_pb_pin->pin_number);
|
||||||
|
}
|
||||||
|
} else if (design_constraints.unconstrained_net(constrained_net_name)) {
|
||||||
constrained_atom_net_id = atom_net_id;
|
constrained_atom_net_id = atom_net_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,18 +512,35 @@ void add_lb_router_nets(LbRouter& lb_router,
|
||||||
LbRRNodeId source_lb_rr_node = lb_rr_graph.find_node(LB_INTERMEDIATE, source_pb_pin);
|
LbRRNodeId source_lb_rr_node = lb_rr_graph.find_node(LB_INTERMEDIATE, source_pb_pin);
|
||||||
VTR_ASSERT(true == lb_rr_graph.valid_node_id(source_lb_rr_node));
|
VTR_ASSERT(true == lb_rr_graph.valid_node_id(source_lb_rr_node));
|
||||||
|
|
||||||
|
/* Output verbose messages for debugging only */
|
||||||
|
VTR_LOGV(verbose,
|
||||||
|
"Pb route for Net %s:\n",
|
||||||
|
atom_ctx.nlist.net_name(atom_net_id_to_route).c_str());
|
||||||
|
|
||||||
/* As the pin remapping is allowed during routing, we should
|
/* As the pin remapping is allowed during routing, we should
|
||||||
* - Find the routing traces from packing results which is mapped to the net
|
* - Find the routing traces from packing results which is mapped to the net
|
||||||
* from the same port (as remapping is allowed for pins in the same port only)
|
* from the same port (as remapping is allowed for pins in the same port only)
|
||||||
* - Find the source pb_graph_pin that drives the routing traces during packing
|
* - Find the source pb_graph_pin that drives the routing traces during packing
|
||||||
* - Then we can find the sink nodes
|
* - Then we can find the sink nodes
|
||||||
|
*
|
||||||
|
* When there is a pin constraint applied. The routing trace
|
||||||
|
* - Find the routing traces from packing results which is mapped to the net
|
||||||
|
* with the same port constraints
|
||||||
*/
|
*/
|
||||||
std::vector<int> pb_route_indices = find_pb_route_remapped_source_pb_pin(pb, source_pb_pin, atom_net_id_to_route);
|
std::vector<int> pb_route_indices;
|
||||||
|
if (design_constraints.unconstrained_net(constrained_net_name)) {
|
||||||
|
pb_route_indices = find_pb_route_remapped_source_pb_pin(pb, source_pb_pin, atom_net_id_to_route);
|
||||||
|
} else {
|
||||||
|
VTR_ASSERT_SAFE(!design_constraints.unconstrained_net(constrained_net_name));
|
||||||
|
pb_route_indices = find_pb_route_by_atom_net(pb, source_pb_pin, atom_net_id_to_route);
|
||||||
|
}
|
||||||
/* It could happen that the constrained net is NOT used in this clb, we just skip it for routing
|
/* It could happen that the constrained net is NOT used in this clb, we just skip it for routing
|
||||||
* For example, a clkB net is never mapped to any ports in the pb that is clocked by clkA net
|
* For example, a clkB net is never mapped to any ports in the pb that is clocked by clkA net
|
||||||
* */
|
* */
|
||||||
int pb_route_index;
|
int pb_route_index;
|
||||||
if (0 == pb_route_indices.size()) {
|
if (0 == pb_route_indices.size()) {
|
||||||
|
VTR_LOGV(verbose,
|
||||||
|
"Bypass routing due to no routing traces found\n");
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
VTR_ASSERT(1 == pb_route_indices.size());
|
VTR_ASSERT(1 == pb_route_indices.size());
|
||||||
|
@ -512,9 +555,6 @@ void add_lb_router_nets(LbRouter& lb_router,
|
||||||
VTR_ASSERT(sink_lb_rr_nodes.size() == sink_pb_graph_pins.size());
|
VTR_ASSERT(sink_lb_rr_nodes.size() == sink_pb_graph_pins.size());
|
||||||
|
|
||||||
/* Output verbose messages for debugging only */
|
/* Output verbose messages for debugging only */
|
||||||
VTR_LOGV(verbose,
|
|
||||||
"Pb route for Net %s:\n",
|
|
||||||
atom_ctx.nlist.net_name(atom_net_id_to_route).c_str());
|
|
||||||
VTR_LOGV(verbose,
|
VTR_LOGV(verbose,
|
||||||
"Source node:\n\t%s -> %s\n",
|
"Source node:\n\t%s -> %s\n",
|
||||||
source_pb_pin->to_string().c_str(),
|
source_pb_pin->to_string().c_str(),
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
/////////////////////////////////////////
|
||||||
|
// Functionality: Two 2-input AND with clocked
|
||||||
|
// and combinational outputs
|
||||||
|
// Each of which are controlled by different clocks
|
||||||
|
// Author: Xifan Tang
|
||||||
|
////////////////////////////////////////
|
||||||
|
|
||||||
|
`timescale 1ns / 1ps
|
||||||
|
|
||||||
|
module and2_latch_2clock(
|
||||||
|
a0,
|
||||||
|
b0,
|
||||||
|
clk0,
|
||||||
|
a1,
|
||||||
|
b1,
|
||||||
|
clk1,
|
||||||
|
c0,
|
||||||
|
d0,
|
||||||
|
c1,
|
||||||
|
d1);
|
||||||
|
|
||||||
|
input wire clk0;
|
||||||
|
|
||||||
|
input wire a0;
|
||||||
|
input wire b0;
|
||||||
|
output wire c0;
|
||||||
|
output reg d0;
|
||||||
|
|
||||||
|
input wire clk1;
|
||||||
|
|
||||||
|
input wire a1;
|
||||||
|
input wire b1;
|
||||||
|
output wire c1;
|
||||||
|
output reg d1;
|
||||||
|
|
||||||
|
|
||||||
|
assign c0 = a0 & b0;
|
||||||
|
|
||||||
|
always @(posedge clk0) begin
|
||||||
|
d0 <= c0;
|
||||||
|
end
|
||||||
|
|
||||||
|
assign c1 = a1 & b1;
|
||||||
|
|
||||||
|
always @(posedge clk1) begin
|
||||||
|
d1 <= c1;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
|
@ -9,17 +9,11 @@
|
||||||
[GENERAL]
|
[GENERAL]
|
||||||
run_engine=openfpga_shell
|
run_engine=openfpga_shell
|
||||||
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
|
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
|
||||||
power_analysis = true
|
power_analysis = false
|
||||||
spice_output=false
|
spice_output=false
|
||||||
verilog_output=true
|
verilog_output=true
|
||||||
timeout_each_job = 20*60
|
timeout_each_job = 20*60
|
||||||
# Due to the limitation in ACE2 which cannot output .blif files
|
fpga_flow=yosys_vpr
|
||||||
# with correct multi-clock assignments to .latch lines
|
|
||||||
# We have to use the vpr_blif flow where the .blif is modified
|
|
||||||
# based on yosys outputs with correct clock assignment!
|
|
||||||
# TODO: This limitation should be removed and we should use yosys_vpr flow!!!
|
|
||||||
fpga_flow=vpr_blif
|
|
||||||
#fpga_flow=yosys_vpr
|
|
||||||
|
|
||||||
[OpenFPGA_SHELL]
|
[OpenFPGA_SHELL]
|
||||||
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/global_tile_multiclock_example_script.openfpga
|
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/global_tile_multiclock_example_script.openfpga
|
||||||
|
@ -32,14 +26,12 @@ openfpga_pin_constraints_file=${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_te
|
||||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_GlobalTile4Clk_40nm.xml
|
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_GlobalTile4Clk_40nm.xml
|
||||||
|
|
||||||
[BENCHMARKS]
|
[BENCHMARKS]
|
||||||
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counter4bit_2clock/counter4bit_2clock.blif
|
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counter4bit_2clock/counter4bit_2clock.v
|
||||||
#bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counter4bit_2clock/counter4bit_2clock.v
|
bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch_2clock/and2_latch_2clock.v
|
||||||
|
|
||||||
[SYNTHESIS_PARAM]
|
[SYNTHESIS_PARAM]
|
||||||
bench0_top = counter4bit_2clock
|
bench0_top = counter4bit_2clock
|
||||||
bench0_act=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counter4bit_2clock/counter4bit_2clock.act
|
bench1_top = and2_latch_2clock
|
||||||
bench0_verilog=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counter4bit_2clock/counter4bit_2clock_post_yosys.v
|
|
||||||
bench0_chan_width = 300
|
|
||||||
|
|
||||||
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||||
end_flow_with_test=
|
end_flow_with_test=
|
||||||
|
|
Loading…
Reference in New Issue