10
10
#include "vtr_log.h"
11
11
12
12
#include "vpr_error.h"
13
+ #include "vpr_utils.h"
14
+
15
+ std ::map < AtomNetId ,std ::vector < AtomPinId >> find_clock_used_as_data_pins (const AtomNetlist & netlist );
16
+
17
+ AtomBlockId fix_clock_to_data_pins (AtomNetlist & netlist ,
18
+ const AtomNetId clock_net , const std ::vector < AtomPinId > & data_pins ,
19
+ const t_model * blk_model ,
20
+ const t_model_ports * model_clock_port , const BitIndex clock_port_bit ,
21
+ const t_model_ports * model_data_port , const BitIndex data_port_bit );
13
22
14
23
std ::vector < AtomBlockId > identify_buffer_luts (const AtomNetlist & netlist );
15
24
bool is_buffer_lut (const AtomNetlist & netlist , const AtomBlockId blk );
@@ -123,9 +132,6 @@ void print_netlist_as_blif(FILE* f, const AtomNetlist& netlist) {
123
132
auto input_ports = netlist .block_input_ports (blk_id );
124
133
auto output_ports = netlist .block_output_ports (blk_id );
125
134
auto clock_ports = netlist .block_clock_ports (blk_id );
126
- VTR_ASSERT (input_ports .size () == 1 );
127
- VTR_ASSERT (output_ports .size () == 1 );
128
- VTR_ASSERT (clock_ports .size () == 1 );
129
135
130
136
for (auto ports : {input_ports , output_ports , clock_ports }) {
131
137
for (AtomPortId port_id : ports ) {
@@ -149,21 +155,35 @@ void print_netlist_as_blif(FILE* f, const AtomNetlist& netlist) {
149
155
}
150
156
}
151
157
158
+ if (d_net .empty ()) {
159
+ d_net = make_unconn (unconn_count , AtomPinType ::SINK );
160
+ }
161
+
162
+ if (q_net .empty ()) {
163
+ q_net = make_unconn (unconn_count , AtomPinType ::DRIVER );
164
+ }
165
+
166
+ if (clk_net .empty ()) {
167
+ clk_net = make_unconn (unconn_count , AtomPinType ::SINK );
168
+ }
169
+
152
170
//Latch type: VPR always assumes rising edge
153
171
auto type = "re" ;
154
172
155
173
//Latch initial value
156
174
int init_val = 3 ; //Unkown or unspecified
157
175
//The initial value is stored as a single value in the truth table
158
176
const auto& so_cover = netlist .block_truth_table (blk_id );
159
- VTR_ASSERT (so_cover .size () == 1 ); //Only one row
160
- VTR_ASSERT (so_cover [0 ].size () == 1 ); //Only one column
161
- switch (so_cover [0 ][0 ]) {
162
- case vtr ::LogicValue ::TRUE: init_val = 1 ; break ;
163
- case vtr ::LogicValue ::FALSE: init_val = 0 ; break ;
164
- case vtr ::LogicValue ::DONT_CARE : init_val = 2 ; break ;
165
- case vtr ::LogicValue ::UNKOWN : init_val = 3 ; break ;
166
- default : VTR_ASSERT_MSG (false, "Unrecognzied latch initial state" );
177
+ if (so_cover .size () == 1 ) {
178
+ VTR_ASSERT (so_cover .size () == 1 ); //Only one row
179
+ VTR_ASSERT (so_cover [0 ].size () == 1 ); //Only one column
180
+ switch (so_cover [0 ][0 ]) {
181
+ case vtr ::LogicValue ::TRUE: init_val = 1 ; break ;
182
+ case vtr ::LogicValue ::FALSE: init_val = 0 ; break ;
183
+ case vtr ::LogicValue ::DONT_CARE : init_val = 2 ; break ;
184
+ case vtr ::LogicValue ::UNKOWN : init_val = 3 ; break ;
185
+ default : VTR_ASSERT_MSG (false, "Unrecognzied latch initial state" );
186
+ }
167
187
}
168
188
169
189
fprintf (f , ".latch %s %s %s %s %d\n" , d_net .c_str (), q_net .c_str (), type , clk_net .c_str (), init_val );
@@ -557,6 +577,102 @@ void remove_buffer_lut(AtomNetlist& netlist, AtomBlockId blk) {
557
577
558
578
}
559
579
580
+ void fix_clock_to_data_conversions (AtomNetlist & netlist , const t_model * library_models ) {
581
+ //Some netlists contain clock signals that are also used as data inputs
582
+ //
583
+ //This function removes these cases by creating a new net whose sinks are the
584
+ //'data' sinks of the clock net. This net is then driven by a latch with no
585
+ //input data signal, but clocked by the original clock
586
+
587
+ auto clock_data_pins = find_clock_used_as_data_pins (netlist );
588
+
589
+ //Use the latch D port to generate the data version fo the clock
590
+ const t_model * model = find_model (library_models , "latch" );
591
+ VTR_ASSERT (model );
592
+ const t_model_ports * clock_port = find_model_port (model , "clk" );
593
+ VTR_ASSERT (clock_port );
594
+ BitIndex clock_port_bit = 0 ;
595
+
596
+ const t_model_ports * data_port = find_model_port (model , "Q" );
597
+ VTR_ASSERT (data_port );
598
+ BitIndex data_port_bit = 0 ;
599
+
600
+ for (auto kv : clock_data_pins ) {
601
+ AtomNetId clock_net = kv .first ;
602
+ const std ::vector < AtomPinId > & data_pins = kv .second ;
603
+
604
+ vtr ::printf_warning (__FILE__ , __LINE__ , "Clock '%s' drives both clock and data pins, splitting it into separate clock and data nets\n" ,
605
+ netlist .net_name (clock_net ).c_str ());
606
+
607
+ fix_clock_to_data_pins (netlist ,
608
+ clock_net , data_pins ,
609
+ model ,
610
+ clock_port , clock_port_bit ,
611
+ data_port , data_port_bit );
612
+ }
613
+ }
614
+
615
+ //Finds all clock sinks which are data ports in the netlist.
616
+ //Returns a map of clock_net to the clock's data_sinks
617
+ std ::map < AtomNetId ,std ::vector < AtomPinId >> find_clock_used_as_data_pins (const AtomNetlist & netlist ) {
618
+ std ::map < AtomNetId ,std ::vector < AtomPinId >> clock_data_pins ;
619
+
620
+ auto netlist_clocks = find_netlist_clocks (netlist );
621
+
622
+
623
+ for (AtomNetId clock_net : netlist_clocks ) {
624
+ for (AtomPinId clock_sink : netlist .net_sinks (clock_net )) {
625
+
626
+ auto port_type = netlist .pin_port_type (clock_sink );
627
+
628
+ if (port_type != AtomPortType ::CLOCK ) {
629
+
630
+ clock_data_pins [clock_net ].push_back (clock_sink );
631
+ }
632
+ }
633
+ }
634
+
635
+ return clock_data_pins ;
636
+ }
637
+
638
+ AtomBlockId fix_clock_to_data_pins (AtomNetlist & netlist ,
639
+ const AtomNetId clock_net , const std ::vector < AtomPinId > & data_pins ,
640
+ const t_model * blk_model ,
641
+ const t_model_ports * model_clock_port , const BitIndex clock_port_bit ,
642
+ const t_model_ports * model_data_port , const BitIndex data_port_bit ) {
643
+ //Create a new block clocked by clock_net which will drive the 'data' version of the clock
644
+
645
+ std ::string blk_name = "__vpr__" + netlist .net_name (clock_net ) + "__as_data__" ;
646
+ VTR_ASSERT_MSG (!netlist .find_block (blk_name ), "Failed to create unique clock as data source block name" );
647
+
648
+ //Make the block
649
+ AtomBlockId blk = netlist .create_block (blk_name , blk_model );
650
+ VTR_ASSERT (blk );
651
+
652
+ //Connect the clock
653
+ AtomPortId clock_port = netlist .create_port (blk , model_clock_port );
654
+ netlist .create_pin (clock_port , clock_port_bit , clock_net , AtomPinType ::SINK );
655
+
656
+ //Make the data port
657
+ AtomPortId data_port = netlist .create_port (blk , model_data_port );
658
+
659
+ //Make the net
660
+ VTR_ASSERT_MSG (!netlist .find_net (blk_name ), "Failed to create unique clock as data net name" );
661
+ AtomNetId clock_data_net = netlist .create_net (blk_name );
662
+ VTR_ASSERT (clock_data_net );
663
+
664
+ //Create the driver pin
665
+ netlist .create_pin (data_port , data_port_bit , clock_data_net , AtomPinType ::DRIVER );
666
+
667
+ //Update all the data pins to connect to clock_data_net instead of the original clock net
668
+ for (AtomPinId sink_pin : data_pins ) {
669
+
670
+ netlist .set_pin_net (sink_pin , AtomPinType ::SINK , clock_data_net );
671
+ }
672
+
673
+ return blk ;
674
+ }
675
+
560
676
bool is_removable_block (const AtomNetlist & netlist , const AtomBlockId blk_id ) {
561
677
//Any block with no fanout is removable
562
678
for (AtomPinId pin_id : netlist .block_output_pins (blk_id )) {
@@ -797,7 +913,7 @@ std::string make_unconn(size_t& unconn_count, AtomPinType /*pin_type*/) {
797
913
return std ::string ("unconn" );
798
914
}
799
915
#else
800
- return std ::string ("unconn " ) + std ::to_string (unconn_count ++ );
916
+ return std ::string ("__vpr__unconn " ) + std ::to_string (unconn_count ++ );
801
917
#endif
802
918
}
803
919
@@ -963,6 +1079,8 @@ std::set<AtomNetId> find_netlist_clocks(const AtomNetlist& netlist) {
963
1079
//
964
1080
//Since we don't have good information about what pins are clock generators we build a lookup as we go
965
1081
for (auto blk_id : netlist .blocks ()) {
1082
+ if (!blk_id ) continue ;
1083
+
966
1084
AtomBlockType type = netlist .block_type (blk_id );
967
1085
if (type != AtomBlockType ::BLOCK ) continue ;
968
1086
@@ -986,6 +1104,8 @@ std::set<AtomNetId> find_netlist_clocks(const AtomNetlist& netlist) {
986
1104
987
1105
//Look for connected input clocks
988
1106
for (auto pin_id : netlist .block_clock_pins (blk_id )) {
1107
+ if (!pin_id ) continue ;
1108
+
989
1109
AtomNetId clk_net_id = netlist .pin_net (pin_id );
990
1110
VTR_ASSERT (clk_net_id );
991
1111
@@ -1001,8 +1121,11 @@ std::set<AtomNetId> find_netlist_clocks(const AtomNetlist& netlist) {
1001
1121
AtomPortId clk_gen_port = netlist .find_port (blk_id , model_port );
1002
1122
1003
1123
for (AtomPinId pin_id : netlist .port_pins (clk_gen_port )) {
1124
+ if (!pin_id ) continue ;
1125
+
1004
1126
AtomNetId clk_net_id = netlist .pin_net (pin_id );
1005
- VTR_ASSERT (clk_net_id );
1127
+ if (!clk_net_id ) continue ;
1128
+
1006
1129
clock_nets .insert (clk_net_id );
1007
1130
}
1008
1131
}
0 commit comments