@@ -92,9 +92,13 @@ struct CounterExtraction
92
92
int width; // counter width
93
93
RTLIL::Wire* rwire; // the register output
94
94
bool has_reset; // true if we have a reset
95
+ bool has_ce; // true if we have a clock enable
95
96
RTLIL::SigSpec rst; // reset pin
97
+ bool rst_inverted; // true if reset is active low
98
+ bool rst_to_max; // true if we reset to max instead of 0
96
99
int count_value; // value we count from
97
- RTLIL::SigSpec clk; // clock signal
100
+ RTLIL::SigSpec ce; // clock signal
101
+ RTLIL::SigSpec clk; // clock enable, if any
98
102
RTLIL::SigSpec outsig; // counter output signal
99
103
RTLIL::Cell* count_mux; // counter mux
100
104
RTLIL::Cell* count_reg; // counter register
@@ -190,24 +194,60 @@ int counter_tryextract(
190
194
return 13 ;
191
195
extract.underflow_inv = underflow_inv;
192
196
193
- // Y connection of the mux must have exactly one load, the counter's internal register
197
+ // Y connection of the mux must have exactly one load, the counter's internal register, if there's no clock enable
198
+ // If we have a clock enable, Y drives the B input of a mux. A of that mux must come from our register
194
199
const RTLIL::SigSpec muxy = sigmap (count_mux->getPort (" \\ Y" ));
195
200
pool<Cell*> muxy_loads = get_other_cells (muxy, index , count_mux);
196
201
if (muxy_loads.size () != 1 )
197
202
return 14 ;
198
- Cell* count_reg = *muxy_loads.begin ();
203
+ Cell* muxload = *muxy_loads.begin ();
204
+ Cell* count_reg = muxload;
205
+ Cell* cemux = NULL ;
206
+ RTLIL::SigSpec cey;
207
+ if (muxload->type == " $mux" )
208
+ {
209
+ // This mux is probably a clock enable mux.
210
+ // Find our count register (should be our only load)
211
+ cemux = muxload;
212
+ cey = sigmap (cemux->getPort (" \\ Y" ));
213
+ pool<Cell*> cey_loads = get_other_cells (cey, index , cemux);
214
+ if (cey_loads.size () != 1 )
215
+ return 24 ;
216
+ count_reg = *cey_loads.begin ();
217
+
218
+ // Mux should have A driven by count Q, and B by muxy
219
+ // TODO: if A and B are swapped, CE polarity is inverted
220
+ if (sigmap (cemux->getPort (" \\ B" )) != muxy)
221
+ return 24 ;
222
+ if (sigmap (cemux->getPort (" \\ A" )) != sigmap (count_reg->getPort (" \\ Q" )))
223
+ return 24 ;
224
+ if (sigmap (cemux->getPort (" \\ Y" )) != sigmap (count_reg->getPort (" \\ D" )))
225
+ return 24 ;
226
+
227
+ // Select of the mux is our clock enable
228
+ extract.has_ce = true ;
229
+ extract.ce = sigmap (cemux->getPort (" \\ S" ));
230
+ }
231
+ else
232
+ extract.has_ce = false ;
233
+
199
234
extract.count_reg = count_reg;
200
235
if (count_reg->type == " $dff" )
201
236
extract.has_reset = false ;
202
237
else if (count_reg->type == " $adff" )
203
238
{
204
239
extract.has_reset = true ;
205
240
206
- // Verify ARST_VALUE is zero and ARST_POLARITY is 1
207
- // TODO: infer an inverter to make it 1 if necessary, so we can support negative level resets?
208
- if (count_reg->getParam (" \\ ARST_POLARITY" ).as_int () != 1 )
209
- return 22 ;
210
- if (count_reg->getParam (" \\ ARST_VALUE" ).as_int () != 0 )
241
+ // Check polarity of reset - we may have to add an inverter later on!
242
+ extract.rst_inverted = (count_reg->getParam (" \\ ARST_POLARITY" ).as_int () != 1 );
243
+
244
+ // Verify ARST_VALUE is zero or full scale
245
+ int rst_value = count_reg->getParam (" \\ ARST_VALUE" ).as_int ();
246
+ if (rst_value == 0 )
247
+ extract.rst_to_max = false ;
248
+ else if (rst_value == extract.count_value )
249
+ extract.rst_to_max = true ;
250
+ else
211
251
return 23 ;
212
252
213
253
// Save the reset
@@ -216,54 +256,59 @@ int counter_tryextract(
216
256
// TODO: support synchronous reset
217
257
else
218
258
return 15 ;
219
- if (!is_full_bus (muxy, index , count_mux, " \\ Y" , count_reg, " \\ D" ))
259
+
260
+ // Sanity check that we use the ALU output properly
261
+ if (extract.has_ce )
262
+ {
263
+ if (!is_full_bus (muxy, index , count_mux, " \\ Y" , cemux, " \\ B" ))
264
+ return 16 ;
265
+ if (!is_full_bus (cey, index , cemux, " \\ Y" , count_reg, " \\ D" ))
266
+ return 16 ;
267
+ }
268
+ else if (!is_full_bus (muxy, index , count_mux, " \\ Y" , count_reg, " \\ D" ))
220
269
return 16 ;
221
270
222
271
// TODO: Verify count_reg CLK_POLARITY is 1
223
272
224
273
// Register output must have exactly two loads, the inverter and ALU
225
274
// (unless we have a parallel output!)
275
+ // If we have a clock enable, 3 is OK
226
276
const RTLIL::SigSpec qport = count_reg->getPort (" \\ Q" );
227
277
const RTLIL::SigSpec cnout = sigmap (qport);
228
278
pool<Cell*> cnout_loads = get_other_cells (cnout, index , count_reg);
229
- if (cnout_loads.size () > 2 )
279
+ unsigned int max_loads = 2 ;
280
+ if (extract.has_ce )
281
+ max_loads = 3 ;
282
+ if (cnout_loads.size () > max_loads)
230
283
{
231
- // If we specified a limited set of cells for parallel output, check that we only drive them
232
- if (!parallel_cells.empty ())
284
+ for (auto c : cnout_loads)
233
285
{
234
- for ( auto c : cnout_loads )
235
- {
236
- if (c == underflow_inv )
237
- continue ;
238
- if (c == cell )
239
- continue ;
286
+ if (c == underflow_inv )
287
+ continue ;
288
+ if (c == cell )
289
+ continue ;
290
+ if (c == muxload )
291
+ continue ;
240
292
293
+ // If we specified a limited set of cells for parallel output, check that we only drive them
294
+ if (!parallel_cells.empty ())
295
+ {
241
296
// Make sure we're in the whitelist
242
297
if ( parallel_cells.find (c->type ) == parallel_cells.end ())
243
298
return 17 ;
299
+ }
244
300
245
- // Figure out what port(s) are driven by it
246
- // TODO: this can probably be done more efficiently w/o multiple iterations over our whole net?
247
- RTLIL::IdString portname;
248
- for (auto b : qport)
301
+ // Figure out what port(s) are driven by it
302
+ // TODO: this can probably be done more efficiently w/o multiple iterations over our whole net?
303
+ for (auto b : qport)
304
+ {
305
+ pool<ModIndex::PortInfo> ports = index .query_ports (b);
306
+ for (auto x : ports)
249
307
{
250
- pool<ModIndex::PortInfo> ports = index .query_ports (b);
251
- for (auto x : ports)
252
- {
253
- if (x.cell != c)
254
- continue ;
255
- if (portname == " " )
256
- portname = x.port ;
257
-
258
- // somehow our counter output is going to multiple ports
259
- // this makes no sense, don't allow inference
260
- else if (portname != x.port )
261
- return 17 ;
262
- }
308
+ if (x.cell != c)
309
+ continue ;
310
+ extract.pouts .insert (ModIndex::PortInfo (c, x.port , 0 ));
263
311
}
264
-
265
- // Save the other loads
266
- extract.pouts .insert (ModIndex::PortInfo (c, portname, 0 ));
267
312
}
268
313
}
269
314
}
@@ -346,7 +391,7 @@ void counter_worker(
346
391
// Do nothing, unless extraction was forced in which case give an error
347
392
if (reason != 0 )
348
393
{
349
- static const char * reasons[24 ]=
394
+ static const char * reasons[25 ]=
350
395
{
351
396
" no problem" , // 0
352
397
" counter is too large/small" , // 1
@@ -370,8 +415,9 @@ void counter_worker(
370
415
" Register output is not full bus" , // 19
371
416
" No init value found" , // 20
372
417
" Underflow value is not equal to init value" , // 21
373
- " Reset polarity is not positive" , // 22
374
- " Reset is not to zero" // 23
418
+ " RESERVED, not implemented" , // 22, kept for compatibility but not used anymore
419
+ " Reset is not to zero or COUNT_TO" , // 23
420
+ " Clock enable configuration is unsupported" // 24
375
421
};
376
422
377
423
if (force_extract)
@@ -409,7 +455,16 @@ void counter_worker(
409
455
{
410
456
// TODO: support other kinds of reset
411
457
cell->setParam (" \\ RESET_MODE" , RTLIL::Const (" LEVEL" ));
412
- cell->setPort (" \\ RST" , extract.rst );
458
+
459
+ // If the reset is active low, infer an inverter ($__COUNT_ cells always have active high reset)
460
+ if (extract.rst_inverted )
461
+ {
462
+ auto realreset = cell->module ->addWire (NEW_ID);
463
+ cell->module ->addNot (NEW_ID, extract.rst , RTLIL::SigSpec (realreset));
464
+ cell->setPort (" \\ RST" , realreset);
465
+ }
466
+ else
467
+ cell->setPort (" \\ RST" , extract.rst );
413
468
}
414
469
else
415
470
{
@@ -424,12 +479,21 @@ void counter_worker(
424
479
cell->setPort (" \\ CLK" , extract.clk );
425
480
cell->setPort (" \\ OUT" , extract.outsig );
426
481
427
- // Hook up hard-wired ports (for now CE and up/=down are not supported), default to no parallel output
482
+ // Hook up clock enable
483
+ if (extract.has_ce )
484
+ {
485
+ cell->setParam (" \\ HAS_CE" , RTLIL::Const (1 ));
486
+ cell->setPort (" \\ CE" , extract.ce );
487
+ }
488
+ else
489
+ cell->setParam (" \\ HAS_CE" , RTLIL::Const (0 ));
490
+
491
+ // Hook up hard-wired ports (for now up/down are not supported), default to no parallel output
428
492
cell->setParam (" \\ HAS_POUT" , RTLIL::Const (0 ));
429
- cell->setParam (" \\ HAS_CE " , RTLIL::Const (0 ));
493
+ cell->setParam (" \\ RESET_TO_MAX " , RTLIL::Const (0 ));
430
494
cell->setParam (" \\ DIRECTION" , RTLIL::Const (" DOWN" ));
431
495
cell->setPort (" \\ CE" , RTLIL::Const (1 ));
432
- cell->setPort (" \\ UP" , RTLIL::Const (1 ));
496
+ cell->setPort (" \\ UP" , RTLIL::Const (0 ));
433
497
434
498
// Hook up any parallel outputs
435
499
for (auto load : extract.pouts )
@@ -455,10 +519,15 @@ void counter_worker(
455
519
string reset_type = " non-resettable" ;
456
520
if (extract.has_reset )
457
521
{
522
+ if (extract.rst_inverted )
523
+ reset_type = " negative" ;
524
+ else
525
+ reset_type = " positive" ;
526
+
458
527
// TODO: support other kind of reset
459
- reset_type = " async resettable" ;
528
+ reset_type + = " async resettable" ;
460
529
}
461
- log (" Found %d-bit %s down counter %s (counting from %d) for register %s declared at %s\n " ,
530
+ log (" Found %d-bit (%s) down counter %s (counting from %d) for register %s, declared at %s\n " ,
462
531
extract.width ,
463
532
reset_type.c_str (),
464
533
countname.c_str (),
0 commit comments