Skip to content

Commit 184bd14

Browse files
committedMay 23, 2017
greenpak4_counters: Added support for parallel output from GP_COUNTx cells
1 parent 662a047 commit 184bd14

File tree

1 file changed

+70
-17
lines changed

1 file changed

+70
-17
lines changed
 

‎techlibs/greenpak4/greenpak4_counters.cc

+70-17
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* yosys -- Yosys Open SYnthesis Suite
33
*
4-
* Copyright (C) 2016 Clifford Wolf <clifford@clifford.at>
4+
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
55
*
66
* Permission to use, copy, modify, and/or distribute this software for any
77
* 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)
8989

9090
struct CounterExtraction
9191
{
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
102103
};
103104

104-
//attempt to extract a counter centered on the given cell
105+
//attempt to extract a counter centered on the given adder cell
105106
int greenpak4_counters_tryextract(ModIndex& index, Cell *cell, CounterExtraction& extract)
106107
{
107108
SigMap& sigmap = index.sigmap;
108109

109110
//GreenPak does not support counters larger than 14 bits so immediately skip anything bigger
111+
//TODO: infer cascaded counters?
110112
int a_width = cell->getParam("\\A_WIDTH").as_int();
111113
extract.width = a_width;
112114
if(a_width > 14)
@@ -213,10 +215,48 @@ int greenpak4_counters_tryextract(ModIndex& index, Cell *cell, CounterExtraction
213215
//TODO: Verify count_reg CLK_POLARITY is 1
214216

215217
//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);
217221
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+
}
220260
if(!is_full_bus(cnout, index, count_reg, "\\Q", underflow_inv, "\\A", true))
221261
return 18;
222262
if(!is_full_bus(cnout, index, count_reg, "\\Q", cell, "\\A", true))
@@ -312,7 +352,7 @@ void greenpak4_counters_worker(
312352
"Mux output is used outside counter", //14
313353
"Counter reg is not DFF/ADFF", //15
314354
"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
316356
"Register output is not full bus", //18
317357
"Register output is not full bus", //19
318358
"No init value found", //20
@@ -344,7 +384,7 @@ void greenpak4_counters_worker(
344384
//TODO: support other kind of reset
345385
reset_type = "async resettable";
346386
}
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",
348388
extract.width,
349389
reset_type.c_str(),
350390
extract.count_value,
@@ -388,6 +428,19 @@ void greenpak4_counters_worker(
388428
cell->setPort("\\CLK", extract.clk);
389429
cell->setPort("\\OUT", extract.outsig);
390430

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+
391444
//Delete the cells we've replaced (let opt_clean handle deleting the now-redundant wires)
392445
cells_to_remove.insert(extract.count_mux);
393446
cells_to_remove.insert(extract.count_reg);

0 commit comments

Comments
 (0)
Please sign in to comment.