|
1 | 1 | /*
|
2 | 2 | * yosys -- Yosys Open SYnthesis Suite
|
3 | 3 | *
|
4 |
| - * Copyright (C) 2016 Clifford Wolf <clifford@clifford.at> |
| 4 | + * Copyright (C) 2017 Clifford Wolf <clifford@clifford.at> |
5 | 5 | *
|
6 | 6 | * Permission to use, copy, modify, and/or distribute this software for any
|
7 | 7 | * purpose with or without fee is hereby granted, provided that the above
|
@@ -89,24 +89,26 @@ bool is_unconnected(const RTLIL::SigSpec& port, ModIndex& index)
|
89 | 89 |
|
90 | 90 | struct CounterExtraction
|
91 | 91 | {
|
92 |
| - int width; //counter width |
93 |
| - RTLIL::Wire* rwire; //the register output |
94 |
| - bool has_reset; //true if we have a reset |
95 |
| - RTLIL::SigSpec rst; //reset pin |
96 |
| - int count_value; //value we count from |
97 |
| - RTLIL::SigSpec clk; //clock signal |
98 |
| - RTLIL::SigSpec outsig; //counter output signal |
99 |
| - RTLIL::Cell* count_mux; //counter mux |
100 |
| - RTLIL::Cell* count_reg; //counter register |
101 |
| - RTLIL::Cell* underflow_inv; //inverter reduction for output-underflow detect |
| 92 | + int width; //counter width |
| 93 | + RTLIL::Wire* rwire; //the register output |
| 94 | + bool has_reset; //true if we have a reset |
| 95 | + RTLIL::SigSpec rst; //reset pin |
| 96 | + int count_value; //value we count from |
| 97 | + RTLIL::SigSpec clk; //clock signal |
| 98 | + RTLIL::SigSpec outsig; //counter output signal |
| 99 | + RTLIL::Cell* count_mux; //counter mux |
| 100 | + RTLIL::Cell* count_reg; //counter register |
| 101 | + RTLIL::Cell* underflow_inv; //inverter reduction for output-underflow detect |
| 102 | + pool<ModIndex::PortInfo> pouts; //Ports that take a parallel output from us |
102 | 103 | };
|
103 | 104 |
|
104 |
| -//attempt to extract a counter centered on the given cell |
| 105 | +//attempt to extract a counter centered on the given adder cell |
105 | 106 | int greenpak4_counters_tryextract(ModIndex& index, Cell *cell, CounterExtraction& extract)
|
106 | 107 | {
|
107 | 108 | SigMap& sigmap = index.sigmap;
|
108 | 109 |
|
109 | 110 | //GreenPak does not support counters larger than 14 bits so immediately skip anything bigger
|
| 111 | + //TODO: infer cascaded counters? |
110 | 112 | int a_width = cell->getParam("\\A_WIDTH").as_int();
|
111 | 113 | extract.width = a_width;
|
112 | 114 | if(a_width > 14)
|
@@ -213,10 +215,48 @@ int greenpak4_counters_tryextract(ModIndex& index, Cell *cell, CounterExtraction
|
213 | 215 | //TODO: Verify count_reg CLK_POLARITY is 1
|
214 | 216 |
|
215 | 217 | //Register output must have exactly two loads, the inverter and ALU
|
216 |
| - const RTLIL::SigSpec cnout = sigmap(count_reg->getPort("\\Q")); |
| 218 | + //(unless we have a parallel output!) |
| 219 | + const RTLIL::SigSpec qport = count_reg->getPort("\\Q"); |
| 220 | + const RTLIL::SigSpec cnout = sigmap(qport); |
217 | 221 | pool<Cell*> cnout_loads = get_other_cells(cnout, index, count_reg);
|
218 |
| - if(cnout_loads.size() != 2) |
219 |
| - return 17; |
| 222 | + if(cnout_loads.size() > 2) |
| 223 | + { |
| 224 | + //It's OK to have other loads iff they go to a DAC or DCMP (these are POUT) |
| 225 | + for(auto c : cnout_loads) |
| 226 | + { |
| 227 | + if(c == underflow_inv) |
| 228 | + continue; |
| 229 | + if(c == cell) |
| 230 | + continue; |
| 231 | + |
| 232 | + //If the cell is not a DAC or DCMP, complain |
| 233 | + if( (c->type != "\\GP_DCMP") && (c->type != "\\GP_DAC") ) |
| 234 | + return 17; |
| 235 | + |
| 236 | + //Figure out what port(s) are driven by it |
| 237 | + //TODO: this can probably be done more efficiently w/o multiple iterations over our whole net? |
| 238 | + RTLIL::IdString portname; |
| 239 | + for(auto b : qport) |
| 240 | + { |
| 241 | + pool<ModIndex::PortInfo> ports = index.query_ports(b); |
| 242 | + for(auto x : ports) |
| 243 | + { |
| 244 | + if(x.cell != c) |
| 245 | + continue; |
| 246 | + if(portname == "") |
| 247 | + portname = x.port; |
| 248 | + |
| 249 | + //somehow our counter output is going to multiple ports |
| 250 | + //this makes no sense, don't allow inference |
| 251 | + else if(portname != x.port) |
| 252 | + return 17; |
| 253 | + } |
| 254 | + } |
| 255 | + |
| 256 | + //Save the other loads |
| 257 | + extract.pouts.insert(ModIndex::PortInfo(c, portname, 0)); |
| 258 | + } |
| 259 | + } |
220 | 260 | if(!is_full_bus(cnout, index, count_reg, "\\Q", underflow_inv, "\\A", true))
|
221 | 261 | return 18;
|
222 | 262 | if(!is_full_bus(cnout, index, count_reg, "\\Q", cell, "\\A", true))
|
@@ -312,7 +352,7 @@ void greenpak4_counters_worker(
|
312 | 352 | "Mux output is used outside counter", //14
|
313 | 353 | "Counter reg is not DFF/ADFF", //15
|
314 | 354 | "Counter input is not full bus", //16
|
315 |
| - "Count register is used outside counter", //17 |
| 355 | + "Count register is used outside counter, but not by a DCMP or DAC", //17 |
316 | 356 | "Register output is not full bus", //18
|
317 | 357 | "Register output is not full bus", //19
|
318 | 358 | "No init value found", //20
|
@@ -344,7 +384,7 @@ void greenpak4_counters_worker(
|
344 | 384 | //TODO: support other kind of reset
|
345 | 385 | reset_type = "async resettable";
|
346 | 386 | }
|
347 |
| - log(" Found %d-bit %s down counter (from %d) for register %s declared at %s\n", |
| 387 | + log(" Found %d-bit %s down counter (counting from %d) for register %s declared at %s\n", |
348 | 388 | extract.width,
|
349 | 389 | reset_type.c_str(),
|
350 | 390 | extract.count_value,
|
@@ -388,6 +428,19 @@ void greenpak4_counters_worker(
|
388 | 428 | cell->setPort("\\CLK", extract.clk);
|
389 | 429 | cell->setPort("\\OUT", extract.outsig);
|
390 | 430 |
|
| 431 | + //Hook up any parallel outputs |
| 432 | + for(auto load : extract.pouts) |
| 433 | + { |
| 434 | + log(" Counter has parallel output to cell %s port %s\n", log_id(load.cell->name), log_id(load.port)); |
| 435 | + |
| 436 | + //Find the wire hooked to the old port |
| 437 | + auto sig = load.cell->getPort(load.port); |
| 438 | + |
| 439 | + //Connect it to our parallel output |
| 440 | + //(this is OK to do more than once b/c they all go to the same place) |
| 441 | + cell->setPort("\\POUT", sig); |
| 442 | + } |
| 443 | + |
391 | 444 | //Delete the cells we've replaced (let opt_clean handle deleting the now-redundant wires)
|
392 | 445 | cells_to_remove.insert(extract.count_mux);
|
393 | 446 | cells_to_remove.insert(extract.count_reg);
|
|
0 commit comments