mirror of https://github.com/YosysHQ/yosys.git
quicklogic: ql_dsp_simd add dspv2 support, fix dspv1
This commit is contained in:
parent
434334ba63
commit
a8c10eea03
|
@ -29,7 +29,7 @@ PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
struct QlDspSimdPass : public Pass {
|
struct QlDspSimdPass : public Pass {
|
||||||
|
|
||||||
QlDspSimdPass() : Pass("ql_dsp_simd", "merge QuickLogic K6N10f DSP pairs to operate in SIMD mode") {}
|
QlDspSimdPass() : Pass("ql_dsp_simd", "merge QuickLogic K6N10f DSP pairs to operate in fractured mode") {}
|
||||||
|
|
||||||
void help() override
|
void help() override
|
||||||
{
|
{
|
||||||
|
@ -37,16 +37,17 @@ struct QlDspSimdPass : public Pass {
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" ql_dsp_simd [selection]\n");
|
log(" ql_dsp_simd [selection]\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("This pass identifies K6N10f DSP cells with identical configuration and pack pairs\n");
|
log("This pass identifies K6N10f DSP cells with identical configuration and merges\n");
|
||||||
log("of them together into other DSP cells that can perform SIMD operation.\n");
|
log("pairs of them, enabling fractured mode.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ..........................................
|
// ..........................................
|
||||||
|
|
||||||
/// Describes DSP config unique to a whole DSP cell
|
/// Describes DSP config unique to a DSP cell
|
||||||
struct DspConfig {
|
struct DspConfig {
|
||||||
// Port connections
|
// Port connections
|
||||||
dict<RTLIL::IdString, RTLIL::SigSpec> connections;
|
dict<RTLIL::IdString, RTLIL::SigSpec> connections;
|
||||||
|
dict<RTLIL::IdString, RTLIL::Const> parameters;
|
||||||
|
|
||||||
DspConfig() = default;
|
DspConfig() = default;
|
||||||
|
|
||||||
|
@ -55,60 +56,149 @@ struct QlDspSimdPass : public Pass {
|
||||||
|
|
||||||
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(connections); return h; }
|
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(connections); return h; }
|
||||||
|
|
||||||
bool operator==(const DspConfig &ref) const { return connections == ref.connections; }
|
bool operator==(const DspConfig &ref) const { return connections == ref.connections && parameters == ref.parameters; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// ..........................................
|
// ..........................................
|
||||||
|
|
||||||
const int m_ModeBitsSize = 80;
|
const int m_Dspv1ModeBitsSize = 80;
|
||||||
|
const int m_Dspv2ModeBitsSize = 68;
|
||||||
// DSP parameters
|
|
||||||
const std::vector<std::string> m_DspParams = {"COEFF_3", "COEFF_2", "COEFF_1", "COEFF_0"};
|
|
||||||
|
|
||||||
/// Temporary SigBit to SigBit helper map.
|
/// Temporary SigBit to SigBit helper map.
|
||||||
SigMap sigmap;
|
SigMap sigmap;
|
||||||
|
|
||||||
|
static bool is_cascade(const Cell* cell)
|
||||||
|
{
|
||||||
|
std::array cascade_ports {
|
||||||
|
ID(a_cout_o),
|
||||||
|
ID(b_cout_o),
|
||||||
|
ID(z_cout_o),
|
||||||
|
ID(a_cin_i),
|
||||||
|
ID(b_cin_i),
|
||||||
|
ID(z_cin_i)
|
||||||
|
};
|
||||||
|
for (auto p : cascade_ports) {
|
||||||
|
if (cell->hasPort(p) && !cell->getPort(p).is_fully_undef())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// ..........................................
|
// ..........................................
|
||||||
|
|
||||||
void execute(std::vector<std::string> a_Args, RTLIL::Design *a_Design) override
|
void execute(std::vector<std::string> a_Args, RTLIL::Design *a_Design) override
|
||||||
{
|
{
|
||||||
log_header(a_Design, "Executing QL_DSP_SIMD pass.\n");
|
log_header(a_Design, "Executing QL_DSP_SIMD pass.\n");
|
||||||
|
|
||||||
// DSP control and config ports to consider and how to map them to ports
|
// The following lists have to match simulation model interfaces.
|
||||||
// of the target DSP cell
|
|
||||||
static const std::vector<std::pair<IdString, IdString>> m_DspCfgPorts = {
|
// DSP control and config ports that must be equal between
|
||||||
std::make_pair(ID(clock_i), ID(clk)),
|
// merged half-blocks
|
||||||
std::make_pair(ID(reset_i), ID(reset)),
|
// In addition to functional differences,
|
||||||
std::make_pair(ID(feedback_i), ID(feedback)),
|
// v1 and v2 have different balance between shared functionality
|
||||||
std::make_pair(ID(load_acc_i), ID(load_acc)),
|
// in ports vs params.
|
||||||
std::make_pair(ID(unsigned_a_i), ID(unsigned_a)),
|
static const std::vector<IdString> m_Dspv1CfgPorts = {
|
||||||
std::make_pair(ID(unsigned_b_i), ID(unsigned_b)),
|
ID(acc_fir_i),
|
||||||
std::make_pair(ID(subtract_i), ID(subtract)),
|
ID(feedback_i),
|
||||||
std::make_pair(ID(output_select_i), ID(output_select)),
|
ID(load_acc_i),
|
||||||
std::make_pair(ID(saturate_enable_i), ID(saturate_enable)),
|
ID(unsigned_a_i),
|
||||||
std::make_pair(ID(shift_right_i), ID(shift_right)),
|
ID(unsigned_b_i),
|
||||||
std::make_pair(ID(round_i), ID(round)),
|
ID(clock_i),
|
||||||
std::make_pair(ID(register_inputs_i), ID(register_inputs))
|
ID(s_reset),
|
||||||
|
ID(saturate_enable_i),
|
||||||
|
ID(output_select_i),
|
||||||
|
ID(round_i),
|
||||||
|
ID(shift_right_i),
|
||||||
|
ID(subtract_i),
|
||||||
|
ID(register_inputs_i),
|
||||||
|
ID(coeff_0_i),
|
||||||
|
ID(coeff_1_i),
|
||||||
|
ID(coeff_2_i),
|
||||||
|
ID(coeff_3_i),
|
||||||
|
};
|
||||||
|
static const std::vector<IdString> m_Dspv1CfgParams = {};
|
||||||
|
static const std::vector<IdString> m_Dspv2CfgPorts = {
|
||||||
|
ID(clock_i),
|
||||||
|
ID(reset_i),
|
||||||
|
ID(acc_reset_i),
|
||||||
|
ID(feedback_i),
|
||||||
|
ID(load_acc_i),
|
||||||
|
ID(output_select_i),
|
||||||
|
};
|
||||||
|
static const std::vector<IdString> m_Dspv2CfgParams = {
|
||||||
|
ID(COEFF_0),
|
||||||
|
ID(ACC_FIR),
|
||||||
|
ID(ROUND),
|
||||||
|
ID(ZC_SHIFT),
|
||||||
|
ID(ZREG_SHIFT),
|
||||||
|
ID(SHIFT_REG),
|
||||||
|
ID(SATURATE),
|
||||||
|
ID(SUBTRACT),
|
||||||
|
ID(PRE_ADD),
|
||||||
|
ID(A_SEL),
|
||||||
|
ID(A_REG),
|
||||||
|
ID(B_SEL),
|
||||||
|
ID(B_REG),
|
||||||
|
ID(C_REG),
|
||||||
|
ID(BC_REG),
|
||||||
|
ID(M_REG),
|
||||||
|
ID(FRAC_MODE),
|
||||||
};
|
};
|
||||||
|
|
||||||
// DSP data ports and how to map them to ports of the target DSP cell
|
|
||||||
static const std::vector<std::pair<IdString, IdString>> m_DspDataPorts = {
|
// Data ports to be concatenated into merged cell
|
||||||
std::make_pair(ID(a_i), ID(a)),
|
static const std::vector<IdString> m_Dspv1DataPorts = {
|
||||||
std::make_pair(ID(b_i), ID(b)),
|
ID(a_i),
|
||||||
std::make_pair(ID(acc_fir_i), ID(acc_fir)),
|
ID(b_i),
|
||||||
std::make_pair(ID(z_o), ID(z)),
|
ID(z_o),
|
||||||
std::make_pair(ID(dly_b_o), ID(dly_b))
|
ID(dly_b_o),
|
||||||
};
|
};
|
||||||
|
static const std::vector<IdString> m_Dspv2DataPorts = {
|
||||||
|
ID(a_i),
|
||||||
|
ID(b_i),
|
||||||
|
ID(c_i),
|
||||||
|
ID(z_o),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Params to serialize into MODE_BITS param
|
||||||
|
static const std::vector<IdString> m_Dspv1ModeBitParams = {
|
||||||
|
ID(COEFF_3),
|
||||||
|
ID(COEFF_2),
|
||||||
|
ID(COEFF_1),
|
||||||
|
ID(COEFF_0),
|
||||||
|
};
|
||||||
|
static const std::vector<IdString> m_Dspv2ModeBitParams = {};
|
||||||
|
|
||||||
// Source DSP cell type (SISD)
|
// Source DSP cell type (half-block)
|
||||||
static const IdString m_SisdDspType = ID(dsp_t1_10x9x32);
|
static const IdString m_Dspv1SisdType = ID(dsp_t1_10x9x32_cfg_ports);
|
||||||
|
static const IdString m_Dspv2SisdType = ID(dspv2_16x9x32_cfg_ports);
|
||||||
|
|
||||||
// Target DSP cell types for the SIMD mode
|
// Target DSP cell types (full-block)
|
||||||
static const IdString m_SimdDspType = ID(QL_DSP2);
|
static const IdString m_Dspv1SimdType = ID(dsp_t1_20x18x64_cfg_ports);
|
||||||
|
static const IdString m_Dspv2SimdType = ID(dspv2_32x18x64_cfg_ports);
|
||||||
|
|
||||||
// Parse args
|
// Parse args
|
||||||
extra_args(a_Args, 1, a_Design);
|
int dsp_version = 1;
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 1; argidx < a_Args.size(); argidx++) {
|
||||||
|
if (a_Args[argidx] == "-dspv2") {
|
||||||
|
dsp_version = 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extra_args(a_Args, argidx, a_Design);
|
||||||
|
|
||||||
|
log_assert(dsp_version < 3);
|
||||||
|
log_assert(dsp_version > 0);
|
||||||
|
const auto& cfg_ports = (dsp_version == 1) ? m_Dspv1CfgPorts : m_Dspv2CfgPorts;
|
||||||
|
const auto& cfg_params = (dsp_version == 1) ? m_Dspv1CfgParams : m_Dspv2CfgParams;
|
||||||
|
const auto& data_ports = (dsp_version == 1) ? m_Dspv1DataPorts : m_Dspv2DataPorts;
|
||||||
|
auto half_dsp = (dsp_version == 1) ? m_Dspv1SisdType : m_Dspv2SisdType;
|
||||||
|
auto full_dsp = (dsp_version == 1) ? m_Dspv1SimdType : m_Dspv2SimdType;
|
||||||
|
auto mode_bit_params = (dsp_version == 1) ? m_Dspv1ModeBitParams : m_Dspv2ModeBitParams;
|
||||||
|
auto mode_bits_size = (dsp_version == 1) ? m_Dspv1ModeBitsSize : m_Dspv2ModeBitsSize;
|
||||||
|
|
||||||
|
int cellsMerged = 0;
|
||||||
// Process modules
|
// Process modules
|
||||||
for (auto module : a_Design->selected_modules()) {
|
for (auto module : a_Design->selected_modules()) {
|
||||||
// Setup the SigMap
|
// Setup the SigMap
|
||||||
|
@ -118,25 +208,33 @@ struct QlDspSimdPass : public Pass {
|
||||||
dict<DspConfig, std::vector<RTLIL::Cell *>> groups;
|
dict<DspConfig, std::vector<RTLIL::Cell *>> groups;
|
||||||
for (auto cell : module->selected_cells()) {
|
for (auto cell : module->selected_cells()) {
|
||||||
// Check if this is a DSP cell we are looking for (type starts with m_SisdDspType)
|
// Check if this is a DSP cell we are looking for (type starts with m_SisdDspType)
|
||||||
if (cell->type != m_SisdDspType)
|
if (cell->type != half_dsp)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Skip if it has the (* keep *) attribute set
|
// Skip if it has the (* keep *) attribute set
|
||||||
if (cell->has_keep_attr())
|
if (cell->has_keep_attr()) {
|
||||||
|
log_debug("skip %s because it's marked keep\n", log_id(cell));
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if it has cascading
|
||||||
|
if (is_cascade(cell)) {
|
||||||
|
log_debug("skip %s because it's cascading\n", log_id(cell));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Add to a group
|
// Add to a group
|
||||||
const auto key = getDspConfig(cell, m_DspCfgPorts);
|
const auto key = getDspConfig(cell, cfg_ports, cfg_params);
|
||||||
groups[key].push_back(cell);
|
groups[key].push_back(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_debug("Checking %zu detected mode-equivalent DSP cell classes\n", groups.size());
|
||||||
std::vector<Cell *> cellsToRemove;
|
std::vector<Cell *> cellsToRemove;
|
||||||
|
|
||||||
// Map cell pairs to the target DSP SIMD cell
|
// Map cell pairs to the target DSP SIMD cell
|
||||||
for (const auto &it : groups) {
|
for (const auto &it : groups) {
|
||||||
const auto &group = it.second;
|
const auto &group = it.second;
|
||||||
const auto &config = it.first;
|
const auto &config = it.first;
|
||||||
|
log_debug("Checking %zu half-blocks\n", group.size());
|
||||||
// Ensure an even number
|
// Ensure an even number
|
||||||
size_t count = group.size();
|
size_t count = group.size();
|
||||||
if (count & 1)
|
if (count & 1)
|
||||||
|
@ -148,7 +246,7 @@ struct QlDspSimdPass : public Pass {
|
||||||
Cell *dsp_b = group[i + 1];
|
Cell *dsp_b = group[i + 1];
|
||||||
|
|
||||||
// Create the new cell
|
// Create the new cell
|
||||||
Cell *simd = module->addCell(NEW_ID, m_SimdDspType);
|
Cell *simd = module->addCell(NEW_ID, full_dsp);
|
||||||
|
|
||||||
log(" SIMD: %s (%s) + %s (%s) => %s (%s)\n", log_id(dsp_a), log_id(dsp_a->type),
|
log(" SIMD: %s (%s) + %s (%s) => %s (%s)\n", log_id(dsp_a), log_id(dsp_a->type),
|
||||||
log_id(dsp_b), log_id(dsp_b->type), log_id(simd), log_id(simd->type));
|
log_id(dsp_b), log_id(dsp_b->type), log_id(simd), log_id(simd->type));
|
||||||
|
@ -157,26 +255,35 @@ struct QlDspSimdPass : public Pass {
|
||||||
// its port widths)
|
// its port widths)
|
||||||
if (!simd->known())
|
if (!simd->known())
|
||||||
log_error(" The target cell type '%s' is not known!", log_id(simd));
|
log_error(" The target cell type '%s' is not known!", log_id(simd));
|
||||||
|
|
||||||
// Connect common ports
|
// Connect common ports
|
||||||
for (const auto &it : m_DspCfgPorts)
|
|
||||||
simd->setPort(it.first, config.connections.at(it.second));
|
for (auto port : cfg_ports) {
|
||||||
|
if (config.connections.count(port))
|
||||||
|
simd->setPort(port, config.connections.at(port));
|
||||||
|
}
|
||||||
|
for (auto param : cfg_params) {
|
||||||
|
if (config.parameters.count(param))
|
||||||
|
simd->setParam(param, config.parameters.at(param));
|
||||||
|
}
|
||||||
|
|
||||||
// Connect data ports
|
// Connect data ports
|
||||||
for (const auto &it : m_DspDataPorts) {
|
for (auto port : data_ports) {
|
||||||
size_t width;
|
size_t width;
|
||||||
bool isOutput;
|
bool isOutput;
|
||||||
|
|
||||||
std::tie(width, isOutput) = getPortInfo(simd, it.second);
|
std::tie(width, isOutput) = getPortInfo(simd, port);
|
||||||
|
if (!width)
|
||||||
|
log_error("Can't determine portinfo for %s\n", log_id(port));
|
||||||
|
|
||||||
auto getConnection = [&](const RTLIL::Cell *cell) {
|
auto getConnection = [&](const RTLIL::Cell *cell) {
|
||||||
RTLIL::SigSpec sigspec;
|
RTLIL::SigSpec sigspec;
|
||||||
if (cell->hasPort(it.first)) {
|
if (cell->hasPort(port)) {
|
||||||
const auto &sig = cell->getPort(it.first);
|
const auto &sig = cell->getPort(port);
|
||||||
sigspec.append(sig);
|
sigspec.append(sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
int padding = width / 2 - sigspec.size();
|
int padding = width / 2 - sigspec.size();
|
||||||
|
log_assert(padding >= 0);
|
||||||
|
|
||||||
if (padding) {
|
if (padding) {
|
||||||
if (!isOutput)
|
if (!isOutput)
|
||||||
|
@ -190,27 +297,32 @@ struct QlDspSimdPass : public Pass {
|
||||||
RTLIL::SigSpec sigspec;
|
RTLIL::SigSpec sigspec;
|
||||||
sigspec.append(getConnection(dsp_a));
|
sigspec.append(getConnection(dsp_a));
|
||||||
sigspec.append(getConnection(dsp_b));
|
sigspec.append(getConnection(dsp_b));
|
||||||
simd->setPort(it.second, sigspec);
|
simd->setPort(port, sigspec);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Concatenate FIR coefficient parameters into the single
|
if (mode_bit_params.size()) {
|
||||||
// MODE_BITS parameter
|
// Concatenate FIR coefficient parameters into the single
|
||||||
Const mode_bits;
|
// MODE_BITS parameter
|
||||||
for (const auto &it : m_DspParams) {
|
Const mode_bits;
|
||||||
auto val_a = dsp_a->getParam(it);
|
for (const auto &it : mode_bit_params) {
|
||||||
auto val_b = dsp_b->getParam(it);
|
auto val_a = dsp_a->getParam(it);
|
||||||
|
auto val_b = dsp_b->getParam(it);
|
||||||
mode_bits.bits().insert(mode_bits.bits().end(),
|
|
||||||
val_a.begin(), val_a.end());
|
mode_bits.bits().insert(mode_bits.bits().end(),
|
||||||
mode_bits.bits().insert(mode_bits.bits().end(),
|
val_a.begin(), val_a.end());
|
||||||
val_b.begin(), val_b.end());
|
mode_bits.bits().insert(mode_bits.bits().end(),
|
||||||
|
val_b.begin(), val_b.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
simd->setParam(ID(MODE_BITS), mode_bits);
|
||||||
|
log_assert(mode_bits.size() == mode_bits_size);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// Enable the fractured mode
|
||||||
// Enable the fractured mode by connecting the control
|
if (dsp_version == 1)
|
||||||
// port.
|
simd->setPort(ID(f_mode), State::S1);
|
||||||
simd->setPort(ID(f_mode), State::S1);
|
else
|
||||||
simd->setParam(ID(MODE_BITS), mode_bits);
|
simd->setParam(ID(FRAC_MODE), State::S1);
|
||||||
log_assert(mode_bits.size() == m_ModeBitsSize);
|
|
||||||
|
|
||||||
// Handle the "is_inferred" attribute. If one of the fragments
|
// Handle the "is_inferred" attribute. If one of the fragments
|
||||||
// is not inferred mark the whole DSP as not inferred
|
// is not inferred mark the whole DSP as not inferred
|
||||||
|
@ -223,11 +335,12 @@ struct QlDspSimdPass : public Pass {
|
||||||
cellsToRemove.push_back(dsp_b);
|
cellsToRemove.push_back(dsp_b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cellsMerged += cellsToRemove.size();
|
||||||
// Remove old cells
|
// Remove old cells
|
||||||
for (auto cell : cellsToRemove)
|
for (auto cell : cellsToRemove)
|
||||||
module->remove(cell);
|
module->remove(cell);
|
||||||
}
|
}
|
||||||
|
log("Merged %d half-block cells\n", cellsMerged);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ..........................................
|
// ..........................................
|
||||||
|
@ -257,19 +370,24 @@ struct QlDspSimdPass : public Pass {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a DSP cell populates and returns a DspConfig struct for it.
|
/// Given a DSP cell populates and returns a DspConfig struct for it.
|
||||||
DspConfig getDspConfig(RTLIL::Cell *a_Cell, const std::vector<std::pair<IdString, IdString>> &dspCfgPorts)
|
DspConfig getDspConfig(RTLIL::Cell *a_Cell, const std::vector<IdString> &dspCfgPorts, const std::vector<IdString> &dspCfgParams)
|
||||||
{
|
{
|
||||||
DspConfig config;
|
DspConfig config;
|
||||||
|
|
||||||
for (const auto &it : dspCfgPorts) {
|
for (auto port : dspCfgPorts) {
|
||||||
auto port = it.first;
|
|
||||||
|
|
||||||
// Port unconnected
|
// Port unconnected
|
||||||
if (!a_Cell->hasPort(port))
|
if (!a_Cell->hasPort(port))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
config.connections[port] = sigmap(a_Cell->getPort(port));
|
config.connections[port] = sigmap(a_Cell->getPort(port));
|
||||||
}
|
}
|
||||||
|
for (auto param : dspCfgParams) {
|
||||||
|
// Param unset?
|
||||||
|
if (!a_Cell->hasParam(param))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
config.parameters[param] = a_Cell->getParam(param);
|
||||||
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
read_verilog <<EOT
|
||||||
|
module foo(
|
||||||
|
input [7:0] A,
|
||||||
|
input [7:0] B,
|
||||||
|
input [7:0] C,
|
||||||
|
input [7:0] D,
|
||||||
|
output reg [7:0] X,
|
||||||
|
output reg [7:0] Y);
|
||||||
|
assign X = A * B;
|
||||||
|
assign Y = C * D;
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
synth_quicklogic -dspv2 -run :map_dsp
|
||||||
|
|
||||||
|
# this is just taken from map_dsp step
|
||||||
|
wreduce t:$mul
|
||||||
|
ql_dsp_macc -dspv2
|
||||||
|
techmap -map +/mul2dsp.v -map +/quicklogic/qlf_k6n10f/dspv2_map.v -D USE_DSP_CFG_PARAMS=0 -D DSP_SIGNEDONLY -D DSP_A_MAXWIDTH=32 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=10 -D DSP_B_MINWIDTH=10 -D DSP_NAME=$__MUL32X18
|
||||||
|
chtype -set $mul t:$__soft_mul
|
||||||
|
techmap -map +/mul2dsp.v -map +/quicklogic/qlf_k6n10f/dspv2_map.v -D USE_DSP_CFG_PARAMS=0 -D DSP_SIGNEDONLY -D DSP_A_MAXWIDTH=16 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=$__MUL16X9
|
||||||
|
# TODO is this missing from synth_quicklogic?
|
||||||
|
read_verilog -lib +/quicklogic/qlf_k6n10f/dspv2_sim.v
|
||||||
|
select -assert-count 2 t:dspv2_16x9x32_cfg_ports
|
||||||
|
select -assert-count 0 t:dspv2_32x18x64_cfg_ports
|
||||||
|
equiv_opt -assert -async2sync -map +/quicklogic/qlf_k6n10f/dspv2_sim.v ql_dsp_simd -dspv2
|
||||||
|
design -load postopt
|
||||||
|
select -assert-count 0 t:dspv2_16x9x32_cfg_ports
|
||||||
|
select -assert-count 1 t:dspv2_32x18x64_cfg_ports
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
|
||||||
|
read_verilog <<EOT
|
||||||
|
module foo(
|
||||||
|
input [7:0] A,
|
||||||
|
input [7:0] B,
|
||||||
|
input [7:0] C,
|
||||||
|
input [7:0] D,
|
||||||
|
input [7:0] E,
|
||||||
|
output reg [7:0] X,
|
||||||
|
output reg [7:0] Y);
|
||||||
|
assign X = A * B;
|
||||||
|
assign Y = C * (D + E); // <-- look here
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
synth_quicklogic -dspv2 -run :map_dsp
|
||||||
|
|
||||||
|
wreduce t:$mul
|
||||||
|
ql_dsp_macc -dspv2
|
||||||
|
techmap -map +/mul2dsp.v -map +/quicklogic/qlf_k6n10f/dspv2_map.v -D USE_DSP_CFG_PARAMS=0 -D DSP_SIGNEDONLY -D DSP_A_MAXWIDTH=32 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=10 -D DSP_B_MINWIDTH=10 -D DSP_NAME=$__MUL32X18
|
||||||
|
chtype -set $mul t:$__soft_mul
|
||||||
|
techmap -map +/mul2dsp.v -map +/quicklogic/qlf_k6n10f/dspv2_map.v -D USE_DSP_CFG_PARAMS=0 -D DSP_SIGNEDONLY -D DSP_A_MAXWIDTH=16 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=$__MUL16X9
|
||||||
|
# TODO is this missing from synth_quicklogic?
|
||||||
|
read_verilog -lib +/quicklogic/qlf_k6n10f/dspv2_sim.v
|
||||||
|
select -assert-count 2 t:dspv2_16x9x32_cfg_ports
|
||||||
|
select -assert-count 0 t:dspv2_32x18x64_cfg_ports
|
||||||
|
equiv_opt -assert -async2sync -map +/quicklogic/qlf_k6n10f/dspv2_sim.v ql_dsp_simd -dspv2
|
||||||
|
design -load postopt
|
||||||
|
select -assert-count 0 t:dspv2_16x9x32_cfg_ports
|
||||||
|
select -assert-count 1 t:dspv2_32x18x64_cfg_ports
|
Loading…
Reference in New Issue