mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-12 20:18:20 +00:00
greenpak4_counters: Added support for parallel output from GP_COUNTx cells
This commit is contained in:
parent
662a047815
commit
184bd148c9
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* yosys -- Yosys Open SYnthesis Suite
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016 Clifford Wolf <clifford@clifford.at>
|
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* 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)
|
||||||
|
|
||||||
struct CounterExtraction
|
struct CounterExtraction
|
||||||
{
|
{
|
||||||
int width; //counter width
|
int width; //counter width
|
||||||
RTLIL::Wire* rwire; //the register output
|
RTLIL::Wire* rwire; //the register output
|
||||||
bool has_reset; //true if we have a reset
|
bool has_reset; //true if we have a reset
|
||||||
RTLIL::SigSpec rst; //reset pin
|
RTLIL::SigSpec rst; //reset pin
|
||||||
int count_value; //value we count from
|
int count_value; //value we count from
|
||||||
RTLIL::SigSpec clk; //clock signal
|
RTLIL::SigSpec clk; //clock signal
|
||||||
RTLIL::SigSpec outsig; //counter output signal
|
RTLIL::SigSpec outsig; //counter output signal
|
||||||
RTLIL::Cell* count_mux; //counter mux
|
RTLIL::Cell* count_mux; //counter mux
|
||||||
RTLIL::Cell* count_reg; //counter register
|
RTLIL::Cell* count_reg; //counter register
|
||||||
RTLIL::Cell* underflow_inv; //inverter reduction for output-underflow detect
|
RTLIL::Cell* underflow_inv; //inverter reduction for output-underflow detect
|
||||||
|
pool<ModIndex::PortInfo> pouts; //Ports that take a parallel output from us
|
||||||
};
|
};
|
||||||
|
|
||||||
//attempt to extract a counter centered on the given cell
|
//attempt to extract a counter centered on the given adder cell
|
||||||
int greenpak4_counters_tryextract(ModIndex& index, Cell *cell, CounterExtraction& extract)
|
int greenpak4_counters_tryextract(ModIndex& index, Cell *cell, CounterExtraction& extract)
|
||||||
{
|
{
|
||||||
SigMap& sigmap = index.sigmap;
|
SigMap& sigmap = index.sigmap;
|
||||||
|
|
||||||
//GreenPak does not support counters larger than 14 bits so immediately skip anything bigger
|
//GreenPak does not support counters larger than 14 bits so immediately skip anything bigger
|
||||||
|
//TODO: infer cascaded counters?
|
||||||
int a_width = cell->getParam("\\A_WIDTH").as_int();
|
int a_width = cell->getParam("\\A_WIDTH").as_int();
|
||||||
extract.width = a_width;
|
extract.width = a_width;
|
||||||
if(a_width > 14)
|
if(a_width > 14)
|
||||||
|
@ -213,10 +215,48 @@ int greenpak4_counters_tryextract(ModIndex& index, Cell *cell, CounterExtraction
|
||||||
//TODO: Verify count_reg CLK_POLARITY is 1
|
//TODO: Verify count_reg CLK_POLARITY is 1
|
||||||
|
|
||||||
//Register output must have exactly two loads, the inverter and ALU
|
//Register output must have exactly two loads, the inverter and ALU
|
||||||
const RTLIL::SigSpec cnout = sigmap(count_reg->getPort("\\Q"));
|
//(unless we have a parallel output!)
|
||||||
|
const RTLIL::SigSpec qport = count_reg->getPort("\\Q");
|
||||||
|
const RTLIL::SigSpec cnout = sigmap(qport);
|
||||||
pool<Cell*> cnout_loads = get_other_cells(cnout, index, count_reg);
|
pool<Cell*> cnout_loads = get_other_cells(cnout, index, count_reg);
|
||||||
if(cnout_loads.size() != 2)
|
if(cnout_loads.size() > 2)
|
||||||
return 17;
|
{
|
||||||
|
//It's OK to have other loads iff they go to a DAC or DCMP (these are POUT)
|
||||||
|
for(auto c : cnout_loads)
|
||||||
|
{
|
||||||
|
if(c == underflow_inv)
|
||||||
|
continue;
|
||||||
|
if(c == cell)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//If the cell is not a DAC or DCMP, complain
|
||||||
|
if( (c->type != "\\GP_DCMP") && (c->type != "\\GP_DAC") )
|
||||||
|
return 17;
|
||||||
|
|
||||||
|
//Figure out what port(s) are driven by it
|
||||||
|
//TODO: this can probably be done more efficiently w/o multiple iterations over our whole net?
|
||||||
|
RTLIL::IdString portname;
|
||||||
|
for(auto b : qport)
|
||||||
|
{
|
||||||
|
pool<ModIndex::PortInfo> ports = index.query_ports(b);
|
||||||
|
for(auto x : ports)
|
||||||
|
{
|
||||||
|
if(x.cell != c)
|
||||||
|
continue;
|
||||||
|
if(portname == "")
|
||||||
|
portname = x.port;
|
||||||
|
|
||||||
|
//somehow our counter output is going to multiple ports
|
||||||
|
//this makes no sense, don't allow inference
|
||||||
|
else if(portname != x.port)
|
||||||
|
return 17;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Save the other loads
|
||||||
|
extract.pouts.insert(ModIndex::PortInfo(c, portname, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
if(!is_full_bus(cnout, index, count_reg, "\\Q", underflow_inv, "\\A", true))
|
if(!is_full_bus(cnout, index, count_reg, "\\Q", underflow_inv, "\\A", true))
|
||||||
return 18;
|
return 18;
|
||||||
if(!is_full_bus(cnout, index, count_reg, "\\Q", cell, "\\A", true))
|
if(!is_full_bus(cnout, index, count_reg, "\\Q", cell, "\\A", true))
|
||||||
|
@ -312,7 +352,7 @@ void greenpak4_counters_worker(
|
||||||
"Mux output is used outside counter", //14
|
"Mux output is used outside counter", //14
|
||||||
"Counter reg is not DFF/ADFF", //15
|
"Counter reg is not DFF/ADFF", //15
|
||||||
"Counter input is not full bus", //16
|
"Counter input is not full bus", //16
|
||||||
"Count register is used outside counter", //17
|
"Count register is used outside counter, but not by a DCMP or DAC", //17
|
||||||
"Register output is not full bus", //18
|
"Register output is not full bus", //18
|
||||||
"Register output is not full bus", //19
|
"Register output is not full bus", //19
|
||||||
"No init value found", //20
|
"No init value found", //20
|
||||||
|
@ -344,7 +384,7 @@ void greenpak4_counters_worker(
|
||||||
//TODO: support other kind of reset
|
//TODO: support other kind of reset
|
||||||
reset_type = "async resettable";
|
reset_type = "async resettable";
|
||||||
}
|
}
|
||||||
log(" Found %d-bit %s down counter (from %d) for register %s declared at %s\n",
|
log(" Found %d-bit %s down counter (counting from %d) for register %s declared at %s\n",
|
||||||
extract.width,
|
extract.width,
|
||||||
reset_type.c_str(),
|
reset_type.c_str(),
|
||||||
extract.count_value,
|
extract.count_value,
|
||||||
|
@ -388,6 +428,19 @@ void greenpak4_counters_worker(
|
||||||
cell->setPort("\\CLK", extract.clk);
|
cell->setPort("\\CLK", extract.clk);
|
||||||
cell->setPort("\\OUT", extract.outsig);
|
cell->setPort("\\OUT", extract.outsig);
|
||||||
|
|
||||||
|
//Hook up any parallel outputs
|
||||||
|
for(auto load : extract.pouts)
|
||||||
|
{
|
||||||
|
log(" Counter has parallel output to cell %s port %s\n", log_id(load.cell->name), log_id(load.port));
|
||||||
|
|
||||||
|
//Find the wire hooked to the old port
|
||||||
|
auto sig = load.cell->getPort(load.port);
|
||||||
|
|
||||||
|
//Connect it to our parallel output
|
||||||
|
//(this is OK to do more than once b/c they all go to the same place)
|
||||||
|
cell->setPort("\\POUT", sig);
|
||||||
|
}
|
||||||
|
|
||||||
//Delete the cells we've replaced (let opt_clean handle deleting the now-redundant wires)
|
//Delete the cells we've replaced (let opt_clean handle deleting the now-redundant wires)
|
||||||
cells_to_remove.insert(extract.count_mux);
|
cells_to_remove.insert(extract.count_mux);
|
||||||
cells_to_remove.insert(extract.count_reg);
|
cells_to_remove.insert(extract.count_reg);
|
||||||
|
|
Loading…
Reference in a new issue