2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include "kernel/yosys.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/modtools.h"
25 PRIVATE_NAMESPACE_BEGIN
27 //get the list of cells hooked up to at least one bit of a given net
28 pool
<Cell
*> get_other_cells(const RTLIL::SigSpec
& port
, ModIndex
& index
, Cell
* src
)
33 pool
<ModIndex::PortInfo
> ports
= index
.query_ports(b
);
44 //return true if there is a full-width bus connection from cell a port ap to cell b port bp
45 //if other_conns_allowed is false, then we require a strict point to point connection (no other links)
47 const RTLIL::SigSpec
& sig
,
53 bool other_conns_allowed
= false)
57 pool
<ModIndex::PortInfo
> ports
= index
.query_ports(s
);
62 if( (x
.cell
== a
) && (x
.port
== ap
) )
64 else if( (x
.cell
== b
) && (x
.port
== bp
) )
66 else if(!other_conns_allowed
)
70 if( (!found_a
) || (!found_b
) )
77 //return true if the signal connects to one port only (nothing on the other end)
78 bool is_unconnected(const RTLIL::SigSpec
& port
, ModIndex
& index
)
82 pool
<ModIndex::PortInfo
> ports
= index
.query_ports(b
);
90 struct CounterExtraction
92 int width
; //counter width
93 bool count_is_up
; //count up (else down)
94 RTLIL::Wire
* rwire
; //the register output
95 bool has_reset
; //true if we have a reset
96 bool has_ce
; //true if we have a clock enable
97 bool ce_inverted
; //true if clock enable is active low
98 RTLIL::SigSpec rst
; //reset pin
99 bool rst_inverted
; //true if reset is active low
100 bool rst_to_max
; //true if we reset to max instead of 0
101 int count_value
; //value we count from
102 RTLIL::SigSpec ce
; //clock signal
103 RTLIL::SigSpec clk
; //clock enable, if any
104 RTLIL::SigSpec outsig
; //counter overflow output signal
105 RTLIL::SigSpec poutsig
; //counter parallel output signal
106 bool has_pout
; //whether parallel output is used
107 RTLIL::Cell
* count_mux
; //counter mux
108 RTLIL::Cell
* count_reg
; //counter register
109 RTLIL::Cell
* overflow_cell
; //cell for counter overflow (either inverter reduction or $eq)
110 pool
<ModIndex::PortInfo
> pouts
; //Ports that take a parallel output from us
113 struct CounterExtractionSettings
115 pool
<RTLIL::IdString
>& parallel_cells
;
119 int allowed_dirs
; //0 = down, 1 = up, 2 = both
122 //attempt to extract a counter centered on the given adder cell
123 //For now we only support DOWN counters.
124 //TODO: up/down support
125 int counter_tryextract(
128 CounterExtraction
& extract
,
129 CounterExtractionSettings settings
)
131 SigMap
& sigmap
= index
.sigmap
;
133 //Both inputs must be unsigned, so don't extract anything with a signed input
134 bool a_sign
= cell
->getParam(ID::A_SIGNED
).as_bool();
135 bool b_sign
= cell
->getParam(ID::B_SIGNED
).as_bool();
139 //CO and X must be unconnected (exactly one connection to each port)
140 if(!is_unconnected(sigmap(cell
->getPort(ID::CO
)), index
))
142 if(!is_unconnected(sigmap(cell
->getPort(ID::X
)), index
))
145 //true if $alu is performing A - B, else A + B
146 bool alu_is_subtract
;
148 //BI and CI must be both constant 0 or both constant 1 as well
149 const RTLIL::SigSpec bi_port
= sigmap(cell
->getPort(ID::BI
));
150 const RTLIL::SigSpec ci_port
= sigmap(cell
->getPort(ID::CI
));
151 if(bi_port
.is_fully_const() && bi_port
.as_int() == 1 &&
152 ci_port
.is_fully_const() && ci_port
.as_int() == 1)
154 alu_is_subtract
= true;
156 else if(bi_port
.is_fully_const() && bi_port
.as_int() == 0 &&
157 ci_port
.is_fully_const() && ci_port
.as_int() == 0)
159 alu_is_subtract
= false;
166 //false -> port B connects to value
167 //true -> port A connects to value
168 bool alu_port_use_a
= false;
172 const int a_width
= cell
->getParam(ID::A_WIDTH
).as_int();
173 const int b_width
= cell
->getParam(ID::B_WIDTH
).as_int();
174 const RTLIL::SigSpec b_port
= sigmap(cell
->getPort(ID::B
));
176 // down, cnt <= cnt - 1
177 if (b_width
== 1 && b_port
.is_fully_const() && b_port
.as_int() == 1)
180 alu_port_use_a
= true;
181 extract
.count_is_up
= false;
184 // up, cnt <= cnt - -1
185 else if (b_width
== a_width
&& b_port
.is_fully_const() && b_port
.is_fully_ones())
188 alu_port_use_a
= true;
189 extract
.count_is_up
= true;
200 const int a_width
= cell
->getParam(ID::A_WIDTH
).as_int();
201 const int b_width
= cell
->getParam(ID::B_WIDTH
).as_int();
202 const RTLIL::SigSpec a_port
= sigmap(cell
->getPort(ID::A
));
203 const RTLIL::SigSpec b_port
= sigmap(cell
->getPort(ID::B
));
205 // down, cnt <= cnt + -1
206 if (b_width
== a_width
&& b_port
.is_fully_const() && b_port
.is_fully_ones())
209 alu_port_use_a
= true;
210 extract
.count_is_up
= false;
212 else if (a_width
== b_width
&& a_port
.is_fully_const() && a_port
.is_fully_ones())
215 alu_port_use_a
= false;
216 extract
.count_is_up
= false;
219 // up, cnt <= cnt + 1
220 else if (b_width
== 1 && b_port
.is_fully_const() && b_port
.as_int() == 1)
223 alu_port_use_a
= true;
224 extract
.count_is_up
= true;
226 else if (a_width
== 1 && a_port
.is_fully_const() && a_port
.as_int() == 1)
229 alu_port_use_a
= false;
230 extract
.count_is_up
= true;
240 if (extract
.count_is_up
&& settings
.allowed_dirs
== 0)
242 if (!extract
.count_is_up
&& settings
.allowed_dirs
== 1)
245 //Check if counter is an appropriate size
248 count_width
= cell
->getParam(ID::A_WIDTH
).as_int();
250 count_width
= cell
->getParam(ID::B_WIDTH
).as_int();
251 extract
.width
= count_width
;
252 if( (count_width
< settings
.minwidth
) || (count_width
> settings
.maxwidth
) )
255 //Y must have exactly one connection, and it has to be a $mux cell.
256 //We must have a direct bus connection from our Y to their A.
257 const RTLIL::SigSpec aluy
= sigmap(cell
->getPort(ID::Y
));
258 pool
<Cell
*> y_loads
= get_other_cells(aluy
, index
, cell
);
259 if(y_loads
.size() != 1)
261 Cell
* count_mux
= *y_loads
.begin();
262 extract
.count_mux
= count_mux
;
263 if(count_mux
->type
!= ID($mux
))
265 if(!is_full_bus(aluy
, index
, cell
, ID::Y
, count_mux
, ID::A
))
268 if (extract
.count_is_up
)
270 //B connection of the mux must be 0
271 const RTLIL::SigSpec underflow
= sigmap(count_mux
->getPort(ID::B
));
272 if(!(underflow
.is_fully_const() && underflow
.is_fully_zero()))
277 //B connection of the mux is our underflow value
278 const RTLIL::SigSpec underflow
= sigmap(count_mux
->getPort(ID::B
));
279 if(!underflow
.is_fully_const())
281 extract
.count_value
= underflow
.as_int();
284 //S connection of the mux must come from an inverter if down, eq if up
285 //(need not be the only load)
286 const RTLIL::SigSpec muxsel
= sigmap(count_mux
->getPort(ID::S
));
287 extract
.outsig
= muxsel
;
288 pool
<Cell
*> muxsel_conns
= get_other_cells(muxsel
, index
, count_mux
);
289 Cell
* overflow_cell
= NULL
;
290 for(auto c
: muxsel_conns
)
292 if(extract
.count_is_up
&& c
->type
!= ID($eq
))
294 if(!extract
.count_is_up
&& c
->type
!= ID($logic_not
))
296 if(!is_full_bus(muxsel
, index
, c
, ID::Y
, count_mux
, ID::S
, true))
302 if(overflow_cell
== NULL
)
304 extract
.overflow_cell
= overflow_cell
;
306 //Y connection of the mux must have exactly one load, the counter's internal register, if there's no clock enable
307 //If we have a clock enable, Y drives the B input of a mux. A of that mux must come from our register
308 const RTLIL::SigSpec muxy
= sigmap(count_mux
->getPort(ID::Y
));
309 pool
<Cell
*> muxy_loads
= get_other_cells(muxy
, index
, count_mux
);
310 if(muxy_loads
.size() != 1)
312 Cell
* muxload
= *muxy_loads
.begin();
313 Cell
* count_reg
= muxload
;
316 if(muxload
->type
== ID($mux
))
318 //This mux is probably a clock enable mux.
319 //Find our count register (should be our only load)
321 cey
= sigmap(cemux
->getPort(ID::Y
));
322 pool
<Cell
*> cey_loads
= get_other_cells(cey
, index
, cemux
);
323 if(cey_loads
.size() != 1)
325 count_reg
= *cey_loads
.begin();
327 if(sigmap(cemux
->getPort(ID::Y
)) != sigmap(count_reg
->getPort(ID::D
)))
329 //Mux should have A driven by count Q, and B by muxy
330 //if A and B are swapped, CE polarity is inverted
331 if(sigmap(cemux
->getPort(ID::B
)) == muxy
&&
332 sigmap(cemux
->getPort(ID::A
)) == sigmap(count_reg
->getPort(ID::Q
)))
334 extract
.ce_inverted
= false;
336 else if(sigmap(cemux
->getPort(ID::A
)) == muxy
&&
337 sigmap(cemux
->getPort(ID::B
)) == sigmap(count_reg
->getPort(ID::Q
)))
339 extract
.ce_inverted
= true;
346 //Select of the mux is our clock enable
347 extract
.has_ce
= true;
348 extract
.ce
= sigmap(cemux
->getPort(ID::S
));
351 extract
.has_ce
= false;
353 extract
.count_reg
= count_reg
;
354 if(count_reg
->type
== ID($dff
))
355 extract
.has_reset
= false;
356 else if(count_reg
->type
== ID($adff
))
358 if (!settings
.allow_arst
)
361 extract
.has_reset
= true;
363 //Check polarity of reset - we may have to add an inverter later on!
364 extract
.rst_inverted
= (count_reg
->getParam(ID::ARST_POLARITY
).as_int() != 1);
366 //Verify ARST_VALUE is zero or full scale
367 int rst_value
= count_reg
->getParam(ID::ARST_VALUE
).as_int();
369 extract
.rst_to_max
= false;
370 else if(rst_value
== extract
.count_value
)
371 extract
.rst_to_max
= true;
376 extract
.rst
= sigmap(count_reg
->getPort(ID::ARST
));
378 //TODO: support synchronous reset
382 //Sanity check that we use the ALU output properly
385 if(!extract
.ce_inverted
&& !is_full_bus(muxy
, index
, count_mux
, ID::Y
, cemux
, ID::B
))
387 if(extract
.ce_inverted
&& !is_full_bus(muxy
, index
, count_mux
, ID::Y
, cemux
, ID::A
))
389 if(!is_full_bus(cey
, index
, cemux
, ID::Y
, count_reg
, ID::D
))
392 else if(!is_full_bus(muxy
, index
, count_mux
, ID::Y
, count_reg
, ID::D
))
395 //TODO: Verify count_reg CLK_POLARITY is 1
397 //Register output must have exactly two loads, the inverter and ALU
398 //(unless we have a parallel output!)
399 //If we have a clock enable, 3 is OK
400 const RTLIL::SigSpec qport
= count_reg
->getPort(ID::Q
);
401 extract
.poutsig
= qport
;
402 extract
.has_pout
= false;
403 const RTLIL::SigSpec cnout
= sigmap(qport
);
404 pool
<Cell
*> cnout_loads
= get_other_cells(cnout
, index
, count_reg
);
405 unsigned int max_loads
= 2;
408 if(cnout_loads
.size() > max_loads
)
410 for(auto c
: cnout_loads
)
412 if(c
== overflow_cell
)
419 //If we specified a limited set of cells for parallel output, check that we only drive them
420 if(!settings
.parallel_cells
.empty())
422 //Make sure we're in the whitelist
423 if( settings
.parallel_cells
.find(c
->type
) == settings
.parallel_cells
.end())
427 //Figure out what port(s) are driven by it
428 //TODO: this can probably be done more efficiently w/o multiple iterations over our whole net?
429 //TODO: For what purpose do we actually need extract.pouts?
432 pool
<ModIndex::PortInfo
> ports
= index
.query_ports(b
);
437 extract
.pouts
.insert(ModIndex::PortInfo(c
, x
.port
, 0));
438 extract
.has_pout
= true;
445 if(index
.query_is_output(b
))
447 // Parallel out goes out of module
448 extract
.has_pout
= true;
451 if(!extract
.count_is_up
)
453 if(!is_full_bus(cnout
, index
, count_reg
, ID::Q
, overflow_cell
, ID::A
, true))
458 if(is_full_bus(cnout
, index
, count_reg
, ID::Q
, overflow_cell
, ID::A
, true))
460 // B must be the overflow value
461 const RTLIL::SigSpec overflow
= sigmap(overflow_cell
->getPort(ID::B
));
462 if(!overflow
.is_fully_const())
464 extract
.count_value
= overflow
.as_int();
466 else if(is_full_bus(cnout
, index
, count_reg
, ID::Q
, overflow_cell
, ID::B
, true))
468 // A must be the overflow value
469 const RTLIL::SigSpec overflow
= sigmap(overflow_cell
->getPort(ID::A
));
470 if(!overflow
.is_fully_const())
472 extract
.count_value
= overflow
.as_int();
479 if(alu_port_use_a
&& !is_full_bus(cnout
, index
, count_reg
, ID::Q
, cell
, ID::A
, true))
481 if(!alu_port_use_a
&& !is_full_bus(cnout
, index
, count_reg
, ID::Q
, cell
, ID::B
, true))
484 //Look up the clock from the register
485 extract
.clk
= sigmap(count_reg
->getPort(ID::CLK
));
487 if(!extract
.count_is_up
)
489 //Register output net must have an INIT attribute equal to the count value
490 extract
.rwire
= cnout
.as_wire();
491 if(extract
.rwire
->attributes
.find(ID::init
) == extract
.rwire
->attributes
.end())
493 int rinit
= extract
.rwire
->attributes
[ID::init
].as_int();
494 if(rinit
!= extract
.count_value
)
499 //Register output net must not have an INIT attribute or it must be zero
500 extract
.rwire
= cnout
.as_wire();
501 if(extract
.rwire
->attributes
.find(ID::init
) == extract
.rwire
->attributes
.end())
503 int rinit
= extract
.rwire
->attributes
[ID::init
].as_int();
514 unsigned int& total_counters
,
515 pool
<Cell
*>& cells_to_remove
,
516 pool
<pair
<Cell
*, string
>>& cells_to_rename
,
517 CounterExtractionSettings settings
)
519 SigMap
& sigmap
= index
.sigmap
;
521 //Core of the counter must be an ALU
522 if (cell
->type
!= ID($alu
))
525 //A input is the count value. Check if it has COUNT_EXTRACT set.
526 //If it's not a wire, don't even try
527 auto port
= sigmap(cell
->getPort(ID::A
));
530 port
= sigmap(cell
->getPort(ID::B
));
534 RTLIL::Wire
* port_wire
= port
.as_wire();
535 bool force_extract
= false;
536 bool never_extract
= false;
537 string count_reg_src
= port_wire
->attributes
[ID::src
].decode_string().c_str();
538 if(port_wire
->attributes
.find(ID(COUNT_EXTRACT
)) != port_wire
->attributes
.end())
540 pool
<string
> sa
= port_wire
->get_strpool_attribute(ID(COUNT_EXTRACT
));
541 string extract_value
;
544 extract_value
= *sa
.begin();
545 log(" Signal %s declared at %s has COUNT_EXTRACT = %s\n",
547 count_reg_src
.c_str(),
548 extract_value
.c_str());
550 if(extract_value
== "FORCE")
551 force_extract
= true;
552 else if(extract_value
== "NO")
553 never_extract
= true;
554 else if(extract_value
== "AUTO")
557 log_error(" Illegal COUNT_EXTRACT value %s (must be one of FORCE, NO, AUTO)\n",
558 extract_value
.c_str());
562 //If we're explicitly told not to extract, don't infer a counter
566 //Attempt to extract a counter
567 CounterExtraction extract
;
568 int reason
= counter_tryextract(index
, cell
, extract
, settings
);
570 //Nonzero code - we could not find a matchable counter.
571 //Do nothing, unless extraction was forced in which case give an error
574 static const char* reasons
[]=
577 "counter is too large/small", //1
578 "counter does not count by one", //2
579 "counter uses signed math", //3
580 "RESERVED, not implemented", //4
581 "ALU is not an adder/subtractor", //5
582 "RESERVED, not implemented", //6
583 "ALU ports used outside counter", //7
584 "ALU ports used outside counter", //8
585 "ALU output used outside counter", //9
586 "ALU output is not a mux", //10
587 "ALU output is not full bus", //11
588 "Underflow value is not constant", //12
589 "No underflow detector found", //13
590 "Mux output is used outside counter", //14
591 "Counter reg is not DFF/ADFF", //15
592 "Counter input is not full bus", //16
593 "Count register is used outside counter, but not by an allowed cell", //17
594 "Register output is not full bus", //18
595 "Register output is not full bus", //19
596 "No init value found", //20
597 "Underflow value is not equal to init value", //21
598 "RESERVED, not implemented", //22, kept for compatibility but not used anymore
599 "Reset is not to zero or COUNT_TO", //23
600 "Clock enable configuration is unsupported", //24
601 "Async reset used but not permitted", //25
602 "Count direction is not allowed" //26
608 "Counter extraction is set to FORCE on register %s, but a counter could not be inferred (%s)\n",
616 string countname
= string("$COUNTx$") + log_id(extract
.rwire
->name
.str());
618 //Wipe all of the old connections to the ALU
619 cell
->unsetPort(ID::A
);
620 cell
->unsetPort(ID::B
);
621 cell
->unsetPort(ID::BI
);
622 cell
->unsetPort(ID::CI
);
623 cell
->unsetPort(ID::CO
);
624 cell
->unsetPort(ID::X
);
625 cell
->unsetPort(ID::Y
);
626 cell
->unsetParam(ID::A_SIGNED
);
627 cell
->unsetParam(ID::A_WIDTH
);
628 cell
->unsetParam(ID::B_SIGNED
);
629 cell
->unsetParam(ID::B_WIDTH
);
630 cell
->unsetParam(ID::Y_WIDTH
);
632 //Change the cell type
633 cell
->type
= ID($__COUNT_
);
636 if(extract
.has_reset
)
638 //TODO: support other kinds of reset
639 cell
->setParam(ID(RESET_MODE
), RTLIL::Const("LEVEL"));
641 //If the reset is active low, infer an inverter ($__COUNT_ cells always have active high reset)
642 if(extract
.rst_inverted
)
644 auto realreset
= cell
->module
->addWire(NEW_ID
);
645 cell
->module
->addNot(NEW_ID
, extract
.rst
, RTLIL::SigSpec(realreset
));
646 cell
->setPort(ID(RST
), realreset
);
649 cell
->setPort(ID(RST
), extract
.rst
);
653 cell
->setParam(ID(RESET_MODE
), RTLIL::Const("RISING"));
654 cell
->setPort(ID(RST
), RTLIL::SigSpec(false));
657 //Hook up other stuff
658 //cell->setParam(ID(CLKIN_DIVIDE), RTLIL::Const(1));
659 cell
->setParam(ID(COUNT_TO
), RTLIL::Const(extract
.count_value
));
660 cell
->setParam(ID::WIDTH
, RTLIL::Const(extract
.width
));
661 cell
->setPort(ID::CLK
, extract
.clk
);
662 cell
->setPort(ID(OUT
), extract
.outsig
);
664 //Hook up clock enable
667 cell
->setParam(ID(HAS_CE
), RTLIL::Const(1));
668 if(extract
.ce_inverted
)
670 auto realce
= cell
->module
->addWire(NEW_ID
);
671 cell
->module
->addNot(NEW_ID
, extract
.ce
, RTLIL::SigSpec(realce
));
672 cell
->setPort(ID(CE
), realce
);
675 cell
->setPort(ID(CE
), extract
.ce
);
679 cell
->setParam(ID(HAS_CE
), RTLIL::Const(0));
680 cell
->setPort(ID(CE
), RTLIL::Const(1));
683 if(extract
.count_is_up
)
685 cell
->setParam(ID(DIRECTION
), RTLIL::Const("UP"));
686 //XXX: What is this supposed to do?
687 cell
->setPort(ID(UP
), RTLIL::Const(1));
691 cell
->setParam(ID(DIRECTION
), RTLIL::Const("DOWN"));
692 cell
->setPort(ID(UP
), RTLIL::Const(0));
695 //Hook up hard-wired ports, default to no parallel output
696 cell
->setParam(ID(HAS_POUT
), RTLIL::Const(0));
697 cell
->setParam(ID(RESET_TO_MAX
), RTLIL::Const(0));
699 //Hook up any parallel outputs
700 for(auto load
: extract
.pouts
)
702 log(" Counter has parallel output to cell %s port %s\n", log_id(load
.cell
->name
), log_id(load
.port
));
706 //Connect it to our parallel output
707 cell
->setPort(ID(POUT
), extract
.poutsig
);
708 cell
->setParam(ID(HAS_POUT
), RTLIL::Const(1));
711 //Delete the cells we've replaced (let opt_clean handle deleting the now-redundant wires)
712 cells_to_remove
.insert(extract
.count_mux
);
713 cells_to_remove
.insert(extract
.count_reg
);
714 cells_to_remove
.insert(extract
.overflow_cell
);
718 string reset_type
= "non-resettable";
719 if(extract
.has_reset
)
721 if(extract
.rst_inverted
)
722 reset_type
= "negative";
724 reset_type
= "positive";
726 //TODO: support other kind of reset
727 reset_type
+= " async resettable";
729 log(" Found %d-bit (%s) %s counter %s (counting %s %d) for register %s, declared at %s\n",
732 extract
.count_is_up
? "up" : "down",
734 extract
.count_is_up
? "to" : "from",
736 log_id(extract
.rwire
->name
),
737 count_reg_src
.c_str());
739 //Optimize the counter
740 //If we have no parallel output, and we have redundant bits, shrink us
741 if(!extract
.has_pout
)
743 //TODO: Need to update this when we add support for counters with nonzero reset values
744 //to make sure the reset value fits in our bit space too
747 int newbits
= ceil(log2(extract
.count_value
));
748 if(extract
.width
!= newbits
)
750 cell
->setParam(ID::WIDTH
, RTLIL::Const(newbits
));
751 log(" Optimizing out %d unused high-order bits (new width is %d)\n",
752 extract
.width
- newbits
,
757 //Finally, rename the cell
758 cells_to_rename
.insert(pair
<Cell
*, string
>(cell
, countname
));
761 struct ExtractCounterPass
: public Pass
{
762 ExtractCounterPass() : Pass("extract_counter", "Extract GreenPak4 counter cells") { }
763 void help() YS_OVERRIDE
765 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
767 log(" extract_counter [options] [selection]\n");
769 log("This pass converts non-resettable or async resettable down counters to\n");
770 log("counter cells. Use a target-specific 'techmap' map file to convert those cells\n");
771 log("to the actual target cells.\n");
773 log(" -maxwidth N\n");
774 log(" Only extract counters up to N bits wide (default 64)\n");
776 log(" -minwidth N\n");
777 log(" Only extract counters at least N bits wide (default 2)\n");
779 log(" -allow_arst yes|no\n");
780 log(" Allow counters to have async reset (default yes)\n");
782 log(" -dir up|down|both\n");
783 log(" Look for up-counters, down-counters, or both (default down)\n");
785 log(" -pout X,Y,...\n");
786 log(" Only allow parallel output from the counter to the listed cell types\n");
787 log(" (if not specified, parallel outputs are not restricted)\n");
791 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
793 log_header(design
, "Executing EXTRACT_COUNTER pass (find counters in netlist).\n");
795 pool
<RTLIL::IdString
> _parallel_cells
;
796 CounterExtractionSettings settings
798 .parallel_cells
= _parallel_cells
,
806 for (argidx
= 1; argidx
< args
.size(); argidx
++)
808 if (args
[argidx
] == "-pout")
810 if(argidx
+ 1 >= args
.size())
812 log_error("extract_counter -pout requires an argument\n");
816 std::string pouts
= args
[++argidx
];
818 for(size_t i
=0; i
<pouts
.length(); i
++)
822 settings
.parallel_cells
.insert(RTLIL::escape_id(tmp
));
828 settings
.parallel_cells
.insert(RTLIL::escape_id(tmp
));
832 if (args
[argidx
] == "-maxwidth" && argidx
+1 < args
.size())
834 settings
.maxwidth
= atoi(args
[++argidx
].c_str());
838 if (args
[argidx
] == "-minwidth" && argidx
+1 < args
.size())
840 settings
.minwidth
= atoi(args
[++argidx
].c_str());
844 if (args
[argidx
] == "-allow_arst" && argidx
+1 < args
.size())
846 auto arg
= args
[++argidx
];
848 settings
.allow_arst
= true;
849 else if (arg
== "no")
850 settings
.allow_arst
= false;
852 log_error("Invalid -allow_arst value \"%s\"\n", arg
.c_str());
856 if (args
[argidx
] == "-dir" && argidx
+1 < args
.size())
858 auto arg
= args
[++argidx
];
860 settings
.allowed_dirs
= 1;
861 else if (arg
== "down")
862 settings
.allowed_dirs
= 0;
863 else if (arg
== "both")
864 settings
.allowed_dirs
= 2;
866 log_error("Invalid -dir value \"%s\"\n", arg
.c_str());
870 extra_args(args
, argidx
, design
);
872 if (settings
.minwidth
< 2)
874 //A counter with less than 2 bits makes no sense
875 log_warning("Minimum counter width is 2 bits wide\n");
876 settings
.minwidth
= 2;
879 //Extract all of the counters we could find
880 unsigned int total_counters
= 0;
881 for (auto module
: design
->selected_modules())
883 pool
<Cell
*> cells_to_remove
;
884 pool
<pair
<Cell
*, string
>> cells_to_rename
;
886 ModIndex
index(module
);
887 for (auto cell
: module
->selected_cells())
888 counter_worker(index
, cell
, total_counters
, cells_to_remove
, cells_to_rename
, settings
);
890 for(auto cell
: cells_to_remove
)
892 //log("Removing cell %s\n", log_id(cell->name));
893 module
->remove(cell
);
896 for(auto cpair
: cells_to_rename
)
898 //log("Renaming cell %s to %s\n", log_id(cpair.first->name), cpair.second.c_str());
899 module
->rename(cpair
.first
, cpair
.second
);
904 log("Extracted %u counters\n", total_counters
);
906 } ExtractCounterPass
;
908 PRIVATE_NAMESPACE_END