mirror of https://github.com/YosysHQ/yosys.git
Merge pull request #4474 from tony-min-1/mchp
Add PolarFire FPGA support
This commit is contained in:
commit
9f869b265c
1
Makefile
1
Makefile
|
@ -879,6 +879,7 @@ endif
|
||||||
+cd tests/arch/quicklogic/pp3 && bash run-test.sh $(SEEDOPT)
|
+cd tests/arch/quicklogic/pp3 && bash run-test.sh $(SEEDOPT)
|
||||||
+cd tests/arch/quicklogic/qlf_k6n10f && bash run-test.sh $(SEEDOPT)
|
+cd tests/arch/quicklogic/qlf_k6n10f && bash run-test.sh $(SEEDOPT)
|
||||||
+cd tests/arch/gatemate && bash run-test.sh $(SEEDOPT)
|
+cd tests/arch/gatemate && bash run-test.sh $(SEEDOPT)
|
||||||
|
+cd tests/arch/microchip && bash run-test.sh $(SEEDOPT)
|
||||||
+cd tests/rpc && bash run-test.sh
|
+cd tests/rpc && bash run-test.sh
|
||||||
+cd tests/memfile && bash run-test.sh
|
+cd tests/memfile && bash run-test.sh
|
||||||
+cd tests/verilog && bash run-test.sh
|
+cd tests/verilog && bash run-test.sh
|
||||||
|
|
|
@ -37,6 +37,17 @@ $(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_cascade_pm.h))
|
||||||
|
|
||||||
# --------------------------------------
|
# --------------------------------------
|
||||||
|
|
||||||
|
OBJS += passes/pmgen/microchip_dsp.o
|
||||||
|
GENFILES += passes/pmgen/microchip_dsp_pm.h
|
||||||
|
GENFILES += passes/pmgen/microchip_dsp_CREG_pm.h
|
||||||
|
GENFILES += passes/pmgen/microchip_dsp_cascade_pm.h
|
||||||
|
passes/pmgen/microchip_dsp.o: passes/pmgen/microchip_dsp_pm.h passes/pmgen/microchip_dsp_CREG_pm.h passes/pmgen/microchip_dsp_cascade_pm.h
|
||||||
|
$(eval $(call add_extra_objs,passes/pmgen/microchip_dsp_pm.h))
|
||||||
|
$(eval $(call add_extra_objs,passes/pmgen/microchip_dsp_CREG_pm.h))
|
||||||
|
$(eval $(call add_extra_objs,passes/pmgen/microchip_dsp_cascade_pm.h))
|
||||||
|
|
||||||
|
# --------------------------------------
|
||||||
|
|
||||||
OBJS += passes/pmgen/peepopt.o
|
OBJS += passes/pmgen/peepopt.o
|
||||||
GENFILES += passes/pmgen/peepopt_pm.h
|
GENFILES += passes/pmgen/peepopt_pm.h
|
||||||
passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h
|
passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h
|
||||||
|
|
|
@ -0,0 +1,362 @@
|
||||||
|
/*
|
||||||
|
ISC License
|
||||||
|
|
||||||
|
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kernel/sigtools.h"
|
||||||
|
#include "kernel/yosys.h"
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
USING_YOSYS_NAMESPACE
|
||||||
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
#include "passes/pmgen/microchip_dsp_CREG_pm.h"
|
||||||
|
#include "passes/pmgen/microchip_dsp_cascade_pm.h"
|
||||||
|
#include "passes/pmgen/microchip_dsp_pm.h"
|
||||||
|
|
||||||
|
void microchip_dsp_pack(microchip_dsp_pm &pm)
|
||||||
|
{
|
||||||
|
auto &st = pm.st_microchip_dsp_pack;
|
||||||
|
|
||||||
|
log("Analysing %s.%s for Microchip MACC_PA packing.\n", log_id(pm.module), log_id(st.dsp));
|
||||||
|
|
||||||
|
Cell *cell = st.dsp;
|
||||||
|
// pack pre-adder
|
||||||
|
if (st.preAdderStatic) {
|
||||||
|
SigSpec &pasub = cell->connections_.at(ID(PASUB));
|
||||||
|
log(" static PASUB preadder %s (%s)\n", log_id(st.preAdderStatic), log_id(st.preAdderStatic->type));
|
||||||
|
bool D_SIGNED = st.preAdderStatic->getParam(ID::B_SIGNED).as_bool();
|
||||||
|
bool B_SIGNED = st.preAdderStatic->getParam(ID::A_SIGNED).as_bool();
|
||||||
|
st.sigB.extend_u0(18, B_SIGNED);
|
||||||
|
st.sigD.extend_u0(18, D_SIGNED);
|
||||||
|
if (st.moveBtoA) {
|
||||||
|
cell->setPort(ID::A, st.sigA); // if pre-adder feeds into A, original sigB will be moved to port A
|
||||||
|
}
|
||||||
|
cell->setPort(ID::B, st.sigB);
|
||||||
|
cell->setPort(ID::D, st.sigD);
|
||||||
|
// MACC_PA supports both addition and subtraction with the pre-adder.
|
||||||
|
// Affects the sign of the 'D' port.
|
||||||
|
if (st.preAdderStatic->type == ID($add))
|
||||||
|
pasub[0] = State::S0;
|
||||||
|
else if (st.preAdderStatic->type == ID($sub))
|
||||||
|
pasub[0] = State::S1;
|
||||||
|
else
|
||||||
|
log_assert(!"strange pre-adder type");
|
||||||
|
|
||||||
|
pm.autoremove(st.preAdderStatic);
|
||||||
|
}
|
||||||
|
// pack post-adder
|
||||||
|
if (st.postAdderStatic) {
|
||||||
|
log(" postadder %s (%s)\n", log_id(st.postAdderStatic), log_id(st.postAdderStatic->type));
|
||||||
|
SigSpec &sub = cell->connections_.at(ID(SUB));
|
||||||
|
// Post-adder in MACC_PA also supports subtraction
|
||||||
|
// Determines the sign of the output from the multiplier.
|
||||||
|
if (st.postAdderStatic->type == ID($add))
|
||||||
|
sub[0] = State::S0;
|
||||||
|
else if (st.postAdderStatic->type == ID($sub))
|
||||||
|
sub[0] = State::S1;
|
||||||
|
else
|
||||||
|
log_assert(!"strange post-adder type");
|
||||||
|
|
||||||
|
if (st.useFeedBack) {
|
||||||
|
cell->setPort(ID(CDIN_FDBK_SEL), {State::S0, State::S1});
|
||||||
|
} else {
|
||||||
|
st.sigC.extend_u0(48, st.postAdderStatic->getParam(ID::A_SIGNED).as_bool());
|
||||||
|
cell->setPort(ID::C, st.sigC);
|
||||||
|
}
|
||||||
|
|
||||||
|
pm.autoremove(st.postAdderStatic);
|
||||||
|
}
|
||||||
|
|
||||||
|
// pack registers
|
||||||
|
if (st.clock != SigBit()) {
|
||||||
|
cell->setPort(ID::CLK, st.clock);
|
||||||
|
|
||||||
|
// function to absorb a register
|
||||||
|
auto f = [&pm, cell](SigSpec &A, Cell *ff, IdString ceport, IdString rstport, IdString bypass) {
|
||||||
|
// input/output ports
|
||||||
|
SigSpec D = ff->getPort(ID::D);
|
||||||
|
SigSpec Q = pm.sigmap(ff->getPort(ID::Q));
|
||||||
|
|
||||||
|
if (!A.empty())
|
||||||
|
A.replace(Q, D);
|
||||||
|
if (rstport != IdString()) {
|
||||||
|
if (ff->type.in(ID($sdff), ID($sdffe))) {
|
||||||
|
SigSpec srst = ff->getPort(ID::SRST);
|
||||||
|
bool rstpol_n = !ff->getParam(ID::SRST_POLARITY).as_bool();
|
||||||
|
// active low sync rst
|
||||||
|
cell->setPort(rstport, rstpol_n ? srst : pm.module->Not(NEW_ID, srst));
|
||||||
|
} else if (ff->type.in(ID($adff), ID($adffe))) {
|
||||||
|
SigSpec arst = ff->getPort(ID::ARST);
|
||||||
|
bool rstpol_n = !ff->getParam(ID::ARST_POLARITY).as_bool();
|
||||||
|
// active low async rst
|
||||||
|
cell->setPort(rstport, rstpol_n ? arst : pm.module->Not(NEW_ID, arst));
|
||||||
|
} else {
|
||||||
|
// active low async/sync rst
|
||||||
|
cell->setPort(rstport, State::S1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ff->type.in(ID($dffe), ID($sdffe), ID($adffe))) {
|
||||||
|
SigSpec ce = ff->getPort(ID::EN);
|
||||||
|
bool cepol = ff->getParam(ID::EN_POLARITY).as_bool();
|
||||||
|
// enables are all active high
|
||||||
|
cell->setPort(ceport, cepol ? ce : pm.module->Not(NEW_ID, ce));
|
||||||
|
} else {
|
||||||
|
// enables are all active high
|
||||||
|
cell->setPort(ceport, State::S1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bypass set to 0
|
||||||
|
cell->setPort(bypass, State::S0);
|
||||||
|
|
||||||
|
for (auto c : Q.chunks()) {
|
||||||
|
auto it = c.wire->attributes.find(ID::init);
|
||||||
|
if (it == c.wire->attributes.end())
|
||||||
|
continue;
|
||||||
|
for (int i = c.offset; i < c.offset + c.width; i++) {
|
||||||
|
log_assert(it->second[i] == State::S0 || it->second[i] == State::Sx);
|
||||||
|
it->second[i] = State::Sx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOTE: flops are not autoremoved because it is possible that they
|
||||||
|
// are only partially absorbed into DSP, or have fanouts.
|
||||||
|
if (st.ffA) {
|
||||||
|
SigSpec A = cell->getPort(ID::A);
|
||||||
|
if (st.ffA) {
|
||||||
|
f(A, st.ffA, ID(A_EN), ID(A_SRST_N), ID(A_BYPASS));
|
||||||
|
}
|
||||||
|
pm.add_siguser(A, cell);
|
||||||
|
cell->setPort(ID::A, A);
|
||||||
|
}
|
||||||
|
if (st.ffB) {
|
||||||
|
SigSpec B = cell->getPort(ID::B);
|
||||||
|
if (st.ffB) {
|
||||||
|
f(B, st.ffB, ID(B_EN), ID(B_SRST_N), ID(B_BYPASS));
|
||||||
|
}
|
||||||
|
pm.add_siguser(B, cell);
|
||||||
|
cell->setPort(ID::B, B);
|
||||||
|
}
|
||||||
|
if (st.ffD) {
|
||||||
|
SigSpec D = cell->getPort(ID::D);
|
||||||
|
if (st.ffD->type.in(ID($adff), ID($adffe))) {
|
||||||
|
f(D, st.ffD, ID(D_EN), ID(D_ARST_N), ID(D_BYPASS));
|
||||||
|
} else {
|
||||||
|
f(D, st.ffD, ID(D_EN), ID(D_SRST_N), ID(D_BYPASS));
|
||||||
|
}
|
||||||
|
|
||||||
|
pm.add_siguser(D, cell);
|
||||||
|
cell->setPort(ID::D, D);
|
||||||
|
}
|
||||||
|
if (st.ffP) {
|
||||||
|
SigSpec P; // unused
|
||||||
|
f(P, st.ffP, ID(P_EN), ID(P_SRST_N), ID(P_BYPASS));
|
||||||
|
st.ffP->connections_.at(ID::Q).replace(st.sigP, pm.module->addWire(NEW_ID, GetSize(st.sigP)));
|
||||||
|
}
|
||||||
|
|
||||||
|
log(" clock: %s (%s)\n", log_signal(st.clock), "posedge");
|
||||||
|
|
||||||
|
if (st.ffA)
|
||||||
|
log(" \t ffA:%s\n", log_id(st.ffA));
|
||||||
|
if (st.ffB)
|
||||||
|
log(" \t ffB:%s\n", log_id(st.ffB));
|
||||||
|
if (st.ffD)
|
||||||
|
log(" \t ffD:%s\n", log_id(st.ffD));
|
||||||
|
if (st.ffP)
|
||||||
|
log(" \t ffP:%s\n", log_id(st.ffP));
|
||||||
|
}
|
||||||
|
log("\n");
|
||||||
|
|
||||||
|
SigSpec P = st.sigP;
|
||||||
|
if (GetSize(P) < 48)
|
||||||
|
P.append(pm.module->addWire(NEW_ID, 48 - GetSize(P)));
|
||||||
|
cell->setPort(ID::P, P);
|
||||||
|
|
||||||
|
pm.blacklist(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For packing cascaded DSPs
|
||||||
|
void microchip_dsp_packC(microchip_dsp_CREG_pm &pm)
|
||||||
|
{
|
||||||
|
auto &st = pm.st_microchip_dsp_packC;
|
||||||
|
|
||||||
|
log_debug("Analysing %s.%s for Microchip DSP packing (REG_C).\n", log_id(pm.module), log_id(st.dsp));
|
||||||
|
log_debug("ffC: %s\n", log_id(st.ffC, "--"));
|
||||||
|
|
||||||
|
Cell *cell = st.dsp;
|
||||||
|
|
||||||
|
if (st.clock != SigBit()) {
|
||||||
|
cell->setPort(ID::CLK, st.clock);
|
||||||
|
|
||||||
|
// same function as above, used for the last CREG we need to absorb
|
||||||
|
auto f = [&pm, cell](SigSpec &A, Cell *ff, IdString ceport, IdString rstport, IdString bypass) {
|
||||||
|
// input/output ports
|
||||||
|
SigSpec D = ff->getPort(ID::D);
|
||||||
|
SigSpec Q = pm.sigmap(ff->getPort(ID::Q));
|
||||||
|
if (!A.empty())
|
||||||
|
A.replace(Q, D);
|
||||||
|
if (rstport != IdString()) {
|
||||||
|
if (ff->type.in(ID($sdff), ID($sdffe))) {
|
||||||
|
SigSpec srst = ff->getPort(ID::SRST);
|
||||||
|
bool rstpol_n = !ff->getParam(ID::SRST_POLARITY).as_bool();
|
||||||
|
// active low sync rst
|
||||||
|
cell->setPort(rstport, rstpol_n ? srst : pm.module->Not(NEW_ID, srst));
|
||||||
|
} else if (ff->type.in(ID($adff), ID($adffe))) {
|
||||||
|
SigSpec arst = ff->getPort(ID::ARST);
|
||||||
|
bool rstpol_n = !ff->getParam(ID::ARST_POLARITY).as_bool();
|
||||||
|
// active low async rst
|
||||||
|
cell->setPort(rstport, rstpol_n ? arst : pm.module->Not(NEW_ID, arst));
|
||||||
|
} else {
|
||||||
|
// active low async/sync rst
|
||||||
|
cell->setPort(rstport, State::S1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ff->type.in(ID($dffe), ID($sdffe), ID($adffe))) {
|
||||||
|
SigSpec ce = ff->getPort(ID::EN);
|
||||||
|
bool cepol = ff->getParam(ID::EN_POLARITY).as_bool();
|
||||||
|
// enables are all active high
|
||||||
|
cell->setPort(ceport, cepol ? ce : pm.module->Not(NEW_ID, ce));
|
||||||
|
} else {
|
||||||
|
// enables are all active high
|
||||||
|
cell->setPort(ceport, State::S1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bypass set to 0
|
||||||
|
cell->setPort(bypass, State::S0);
|
||||||
|
|
||||||
|
for (auto c : Q.chunks()) {
|
||||||
|
auto it = c.wire->attributes.find(ID::init);
|
||||||
|
if (it == c.wire->attributes.end())
|
||||||
|
continue;
|
||||||
|
for (int i = c.offset; i < c.offset + c.width; i++) {
|
||||||
|
log_assert(it->second[i] == State::S0 || it->second[i] == State::Sx);
|
||||||
|
it->second[i] = State::Sx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (st.ffC) {
|
||||||
|
SigSpec C = cell->getPort(ID::C);
|
||||||
|
|
||||||
|
if (st.ffC->type.in(ID($adff), ID($adffe))) {
|
||||||
|
f(C, st.ffC, ID(C_EN), ID(C_ARST_N), ID(C_BYPASS));
|
||||||
|
} else {
|
||||||
|
f(C, st.ffC, ID(C_EN), ID(C_SRST_N), ID(C_BYPASS));
|
||||||
|
}
|
||||||
|
pm.add_siguser(C, cell);
|
||||||
|
cell->setPort(ID::C, C);
|
||||||
|
}
|
||||||
|
|
||||||
|
log(" clock: %s (%s)", log_signal(st.clock), "posedge");
|
||||||
|
|
||||||
|
if (st.ffC)
|
||||||
|
log(" ffC:%s", log_id(st.ffC));
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
pm.blacklist(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MicrochipDspPass : public Pass {
|
||||||
|
MicrochipDspPass() : Pass("microchip_dsp", "MICROCHIP: pack resources into DSPs") {}
|
||||||
|
void help() override
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" microchip_dsp [options] [selection]\n");
|
||||||
|
log("\n");
|
||||||
|
log("Pack input registers 'A', 'B', 'C', and 'D' (with optional enable/reset),\n");
|
||||||
|
log("output register 'P' (with optional enable/reset), pre-adder and/or post-adder into\n");
|
||||||
|
log("Microchip DSP resources.\n");
|
||||||
|
log("\n");
|
||||||
|
log("Multiply-accumulate operations using the post-adder with feedback on the 'C'\n");
|
||||||
|
log("input will be folded into the DSP. In this scenario only, the 'C' input can be\n");
|
||||||
|
log("used to override the current accumulation result with a new value. This will\n");
|
||||||
|
log("be added to the multiplier result to form the next accumulation result.\n");
|
||||||
|
log("\n");
|
||||||
|
log("Use of the dedicated 'PCOUT' -> 'PCIN' cascade path is detected for 'P' -> 'C'\n");
|
||||||
|
log("connections (optionally, where 'P' is right-shifted by 17-bits and used as an\n");
|
||||||
|
log("input to the post-adder. This pattern is common for summing partial products to\n");
|
||||||
|
log("implement wide multipliers). Cascade chains are limited to a mazimum length \n");
|
||||||
|
log("of 24 cells, corresponding to PolarFire (pf) devices.\n");
|
||||||
|
log("\n");
|
||||||
|
log("This pass is a no-op if the scratchpad variable 'microchip_dsp.multonly' is set\n");
|
||||||
|
log("to 1.\n");
|
||||||
|
log("\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -family {polarfire}\n");
|
||||||
|
log(" select the family to target\n");
|
||||||
|
log(" default: polarfire\n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||||
|
{
|
||||||
|
log_header(design, "Executing MICROCHIP_DSP pass (pack resources into DSPs).\n");
|
||||||
|
|
||||||
|
std::string family = "polarfire";
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||||
|
if ((args[argidx] == "-family") && argidx + 1 < args.size()) {
|
||||||
|
family = args[++argidx];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
|
for (auto module : design->selected_modules()) {
|
||||||
|
|
||||||
|
if (design->scratchpad_get_bool("microchip_dsp.multonly"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
{
|
||||||
|
// For more details on PolarFire MACC_PA, consult
|
||||||
|
// the "PolarFire FPGA Macro Library Guide"
|
||||||
|
|
||||||
|
// Main pattern matching step to capture a DSP cell.
|
||||||
|
// Match for pre-adder, post-adder, as well as
|
||||||
|
// registers 'A', 'B', 'D', and 'P'. Additionally,
|
||||||
|
// check for an accumulator pattern based on whether
|
||||||
|
// a post-adder and PREG are both present AND
|
||||||
|
// if PREG feeds into this post-adder.
|
||||||
|
microchip_dsp_pm pm(module, module->selected_cells());
|
||||||
|
pm.run_microchip_dsp_pack(microchip_dsp_pack);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Separating out CREG packing is necessary since there
|
||||||
|
// is no guarantee that the cell ordering corresponds
|
||||||
|
// to the "expected" case (i.e. the order in which
|
||||||
|
// they appear in the source). There existed the possibility
|
||||||
|
// where a register got packed as a CREG into a
|
||||||
|
// downstream DSP that should have otherwise been a
|
||||||
|
// PREG of an upstream DSP that had not been visited
|
||||||
|
// yet
|
||||||
|
{
|
||||||
|
microchip_dsp_CREG_pm pm(module, module->selected_cells());
|
||||||
|
pm.run_microchip_dsp_packC(microchip_dsp_packC);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lastly, identify and utilise PCOUT -> PCIN chains
|
||||||
|
{
|
||||||
|
microchip_dsp_cascade_pm pm(module, module->selected_cells());
|
||||||
|
pm.run_microchip_dsp_cascade();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} MicrochipDspPass;
|
||||||
|
|
||||||
|
PRIVATE_NAMESPACE_END
|
|
@ -0,0 +1,439 @@
|
||||||
|
// ISC License
|
||||||
|
//
|
||||||
|
// Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
// This file describes the main pattern matcher setup (of three total) that
|
||||||
|
// forms the `microchip_dsp` pass described in microchip_dsp.cc
|
||||||
|
// At a high level, it works as follows:
|
||||||
|
// ( 1) Starting from a DSP cell. Capture DSP configurations as states
|
||||||
|
// ( 2) Match for pre-adder
|
||||||
|
// ( 3) Match for post-adder
|
||||||
|
// ( 4) Match register 'A', 'B', 'D', 'P'
|
||||||
|
// ( 5) If post-adder and PREG both present, check if PREG feeds into post-adder.
|
||||||
|
// This indicates an accumulator situation like the ASCII diagram below:
|
||||||
|
// +--------------------------------+
|
||||||
|
// |_________ |
|
||||||
|
// | /-------\ +----+ |
|
||||||
|
// +----+ +-| post- |___|PREG|---+ 'P'
|
||||||
|
// |MULT|------ | adder | +----+
|
||||||
|
// +----+ \-------/
|
||||||
|
|
||||||
|
pattern microchip_dsp_pack
|
||||||
|
|
||||||
|
state <SigBit> clock
|
||||||
|
state <SigSpec> sigA sigB sigC sigD sigP
|
||||||
|
state <Cell*> ffA ffB ffD ffP
|
||||||
|
state <Cell*> preAdderStatic postAdderStatic
|
||||||
|
state <bool> moveBtoA useFeedBack
|
||||||
|
|
||||||
|
// static ports, used to detect dsp configuration
|
||||||
|
state <SigSpec> bypassA bypassB bypassC bypassD bypassP
|
||||||
|
state <SigSpec> bypassPASUB
|
||||||
|
|
||||||
|
// Variables used for subpatterns
|
||||||
|
state <SigSpec> argQ argD
|
||||||
|
udata <bool> allowAsync
|
||||||
|
udata <SigSpec> dffD dffQ
|
||||||
|
udata <SigBit> dffclock
|
||||||
|
udata <Cell*> dff
|
||||||
|
udata <Cell*> u_preAdderStatic u_postAdderStatic
|
||||||
|
udata <IdString> u_postAddAB
|
||||||
|
state <IdString> postAddAB
|
||||||
|
|
||||||
|
// (1) Starting from a DSP cell
|
||||||
|
match dsp
|
||||||
|
select dsp->type.in(\MACC_PA)
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
// detect existing signals connected to DSP
|
||||||
|
// detect configuration ports
|
||||||
|
code sigA sigB sigC sigD clock sigP
|
||||||
|
//helper function to remove unused bits
|
||||||
|
auto unextend = [](const SigSpec &sig) {
|
||||||
|
int i;
|
||||||
|
for (i = GetSize(sig)-1; i > 0; i--)
|
||||||
|
if (sig[i] != sig[i-1])
|
||||||
|
break;
|
||||||
|
// Do not remove non-const sign bit
|
||||||
|
if (sig[i].wire)
|
||||||
|
++i;
|
||||||
|
return sig.extract(0, i);
|
||||||
|
};
|
||||||
|
|
||||||
|
//unextend to remove unused bits
|
||||||
|
sigA = unextend(port(dsp, \A));
|
||||||
|
sigB = unextend(port(dsp, \B));
|
||||||
|
|
||||||
|
//update signals
|
||||||
|
sigC = port(dsp, \C, SigSpec());
|
||||||
|
sigD = port(dsp, \D, SigSpec());
|
||||||
|
|
||||||
|
|
||||||
|
SigSpec P = port(dsp, \P);
|
||||||
|
// Only care about bits that are used
|
||||||
|
int i;
|
||||||
|
for (i = GetSize(P)-1; i >= 0; i--)
|
||||||
|
if (nusers(P[i]) > 1)
|
||||||
|
break;
|
||||||
|
i++;
|
||||||
|
log_assert(nusers(P.extract_end(i)) <= 1);
|
||||||
|
// This sigP could have no users if downstream sinks (e.g. $add) is
|
||||||
|
// narrower than $mul result, for example
|
||||||
|
if (i == 0)
|
||||||
|
reject;
|
||||||
|
sigP = P.extract(0, i);
|
||||||
|
clock = port(dsp, \CLK, SigBit());
|
||||||
|
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// capture static configuration ports
|
||||||
|
code bypassA bypassB bypassC bypassD bypassPASUB bypassP
|
||||||
|
bypassA = port(dsp, \A_BYPASS, SigSpec());
|
||||||
|
bypassB = port(dsp, \B_BYPASS, SigSpec());
|
||||||
|
bypassC = port(dsp, \C_BYPASS, SigSpec());
|
||||||
|
bypassD = port(dsp, \D_BYPASS, SigSpec());
|
||||||
|
bypassPASUB = port(dsp, \PASUB_BYPASS, SigSpec());
|
||||||
|
bypassP = port(dsp, \P_BYPASS, SigSpec());
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (2) Match for pre-adder
|
||||||
|
//
|
||||||
|
code sigA sigB sigD preAdderStatic moveBtoA
|
||||||
|
subpattern(preAddMatching);
|
||||||
|
preAdderStatic = u_preAdderStatic;
|
||||||
|
moveBtoA = false;
|
||||||
|
|
||||||
|
if (preAdderStatic) {
|
||||||
|
|
||||||
|
if (port(preAdderStatic, \Y) == sigA)
|
||||||
|
{
|
||||||
|
//used for packing
|
||||||
|
moveBtoA = true;
|
||||||
|
|
||||||
|
// sigA should be the input to the multiplier without the preAdd. sigB and sigD should be
|
||||||
|
//the preAdd inputs. If our "A" input into the multiplier is from the preAdd (not sigA), then
|
||||||
|
// we basically swap it.
|
||||||
|
sigA = sigB;
|
||||||
|
}
|
||||||
|
|
||||||
|
// port B of preAdderStatic must be mapped to port D of DSP for subtraction
|
||||||
|
sigD = port(preAdderStatic, \B);
|
||||||
|
sigB = port(preAdderStatic, \A);
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (3) Match for post-adder
|
||||||
|
//
|
||||||
|
code postAdderStatic sigP sigC
|
||||||
|
u_postAdderStatic = nullptr;
|
||||||
|
subpattern(postAddMatching);
|
||||||
|
postAdderStatic = u_postAdderStatic;
|
||||||
|
|
||||||
|
if (postAdderStatic) {
|
||||||
|
//sigC will be whichever input to the postAdder that is NOT from the multiplier
|
||||||
|
// u_postAddAB is the input to the postAdder from the multiplier
|
||||||
|
sigC = port(postAdderStatic, u_postAddAB == \A ? \B : \A);
|
||||||
|
sigP = port(postAdderStatic, \Y);
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
|
||||||
|
// (4) Matching registers
|
||||||
|
//
|
||||||
|
// 'A' input for REG_A
|
||||||
|
code argQ bypassA sigA clock ffA
|
||||||
|
if (bypassA.is_fully_ones()){
|
||||||
|
argQ = sigA;
|
||||||
|
allowAsync = false;
|
||||||
|
subpattern(in_dffe);
|
||||||
|
if (dff) {
|
||||||
|
ffA = dff;
|
||||||
|
clock = dffclock;
|
||||||
|
sigA = dffD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// 'B' input for REG_B
|
||||||
|
code argQ bypassB sigB clock ffB
|
||||||
|
if (bypassB.is_fully_ones()){
|
||||||
|
argQ = sigB;
|
||||||
|
allowAsync = false;
|
||||||
|
subpattern(in_dffe);
|
||||||
|
if (dff) {
|
||||||
|
ffB = dff;
|
||||||
|
clock = dffclock;
|
||||||
|
sigB = dffD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// 'D' input for REG_D
|
||||||
|
code argQ bypassP sigD clock ffD
|
||||||
|
if (bypassD.is_fully_ones()){
|
||||||
|
argQ = sigD;
|
||||||
|
allowAsync = true;
|
||||||
|
subpattern(in_dffe);
|
||||||
|
if (dff) {
|
||||||
|
ffD = dff;
|
||||||
|
clock = dffclock;
|
||||||
|
sigD = dffD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// 'P' output for REG_P
|
||||||
|
code argD ffP sigP clock bypassP
|
||||||
|
if (bypassP.is_fully_ones() && nusers(sigP) == 2) {
|
||||||
|
argD = sigP;
|
||||||
|
allowAsync = false;
|
||||||
|
subpattern(out_dffe);
|
||||||
|
if (dff) {
|
||||||
|
ffP = dff;
|
||||||
|
clock = dffclock;
|
||||||
|
sigP = dffQ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (5) If post-adder and PREG both present, check if PREG feeds into post-adder via port C.
|
||||||
|
// This indicates an accumulator situation. Port C can be freed
|
||||||
|
// +--------------------------------+
|
||||||
|
// |_________ |
|
||||||
|
// | /-------\ +----+ |
|
||||||
|
// +----+ +-| post- |___|PREG|---+ 'P'
|
||||||
|
// |MULT|------ | adder | +----+
|
||||||
|
// +----+ \-------/
|
||||||
|
code useFeedBack
|
||||||
|
useFeedBack = false;
|
||||||
|
if (postAdderStatic && ffP) {
|
||||||
|
if (sigC == sigP) {
|
||||||
|
useFeedBack = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// if any cells are absorbed, invoke the callback function
|
||||||
|
code
|
||||||
|
if (preAdderStatic || postAdderStatic)
|
||||||
|
accept;
|
||||||
|
if (ffA || ffB || ffD || ffP)
|
||||||
|
accept;
|
||||||
|
endcode
|
||||||
|
|
||||||
|
|
||||||
|
// #######################
|
||||||
|
// Subpattern for matching against post-adder
|
||||||
|
// Match 'P' output that exclusively drives one of two inputs to an $add
|
||||||
|
// cell (post-adder).
|
||||||
|
// The other input to the adder is assumed to come in from the 'C' input
|
||||||
|
|
||||||
|
subpattern postAddMatching
|
||||||
|
arg sigP
|
||||||
|
|
||||||
|
match postAdd
|
||||||
|
|
||||||
|
select postAdd->type.in($add, $sub)
|
||||||
|
select GetSize(port(postAdd, \Y)) <= 48
|
||||||
|
|
||||||
|
// AB is the port that connects MUL to ADD
|
||||||
|
choice <IdString> AB {\A, \B}
|
||||||
|
select nusers(port(postAdd, AB)) == 2
|
||||||
|
|
||||||
|
// has one input coming from multiplier
|
||||||
|
index <SigBit> port(postAdd, AB)[0] === sigP[0]
|
||||||
|
filter GetSize(port(postAdd, AB)) >= GetSize(sigP)
|
||||||
|
filter port(postAdd, AB).extract(0, GetSize(sigP)) == sigP
|
||||||
|
// Check that remainder of AB is a sign- or zero-extension
|
||||||
|
filter port(postAdd, AB).extract_end(GetSize(sigP)) == SigSpec(sigP[GetSize(sigP)-1], GetSize(port(postAdd, AB))-GetSize(sigP)) || port(postAdd, AB).extract_end(GetSize(sigP)) == SigSpec(State::S0, GetSize(port(postAdd, AB))-GetSize(sigP))
|
||||||
|
|
||||||
|
set postAddAB AB
|
||||||
|
// optional
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code
|
||||||
|
if (postAdd)
|
||||||
|
{
|
||||||
|
if (postAdd->type.in(ID($sub)) && postAddAB == \A) {
|
||||||
|
// if $sub, the multiplier output must match to $sub.B, otherwise no match
|
||||||
|
} else {
|
||||||
|
u_postAddAB = postAddAB;
|
||||||
|
u_postAdderStatic = postAdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
|
||||||
|
// #######################
|
||||||
|
// Subpattern for matching against pre-adder
|
||||||
|
// support static PASUB only
|
||||||
|
|
||||||
|
subpattern preAddMatching
|
||||||
|
arg sigA sigB sigD bypassB bypassD bypassPASUB
|
||||||
|
|
||||||
|
code
|
||||||
|
u_preAdderStatic = nullptr;
|
||||||
|
|
||||||
|
// Ensure that preAdder not already used
|
||||||
|
// Assume we can inspect port D to see if its all zeros.
|
||||||
|
if (!(sigD.empty() || sigD.is_fully_zero())) reject;
|
||||||
|
if (!bypassB.is_fully_ones()) reject;
|
||||||
|
if (!bypassD.is_fully_ones()) reject;
|
||||||
|
if (!bypassPASUB.is_fully_ones()) reject;
|
||||||
|
endcode
|
||||||
|
|
||||||
|
match preAdd
|
||||||
|
|
||||||
|
// can handle add or sub
|
||||||
|
select preAdd->type.in($add, $sub)
|
||||||
|
|
||||||
|
// Output has to be 18 bits or less, and only has single fanout
|
||||||
|
select GetSize(port(preAdd, \Y)) <= 18
|
||||||
|
select nusers(port(preAdd, \Y)) == 2
|
||||||
|
|
||||||
|
// Adder inputs must be 18 bits or less
|
||||||
|
select GetSize(port(preAdd, \A)) <= 18
|
||||||
|
select GetSize(port(preAdd, \B)) <= 18
|
||||||
|
|
||||||
|
// Output feeds into one of multiplier input
|
||||||
|
filter port(preAdd, \Y) == sigB || port(preAdd, \Y) == sigA
|
||||||
|
|
||||||
|
// optional
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code
|
||||||
|
if (preAdd)
|
||||||
|
{
|
||||||
|
u_preAdderStatic = preAdd;
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// #######################
|
||||||
|
// Subpattern for matching against input registers, based on knowledge of the
|
||||||
|
// 'Q' input.
|
||||||
|
subpattern in_dffe
|
||||||
|
arg argQ clock
|
||||||
|
|
||||||
|
code
|
||||||
|
dff = nullptr;
|
||||||
|
if (argQ.empty())
|
||||||
|
reject;
|
||||||
|
for (const auto &c : argQ.chunks()) {
|
||||||
|
// Abandon matches when 'Q' is a constant
|
||||||
|
if (!c.wire)
|
||||||
|
reject;
|
||||||
|
// Abandon matches when 'Q' has the keep attribute set
|
||||||
|
if (c.wire->get_bool_attribute(\keep))
|
||||||
|
reject;
|
||||||
|
// Abandon matches when 'Q' has a non-zero init attribute set
|
||||||
|
Const init = c.wire->attributes.at(\init, Const());
|
||||||
|
if (!init.empty())
|
||||||
|
for (auto b : init.extract(c.offset, c.width))
|
||||||
|
if (b != State::Sx && b != State::S0)
|
||||||
|
reject;
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
match ff
|
||||||
|
// reg D has async rst
|
||||||
|
// reg A, B has sync rst
|
||||||
|
select ff->type.in($dff, $dffe, $sdff, $sdffe, $adff, $adffe)
|
||||||
|
// does not support clock inversion
|
||||||
|
select param(ff, \CLK_POLARITY).as_bool()
|
||||||
|
|
||||||
|
// it is possible that only part of a dff output matches argQ
|
||||||
|
slice offset GetSize(port(ff, \D))
|
||||||
|
index <SigBit> port(ff, \Q)[offset] === argQ[0]
|
||||||
|
|
||||||
|
// Check that the rest of argQ is present
|
||||||
|
filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
|
||||||
|
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
|
||||||
|
|
||||||
|
// only consider async rst flops when flag is set
|
||||||
|
filter !ff->type.in($adff, $adffe) || allowAsync
|
||||||
|
|
||||||
|
// clock must be consistent
|
||||||
|
filter clock == SigBit() || port(ff, \CLK)[0] == clock
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code argQ
|
||||||
|
// Check that reset value, if present, is fully 0.
|
||||||
|
bool noResetFlop = ff->type.in($dff, $dffe);
|
||||||
|
bool srstZero = ff->type.in($sdff, $sdffe) && param(ff, \SRST_VALUE).is_fully_zero();
|
||||||
|
bool arstZero = ff->type.in($adff, $adffe) && param(ff, \ARST_VALUE).is_fully_zero();
|
||||||
|
bool resetLegal = noResetFlop || srstZero || arstZero;
|
||||||
|
if (resetLegal)
|
||||||
|
{
|
||||||
|
SigSpec Q = port(ff, \Q);
|
||||||
|
dff = ff;
|
||||||
|
dffclock = port(ff, \CLK);
|
||||||
|
dffD = argQ;
|
||||||
|
SigSpec D = port(ff, \D);
|
||||||
|
argQ = Q;
|
||||||
|
dffD.replace(argQ, D);
|
||||||
|
}
|
||||||
|
|
||||||
|
endcode
|
||||||
|
// #######################
|
||||||
|
|
||||||
|
|
||||||
|
subpattern out_dffe
|
||||||
|
arg argD argQ clock
|
||||||
|
|
||||||
|
code
|
||||||
|
dff = nullptr;
|
||||||
|
for (auto c : argD.chunks())
|
||||||
|
// Abandon matches when 'D' has the keep attribute set
|
||||||
|
if (c.wire->get_bool_attribute(\keep))
|
||||||
|
reject;
|
||||||
|
endcode
|
||||||
|
|
||||||
|
match ff
|
||||||
|
select ff->type.in($dff, $dffe, $sdff, $sdffe)
|
||||||
|
// does not support clock inversion
|
||||||
|
select param(ff, \CLK_POLARITY).as_bool()
|
||||||
|
|
||||||
|
slice offset GetSize(port(ff, \D))
|
||||||
|
index <SigBit> port(ff, \D)[offset] === argD[0]
|
||||||
|
|
||||||
|
// Check that the rest of argD is present
|
||||||
|
filter GetSize(port(ff, \D)) >= offset + GetSize(argD)
|
||||||
|
filter port(ff, \D).extract(offset, GetSize(argD)) == argD
|
||||||
|
|
||||||
|
filter clock == SigBit() || port(ff, \CLK)[0] == clock
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code argQ
|
||||||
|
SigSpec D = port(ff, \D);
|
||||||
|
SigSpec Q = port(ff, \Q);
|
||||||
|
argQ = argD;
|
||||||
|
argQ.replace(D, Q);
|
||||||
|
|
||||||
|
// Abandon matches when 'Q' has a non-zero init attribute set
|
||||||
|
for (auto c : argQ.chunks()) {
|
||||||
|
Const init = c.wire->attributes.at(\init, Const());
|
||||||
|
if (!init.empty())
|
||||||
|
for (auto b : init.extract(c.offset, c.width))
|
||||||
|
if (b != State::Sx && b != State::S0)
|
||||||
|
reject;
|
||||||
|
}
|
||||||
|
|
||||||
|
dff = ff;
|
||||||
|
dffQ = argQ;
|
||||||
|
dffclock = port(ff, \CLK);
|
||||||
|
endcode
|
|
@ -0,0 +1,168 @@
|
||||||
|
// ISC License
|
||||||
|
//
|
||||||
|
// Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
// This file describes the second of three pattern matcher setups that
|
||||||
|
// forms the `microchip_dsp` pass described in microchip_dsp.cc
|
||||||
|
// At a high level, it works as follows:
|
||||||
|
// (1) Starting from a DSP cell that (a) doesn't have a CREG already,
|
||||||
|
// and (b) uses the 'C' port
|
||||||
|
// (2) Match the driver of the 'C' input to a possible $dff cell (CREG)
|
||||||
|
// (attached to at most two $mux cells that implement clock-enable or
|
||||||
|
// reset functionality, using a subpattern discussed below)
|
||||||
|
// Notes:
|
||||||
|
// - Running CREG packing after microchip_dsp_pack is necessary since there is no
|
||||||
|
// guarantee that the cell ordering corresponds to the "expected" case (i.e.
|
||||||
|
// the order in which they appear in the source) thus the possiblity existed
|
||||||
|
// where a register got packed as a CREG into a downstream DSP, while it should
|
||||||
|
// have otherwise been a PREG of an upstream DSP that had not been visited.
|
||||||
|
// yet.
|
||||||
|
// - The reason this is separated out from the microchip_dsp.pmg file is
|
||||||
|
// for efficiency --- each *.pmg file creates a class of the same basename,
|
||||||
|
// which when constructed, creates a custom database tailored to the
|
||||||
|
// pattern(s) contained within. Since the pattern in this file must be
|
||||||
|
// executed after the pattern contained in microchip_dsp.pmg, it is necessary
|
||||||
|
// to reconstruct this database. Separating the two patterns into
|
||||||
|
// independent files causes two smaller, more specific, databases.
|
||||||
|
|
||||||
|
pattern microchip_dsp_packC
|
||||||
|
|
||||||
|
udata <std::function<SigSpec(const SigSpec&)>> unextend
|
||||||
|
state <SigBit> clock
|
||||||
|
state <SigSpec> sigC sigP
|
||||||
|
state <Cell*> ffC
|
||||||
|
|
||||||
|
// Variables used for subpatterns
|
||||||
|
state <SigSpec> argQ argD
|
||||||
|
state <int> ffoffset
|
||||||
|
udata <SigSpec> dffD dffQ
|
||||||
|
udata <SigBit> dffclock
|
||||||
|
udata <Cell*> dff
|
||||||
|
|
||||||
|
// (1) Starting from a DSP cell that (a) doesn't have a CREG already,
|
||||||
|
// and (b) uses the 'C' port
|
||||||
|
match dsp
|
||||||
|
select dsp->type.in(\MACC_PA)
|
||||||
|
select port(dsp, \C_BYPASS, SigSpec()).is_fully_ones()
|
||||||
|
select nusers(port(dsp, \C, SigSpec())) > 1
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code sigC sigP clock
|
||||||
|
//helper function to remove unused bits
|
||||||
|
unextend = [](const SigSpec &sig) {
|
||||||
|
int i;
|
||||||
|
for (i = GetSize(sig)-1; i > 0; i--)
|
||||||
|
if (sig[i] != sig[i-1])
|
||||||
|
break;
|
||||||
|
// Do not remove non-const sign bit
|
||||||
|
if (sig[i].wire)
|
||||||
|
++i;
|
||||||
|
return sig.extract(0, i);
|
||||||
|
};
|
||||||
|
sigC = unextend(port(dsp, \C, SigSpec()));
|
||||||
|
|
||||||
|
SigSpec P = port(dsp, \P);
|
||||||
|
|
||||||
|
// Only care about those bits that are used
|
||||||
|
int i;
|
||||||
|
for (i = GetSize(P)-1; i >= 0; i--)
|
||||||
|
if (nusers(P[i]) > 1)
|
||||||
|
break;
|
||||||
|
i++;
|
||||||
|
log_assert(nusers(P.extract_end(i)) <= 1);
|
||||||
|
sigP = P.extract(0, i);
|
||||||
|
|
||||||
|
clock = port(dsp, \CLK, SigBit());
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (2) Match the driver of the 'C' input to a possible $dff cell (CREG)
|
||||||
|
// (attached to at most two $mux cells that implement clock-enable or
|
||||||
|
// reset functionality, using the in_dffe subpattern)
|
||||||
|
code argQ ffC sigC clock
|
||||||
|
argQ = sigC;
|
||||||
|
subpattern(in_dffe);
|
||||||
|
if (dff) {
|
||||||
|
ffC = dff;
|
||||||
|
clock = dffclock;
|
||||||
|
sigC = dffD;
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
code
|
||||||
|
if (ffC)
|
||||||
|
accept;
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// #######################
|
||||||
|
|
||||||
|
// Subpattern for matching against input registers, based on knowledge of the
|
||||||
|
// 'Q' input.
|
||||||
|
subpattern in_dffe
|
||||||
|
arg argQ clock
|
||||||
|
|
||||||
|
code
|
||||||
|
dff = nullptr;
|
||||||
|
if (argQ.empty())
|
||||||
|
reject;
|
||||||
|
for (const auto &c : argQ.chunks()) {
|
||||||
|
// Abandon matches when 'Q' is a constant
|
||||||
|
if (!c.wire)
|
||||||
|
reject;
|
||||||
|
// Abandon matches when 'Q' has the keep attribute set
|
||||||
|
if (c.wire->get_bool_attribute(\keep))
|
||||||
|
reject;
|
||||||
|
// Abandon matches when 'Q' has a non-zero init attribute set
|
||||||
|
Const init = c.wire->attributes.at(\init, Const());
|
||||||
|
if (!init.empty())
|
||||||
|
for (auto b : init.extract(c.offset, c.width))
|
||||||
|
if (b != State::Sx && b != State::S0)
|
||||||
|
reject;
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
match ff
|
||||||
|
select ff->type.in($dff, $dffe, $sdff, $sdffe, $adff, $adffe)
|
||||||
|
// does not support clock inversion
|
||||||
|
select param(ff, \CLK_POLARITY).as_bool()
|
||||||
|
|
||||||
|
slice offset GetSize(port(ff, \D))
|
||||||
|
index <SigBit> port(ff, \Q)[offset] === argQ[0]
|
||||||
|
|
||||||
|
// Check that the rest of argQ is present
|
||||||
|
filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
|
||||||
|
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
|
||||||
|
|
||||||
|
filter clock == SigBit() || port(ff, \CLK)[0] == clock
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code argQ
|
||||||
|
// Check that reset value, if present, is fully 0.
|
||||||
|
bool noResetFlop = ff->type.in($dff, $dffe);
|
||||||
|
bool srstZero = ff->type.in($sdff, $sdffe) && param(ff, \SRST_VALUE).is_fully_zero();
|
||||||
|
bool arstZero = ff->type.in($adff, $adffe) && param(ff, \ARST_VALUE).is_fully_zero();
|
||||||
|
bool resetLegal = noResetFlop || srstZero || arstZero;
|
||||||
|
if (resetLegal)
|
||||||
|
{
|
||||||
|
SigSpec Q = port(ff, \Q);
|
||||||
|
dff = ff;
|
||||||
|
dffclock = port(ff, \CLK);
|
||||||
|
dffD = argQ;
|
||||||
|
SigSpec D = port(ff, \D);
|
||||||
|
argQ = Q;
|
||||||
|
dffD.replace(argQ, D);
|
||||||
|
}
|
||||||
|
|
||||||
|
endcode
|
|
@ -0,0 +1,236 @@
|
||||||
|
// ISC License
|
||||||
|
//
|
||||||
|
// Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
// This file describes the third of three pattern matcher setups that
|
||||||
|
// forms the `microchip_dsp` pass described in microchip_dsp.cc
|
||||||
|
// At a high level, it works as follows:
|
||||||
|
// (1) Starting from a DSP cell that
|
||||||
|
// (a) CDIN_FDBK_SEL is set to default "00"
|
||||||
|
// (b) doesn't already use the 'PCOUT' port
|
||||||
|
// (2) Match another DSP cell that
|
||||||
|
// (a) does not have the CREG enabled,
|
||||||
|
// (b) 'C' port is driven by the 'P' output of the previous DSP cell
|
||||||
|
// (c) has its 'PCIN' port unused
|
||||||
|
// (3) Recursively go to (2) until no more matches possible, keeping track
|
||||||
|
// of the longest possible chain found
|
||||||
|
// (4) The longest chain is then divided into chunks of no more than
|
||||||
|
// MAX_DSP_CASCADE in length (to prevent long cascades that exceed the
|
||||||
|
// height of a DSP column) with each DSP in each chunk being rewritten
|
||||||
|
// to use [ABP]COUT -> [ABP]CIN cascading as appropriate
|
||||||
|
|
||||||
|
pattern microchip_dsp_cascade
|
||||||
|
|
||||||
|
udata <std::function<SigSpec(const SigSpec&)>> unextend
|
||||||
|
udata <vector<std::tuple<Cell*,int>>> chain longest_chain
|
||||||
|
udata <std::set<Cell*>> visited
|
||||||
|
state <Cell*> next
|
||||||
|
state <SigSpec> clock
|
||||||
|
|
||||||
|
// Variables used for subpatterns
|
||||||
|
state <SigSpec> argQ argD
|
||||||
|
state <int> ffoffset
|
||||||
|
udata <SigSpec> dffD dffQ
|
||||||
|
udata <SigBit> dffclock
|
||||||
|
udata <Cell*> dff
|
||||||
|
|
||||||
|
// Maximum of 24 cascaded blocks
|
||||||
|
code
|
||||||
|
#define MAX_DSP_CASCADE 24
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// NOTE: Chain vector
|
||||||
|
// +--------+ +--------+
|
||||||
|
// | first |----> | next | ----> ...
|
||||||
|
// +--------+ +--------+
|
||||||
|
// first.COUT cascades to next.CIN, so on and so forth
|
||||||
|
|
||||||
|
// Helper function to remove unused bits
|
||||||
|
code
|
||||||
|
unextend = [](const SigSpec &sig) {
|
||||||
|
int i;
|
||||||
|
for (i = GetSize(sig)-1; i > 0; i--)
|
||||||
|
if (sig[i] != sig[i-1])
|
||||||
|
break;
|
||||||
|
// Do not remove non-const sign bit
|
||||||
|
if (sig[i].wire)
|
||||||
|
++i;
|
||||||
|
return sig.extract(0, i);
|
||||||
|
};
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (1) Starting from a DSP cell that
|
||||||
|
// (a) CDIN_FDBK_SEL is set to default "00"
|
||||||
|
// (b) doesn't already use the 'PCOUT' port
|
||||||
|
match first
|
||||||
|
select first->type.in(\MACC_PA) && port(first, \CDIN_FDBK_SEL, Const(0, 2)) == Const::from_string("00")
|
||||||
|
select nusers(port(first, \CDOUT, SigSpec())) <= 1
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
// (4) The longest chain is then divided into chunks of no more than
|
||||||
|
// MAX_DSP_CASCADE in length (to prevent long cascades that exceed the
|
||||||
|
// height of a DSP column) with each DSP in each chunk being rewritten
|
||||||
|
// to use [ABP]COUT -> [ABP]CIN cascading as appropriate
|
||||||
|
code
|
||||||
|
visited.clear();
|
||||||
|
visited.insert(first);
|
||||||
|
|
||||||
|
longest_chain.clear();
|
||||||
|
chain.emplace_back(first, -1);
|
||||||
|
subpattern(tail);
|
||||||
|
finally
|
||||||
|
|
||||||
|
// longest cascade chain has been found with DSP "first" being the head of the chain
|
||||||
|
// do some post processing
|
||||||
|
|
||||||
|
chain.pop_back();
|
||||||
|
visited.clear();
|
||||||
|
log_assert(chain.empty());
|
||||||
|
|
||||||
|
if (GetSize(longest_chain) > 1) {
|
||||||
|
Cell *dsp = std::get<0>(longest_chain.front());
|
||||||
|
|
||||||
|
Cell *dsp_pcin;
|
||||||
|
int SHIFT = -1;
|
||||||
|
for (int i = 1; i < GetSize(longest_chain); i++) {
|
||||||
|
log_assert(dsp->type.in(\MACC_PA));
|
||||||
|
|
||||||
|
std::tie(dsp_pcin,SHIFT) = longest_chain[i];
|
||||||
|
|
||||||
|
// Chain length exceeds the maximum cascade length, must split it up
|
||||||
|
if (i % MAX_DSP_CASCADE > 0) {
|
||||||
|
Wire *cascade = module->addWire(NEW_ID, 48);
|
||||||
|
|
||||||
|
// zero port C and move wire to cascade
|
||||||
|
dsp_pcin->setPort(ID(C), Const(0, 48));
|
||||||
|
dsp_pcin->setPort(ID(CDIN), cascade);
|
||||||
|
dsp->setPort(ID(CDOUT), cascade);
|
||||||
|
|
||||||
|
// Configure wire to cascade the dsps
|
||||||
|
add_siguser(cascade, dsp_pcin);
|
||||||
|
add_siguser(cascade, dsp);
|
||||||
|
|
||||||
|
// configure mux to use cascade for signal E
|
||||||
|
SigSpec cdin_fdbk_sel = port(dsp_pcin, \CDIN_FDBK_SEL, Const(0, 2));
|
||||||
|
cdin_fdbk_sel[1] = State::S1;
|
||||||
|
dsp_pcin->setPort(\CDIN_FDBK_SEL, cdin_fdbk_sel);
|
||||||
|
|
||||||
|
// check if shifting is required for wide multiplier implmentation
|
||||||
|
if (SHIFT == 17)
|
||||||
|
{
|
||||||
|
dsp_pcin->setPort(\ARSHFT17, State::S1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
log_debug("PCOUT -> PCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
log_debug(" Blocking %s -> %s cascade (exceeds max: %d)\n", log_id(dsp), log_id(dsp_pcin), MAX_DSP_CASCADE);
|
||||||
|
}
|
||||||
|
|
||||||
|
dsp = dsp_pcin;
|
||||||
|
}
|
||||||
|
|
||||||
|
accept;
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
subpattern tail
|
||||||
|
arg first
|
||||||
|
arg next
|
||||||
|
|
||||||
|
// (2) Match another DSP cell that
|
||||||
|
// (a) does not have the CREG enabled,
|
||||||
|
// (b) 'C' port is driven by the 'P' output of the previous DSP cell
|
||||||
|
// (c) has its 'PCIN' port unused
|
||||||
|
match nextP
|
||||||
|
// find candidates where nextP.C port is driven (maybe partially) by chain's tail DSP.P port
|
||||||
|
// and with no registers in between (since cascade path cannot be pipelined)
|
||||||
|
|
||||||
|
// reg C must not be used
|
||||||
|
select port(nextP, \C_BYPASS, SigSpec()).is_fully_ones()
|
||||||
|
|
||||||
|
// must be same DSP type
|
||||||
|
select nextP->type.in(\MACC_PA)
|
||||||
|
|
||||||
|
// port C should be driven by something
|
||||||
|
select nusers(port(nextP, \C, SigSpec())) > 1
|
||||||
|
|
||||||
|
// CIN must be unused
|
||||||
|
select nusers(port(nextP, \PCIN, SigSpec())) == 0
|
||||||
|
|
||||||
|
// should not have internal feedback connection
|
||||||
|
select port(nextP, \CDIN_FDBK_SEL, SigSpec()).is_fully_zero()
|
||||||
|
|
||||||
|
// SHIFT should be unused
|
||||||
|
select port(nextP, \ARSHFT17_BYPASS).is_fully_ones()
|
||||||
|
select port(nextP, \ARSHFT17).is_fully_zero()
|
||||||
|
select nusers(port(nextP, \ARSHFT17, SigSpec())) == 0
|
||||||
|
|
||||||
|
// current DSP cell can be cascaded with the back of the cascade chain
|
||||||
|
// index <SigBit> port(nextP, \C)[0] === port(std::get<0>(chain.back()), \P)[0] || port(nextP, \C)[0] === port(std::get<0>(chain.back()), \P)[17]
|
||||||
|
filter port(nextP, \C)[0] == port(std::get<0>(chain.back()), \P)[0] || port(nextP, \C)[0] == port(std::get<0>(chain.back()), \P)[17]
|
||||||
|
|
||||||
|
// semioptional
|
||||||
|
|
||||||
|
optional
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code next
|
||||||
|
next = nextP;
|
||||||
|
|
||||||
|
// keep DSP type consistent in the chain
|
||||||
|
// currently since we only have one type anyways, this line is always false
|
||||||
|
if (next && next->type != first->type) reject;
|
||||||
|
|
||||||
|
// break infinite recursion when there's a combinational loop
|
||||||
|
if (visited.count(next) > 0) reject;
|
||||||
|
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (3) Recursively go to (2) until no more matches possible, recording the
|
||||||
|
// longest possible chain
|
||||||
|
code
|
||||||
|
if (next) {
|
||||||
|
SigSpec driver_sigP = port(std::get<0>(chain.back()), \P);
|
||||||
|
int shift = 0;
|
||||||
|
if (port(next, \C)[0] == port(std::get<0>(chain.back()), \P)[17]) shift = 17;
|
||||||
|
|
||||||
|
chain.emplace_back(next, shift);
|
||||||
|
visited.insert(next);
|
||||||
|
|
||||||
|
SigSpec sigC = unextend(port(next, \C));
|
||||||
|
|
||||||
|
// Make sure driverDSP.P === DSP.C
|
||||||
|
if (GetSize(sigC) + shift <= GetSize(driver_sigP) && driver_sigP.extract(shift, GetSize(sigC)) == sigC)
|
||||||
|
{
|
||||||
|
subpattern(tail);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (GetSize(chain) > GetSize(longest_chain))
|
||||||
|
longest_chain = chain;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
if (next)
|
||||||
|
{
|
||||||
|
visited.erase(next);
|
||||||
|
chain.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
endcode
|
|
@ -0,0 +1,191 @@
|
||||||
|
# ISC License
|
||||||
|
#
|
||||||
|
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# LSRAM true dual-port
|
||||||
|
ram block $__LSRAM_TDP_ {
|
||||||
|
|
||||||
|
# Cost of a given cell is assumed to be:
|
||||||
|
# (cost-widthscale) + [widthscale * (used_bits/14)]
|
||||||
|
cost 129;
|
||||||
|
|
||||||
|
# INIT is supported
|
||||||
|
init any;
|
||||||
|
|
||||||
|
# port A and port B are allowed to have different widths, but they MUST have
|
||||||
|
# WIDTH values of the same set.
|
||||||
|
# Example: Port A has a Data Width of 1. Then Port B's Data Width must be either
|
||||||
|
# 1, 2, 4, 8, or 16 (both values are in the 'WIDTH_1' set).
|
||||||
|
# WIDTH_1 = {1, 2, 4, 8, 16}
|
||||||
|
# WIDTH_2 = {5, 10, 20}
|
||||||
|
|
||||||
|
# "byte" specifies how many data bits correspond to one write enable bit.
|
||||||
|
# "byte" must be larger than width, or width must be a multipler of "byte"
|
||||||
|
# if "byte" > WIDTH, a single enable wire is inferred
|
||||||
|
# otherwise, WIDTH/byte number of enable wires are inferred
|
||||||
|
#
|
||||||
|
# WIDTH = {1, 2, 4, 5, 8, 10} requires 1 enable wire
|
||||||
|
# WIDTH = {16, 20} requires 2 enable wire
|
||||||
|
|
||||||
|
option "WIDTH_CONFIG" "REGULAR" {
|
||||||
|
|
||||||
|
# Data-Width| Address bits
|
||||||
|
# 1 | 14
|
||||||
|
# 2 | 13
|
||||||
|
# 4 | 12
|
||||||
|
# 8 | 11
|
||||||
|
# 16 | 10
|
||||||
|
|
||||||
|
# 14 address bits
|
||||||
|
abits 14;
|
||||||
|
|
||||||
|
widths 1 2 4 8 16 per_port;
|
||||||
|
byte 8;
|
||||||
|
}
|
||||||
|
option "WIDTH_CONFIG" "ALIGN" {
|
||||||
|
|
||||||
|
# Data-Width| Address bits
|
||||||
|
# 5 | 12
|
||||||
|
# 10 | 11
|
||||||
|
# 20 | 10
|
||||||
|
|
||||||
|
# Quick "hack" to fix address bit alignment by setting address bits to 12.
|
||||||
|
# If abits=14, tool will think there are 14 bits for width=5, 13 bits for width=10, 12 bits for width=20
|
||||||
|
# THe LSRAM_map.v file detects if this option is being used, and adjusts the address port alignments accordingly.
|
||||||
|
abits 12;
|
||||||
|
|
||||||
|
widths 5 10 20 per_port;
|
||||||
|
byte 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
port srsw "A" "B" {
|
||||||
|
|
||||||
|
# read & write width must be same
|
||||||
|
width tied;
|
||||||
|
|
||||||
|
# clock polarity is rising
|
||||||
|
clock posedge;
|
||||||
|
|
||||||
|
# A/B read-enable
|
||||||
|
rden;
|
||||||
|
|
||||||
|
|
||||||
|
# initial value of read port data (not supported)
|
||||||
|
rdinit none;
|
||||||
|
|
||||||
|
# write modes (<A/B>_WMODE)
|
||||||
|
# 1. Simple Write: read-data port holds prev value (similar to "NO_CHANGE" for RAMB18E1)
|
||||||
|
# 2. Feed-through: read-data port takes new write value (similar to "WRITE_FIRST" for RAMB18E1)
|
||||||
|
# 3. Read-Before-Write: read-data port holds old value while being written (similar to "READ_FIRST" for RAMB18E1)
|
||||||
|
|
||||||
|
portoption "WRITE_MODE" "NO_CHANGE" {
|
||||||
|
|
||||||
|
# Read-write interaction
|
||||||
|
rdwr no_change;
|
||||||
|
|
||||||
|
# Write transparency:
|
||||||
|
# For write ports, define behaviour when another synchronous read port
|
||||||
|
# reads from the same memory cell that said write port is writing to at the same time.
|
||||||
|
wrtrans all old;
|
||||||
|
}
|
||||||
|
portoption "WRITE_MODE" "WRITE_FIRST" {
|
||||||
|
# bits corresponding to high A/B_WEN are updated
|
||||||
|
rdwr new_only;
|
||||||
|
wrtrans all new;
|
||||||
|
}
|
||||||
|
portoption "WRITE_MODE" "READ_FIRST" {
|
||||||
|
rdwr old;
|
||||||
|
|
||||||
|
wrtrans all old;
|
||||||
|
}
|
||||||
|
|
||||||
|
# generate params to indicate if read or write is used for each port
|
||||||
|
optional_rw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# two-port configuration
|
||||||
|
ram block $__LSRAM_SDP_ {
|
||||||
|
|
||||||
|
# since two-port configuration is dedicated for wide-read/write,
|
||||||
|
# we want to prioritize this configuration over TDP to avoid tool picking multiple TDP RAMs
|
||||||
|
# inplace of a single SDP RAM for wide read/write. This means the cost of a single SDP should
|
||||||
|
# be less than 2 TDP.
|
||||||
|
cost 129;
|
||||||
|
init any;
|
||||||
|
|
||||||
|
option "WIDTH_CONFIG" "REGULAR" {
|
||||||
|
|
||||||
|
# Data-Width| Address bits
|
||||||
|
# 1 | 14
|
||||||
|
# 2 | 13
|
||||||
|
# 4 | 12
|
||||||
|
# 8 | 11
|
||||||
|
# 16 | 10
|
||||||
|
# 32 | 9
|
||||||
|
|
||||||
|
abits 14;
|
||||||
|
|
||||||
|
widths 1 2 4 8 16 32 per_port;
|
||||||
|
|
||||||
|
# width = 32, byte-write size is 8, ignore other widths
|
||||||
|
byte 8;
|
||||||
|
|
||||||
|
}
|
||||||
|
option "WIDTH_CONFIG" "ALIGN" {
|
||||||
|
|
||||||
|
# Data-Width| Address bits
|
||||||
|
# 5 | 12
|
||||||
|
# 10 | 11
|
||||||
|
# 20 | 10
|
||||||
|
# 40 | 9
|
||||||
|
|
||||||
|
# Same trick as TSP RAM for alignment
|
||||||
|
abits 12;
|
||||||
|
widths 5 10 20 40 per_port;
|
||||||
|
byte 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
port sw "W" {
|
||||||
|
|
||||||
|
# only consider wide write
|
||||||
|
|
||||||
|
option "WIDTH_CONFIG" "REGULAR" width 32;
|
||||||
|
option "WIDTH_CONFIG" "ALIGN" width 40;
|
||||||
|
|
||||||
|
clock posedge;
|
||||||
|
|
||||||
|
# only simple write supported for two-port mode
|
||||||
|
wrtrans all old;
|
||||||
|
|
||||||
|
optional;
|
||||||
|
}
|
||||||
|
port sr "R" {
|
||||||
|
|
||||||
|
option "WIDTH_CONFIG" "REGULAR" width 32;
|
||||||
|
option "WIDTH_CONFIG" "ALIGN" width 40;
|
||||||
|
|
||||||
|
|
||||||
|
clock posedge;
|
||||||
|
rden;
|
||||||
|
rdinit none;
|
||||||
|
optional;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,320 @@
|
||||||
|
/*
|
||||||
|
ISC License
|
||||||
|
|
||||||
|
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// See document PolarFire Family Fabric User Guide
|
||||||
|
// section 4.1 for port list.
|
||||||
|
|
||||||
|
|
||||||
|
//LSRAM true dual-port
|
||||||
|
module $__LSRAM_TDP_ (...);
|
||||||
|
|
||||||
|
parameter INIT = 0;
|
||||||
|
parameter ADDR_BITS = 14;
|
||||||
|
|
||||||
|
parameter OPTION_WIDTH_CONFIG = "A";
|
||||||
|
|
||||||
|
parameter PORT_A_WIDTH = 1;
|
||||||
|
parameter PORT_A_WR_EN_WIDTH = 1;
|
||||||
|
parameter PORT_A_RD_USED = 0;
|
||||||
|
parameter PORT_A_WR_USED = 0;
|
||||||
|
parameter PORT_A_OPTION_WRITE_MODE = "NO_CHANGE";
|
||||||
|
|
||||||
|
parameter PORT_B_WIDTH = 1;
|
||||||
|
parameter PORT_B_WR_EN_WIDTH = 1;
|
||||||
|
parameter PORT_B_RD_USED = 0;
|
||||||
|
parameter PORT_B_WR_USED = 0;
|
||||||
|
parameter PORT_B_OPTION_WRITE_MODE = "NO_CHANGE";
|
||||||
|
|
||||||
|
|
||||||
|
input PORT_A_CLK;
|
||||||
|
input PORT_A_RD_EN;
|
||||||
|
input [ADDR_BITS-1:0] PORT_A_ADDR;
|
||||||
|
input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA;
|
||||||
|
input [PORT_A_WR_EN_WIDTH-1:0] PORT_A_WR_EN;
|
||||||
|
output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA;
|
||||||
|
|
||||||
|
|
||||||
|
input PORT_B_CLK;
|
||||||
|
input PORT_B_RD_EN;
|
||||||
|
input [ADDR_BITS-1:0] PORT_B_ADDR;
|
||||||
|
input [PORT_B_WIDTH-1:0] PORT_B_WR_DATA;
|
||||||
|
input [PORT_B_WR_EN_WIDTH-1:0] PORT_B_WR_EN;
|
||||||
|
output [PORT_B_WIDTH-1:0] PORT_B_RD_DATA;
|
||||||
|
|
||||||
|
|
||||||
|
`include "brams_defs.vh"
|
||||||
|
|
||||||
|
// address wires
|
||||||
|
wire [ADDR_BITS-1:0] A_address;
|
||||||
|
wire [ADDR_BITS-1:0] B_address;
|
||||||
|
assign A_address = (OPTION_WIDTH_CONFIG == "REGULAR") ? PORT_A_ADDR : {PORT_A_ADDR, 2'b00};
|
||||||
|
assign B_address = (OPTION_WIDTH_CONFIG == "REGULAR") ? PORT_B_ADDR : {PORT_B_ADDR, 2'b00};
|
||||||
|
|
||||||
|
// if port is not used, set block sel to 0 to disable it (read-data output is set to 0)
|
||||||
|
parameter PORT_A_RD_USED = 0;
|
||||||
|
parameter PORT_A_WR_USED = 0;
|
||||||
|
wire [2:0] A_BLK_SEL = (PORT_A_RD_USED == 1 || PORT_A_WR_USED == 1) ? 3'b111 : 3'b000;
|
||||||
|
wire [2:0] B_BLK_SEL = (PORT_B_RD_USED == 1 || PORT_B_WR_USED == 1) ? 3'b111 : 3'b000;
|
||||||
|
|
||||||
|
// wires for write data
|
||||||
|
generate
|
||||||
|
wire [19:0] A_write_data;
|
||||||
|
wire [19:0] B_write_data;
|
||||||
|
if (PORT_A_WIDTH == 16) begin
|
||||||
|
assign A_write_data[7:0] = PORT_A_WR_DATA[7:0];
|
||||||
|
assign A_write_data[17:10] = PORT_A_WR_DATA[15:8];
|
||||||
|
assign A_write_data[9:8] = 2'b0;
|
||||||
|
assign A_write_data[19:18] = 2'b0;
|
||||||
|
end else begin
|
||||||
|
assign A_write_data[PORT_A_WIDTH-1:0] = PORT_A_WR_DATA;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (PORT_B_WIDTH == 16) begin
|
||||||
|
assign B_write_data[7:0] = PORT_B_WR_DATA[7:0];
|
||||||
|
assign B_write_data[17:10] = PORT_B_WR_DATA[15:8];
|
||||||
|
assign B_write_data[9:8] = 2'b0;
|
||||||
|
assign B_write_data[19:18] = 2'b0;
|
||||||
|
end else begin
|
||||||
|
assign B_write_data[PORT_B_WIDTH-1:0] = PORT_B_WR_DATA;
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
// wires for read data
|
||||||
|
wire [19:0] A_read_data;
|
||||||
|
assign PORT_A_RD_DATA = A_read_data[PORT_A_WIDTH-1:0];
|
||||||
|
wire [19:0] B_read_data;
|
||||||
|
assign PORT_B_RD_DATA = B_read_data[PORT_B_WIDTH-1:0];
|
||||||
|
|
||||||
|
// byte-write enables
|
||||||
|
wire [1:0] A_write_EN = (PORT_A_WR_EN_WIDTH == 1) ? {1'b0, PORT_A_WR_EN} : PORT_A_WR_EN;
|
||||||
|
wire [1:0] B_write_EN = (PORT_B_WR_EN_WIDTH == 1) ? {1'b0, PORT_B_WR_EN} : PORT_B_WR_EN;
|
||||||
|
|
||||||
|
// port width
|
||||||
|
wire [2:0] A_width = (PORT_A_WIDTH == 1) ? 3'b000 :
|
||||||
|
(PORT_A_WIDTH == 2) ? 3'b001 :
|
||||||
|
(PORT_A_WIDTH == 4 || PORT_A_WIDTH == 5) ? 3'b010 :
|
||||||
|
(PORT_A_WIDTH == 8 || PORT_A_WIDTH == 10) ? 3'b011 : 3'b100;
|
||||||
|
wire [2:0] B_width = (PORT_B_WIDTH == 1) ? 3'b000 :
|
||||||
|
(PORT_B_WIDTH == 2) ? 3'b001 :
|
||||||
|
(PORT_B_WIDTH == 4 || PORT_B_WIDTH == 5) ? 3'b010 :
|
||||||
|
(PORT_B_WIDTH == 8 || PORT_B_WIDTH == 10) ? 3'b011 : 3'b100;
|
||||||
|
|
||||||
|
// write modes
|
||||||
|
wire [1:0] A_write_mode = PORT_A_OPTION_WRITE_MODE == "NO_CHANGE" ? 2'b00 :
|
||||||
|
PORT_A_OPTION_WRITE_MODE == "WRITE_FIRST" ? 2'b01 : 2'b10;
|
||||||
|
wire [1:0] B_write_mode = PORT_B_OPTION_WRITE_MODE == "NO_CHANGE" ? 2'b00 :
|
||||||
|
PORT_B_OPTION_WRITE_MODE == "WRITE_FIRST" ? 2'b01 : 2'b10;
|
||||||
|
|
||||||
|
RAM1K20 #(
|
||||||
|
`PARAMS_INIT_LSRAM
|
||||||
|
) _TECHMAP_REPLACE_ (
|
||||||
|
|
||||||
|
// port A
|
||||||
|
.A_ADDR(A_address),
|
||||||
|
.A_BLK_EN(A_BLK_SEL),
|
||||||
|
.A_CLK(PORT_A_CLK),
|
||||||
|
.A_DIN(A_write_data),
|
||||||
|
.A_DOUT(A_read_data),
|
||||||
|
.A_WEN(A_write_EN),
|
||||||
|
.A_REN(PORT_A_RD_EN),
|
||||||
|
.A_WIDTH(A_width),
|
||||||
|
.A_WMODE(A_write_mode),
|
||||||
|
.A_BYPASS(1'b1),
|
||||||
|
.A_DOUT_EN(1'b1),
|
||||||
|
.A_DOUT_SRST_N(1'b1),
|
||||||
|
.A_DOUT_ARST_N(1'b1),
|
||||||
|
|
||||||
|
// port B
|
||||||
|
.B_ADDR(B_address),
|
||||||
|
.B_BLK_EN(B_BLK_SEL),
|
||||||
|
.B_CLK(PORT_B_CLK),
|
||||||
|
.B_DIN(B_write_data),
|
||||||
|
.B_DOUT(B_read_data),
|
||||||
|
.B_WEN(B_write_EN),
|
||||||
|
.B_REN(PORT_B_RD_EN),
|
||||||
|
.B_WIDTH(B_width),
|
||||||
|
.B_WMODE(B_write_mode),
|
||||||
|
.B_BYPASS(1'b1),
|
||||||
|
.B_DOUT_EN(1'b1),
|
||||||
|
.B_DOUT_SRST_N(1'b1),
|
||||||
|
.B_DOUT_ARST_N(1'b1),
|
||||||
|
|
||||||
|
// Disable ECC for TDP
|
||||||
|
.ECC_EN(1'b0),
|
||||||
|
.ECC_BYPASS(1'b1),
|
||||||
|
.BUSY_FB(1'b0)
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// single dual port configuration
|
||||||
|
module $__LSRAM_SDP_ (...);
|
||||||
|
|
||||||
|
parameter INIT = 0;
|
||||||
|
parameter OPTION_WIDTH_CONFIG = "REGULAR";
|
||||||
|
parameter ADDR_BITS = 14;
|
||||||
|
|
||||||
|
parameter PORT_W_WIDTH = 1;
|
||||||
|
parameter PORT_W_WR_EN_WIDTH = 4;
|
||||||
|
parameter PORT_W_USED = 1;
|
||||||
|
|
||||||
|
parameter PORT_R_WIDTH = 1;
|
||||||
|
parameter PORT_R_USED = 0;
|
||||||
|
|
||||||
|
input PORT_W_CLK;
|
||||||
|
input [ADDR_BITS-1:0] PORT_W_ADDR;
|
||||||
|
input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
|
||||||
|
input [PORT_W_WR_EN_WIDTH-1:0] PORT_W_WR_EN;
|
||||||
|
|
||||||
|
input PORT_R_CLK;
|
||||||
|
input PORT_R_RD_EN;
|
||||||
|
input [ADDR_BITS-1:0] PORT_R_ADDR;
|
||||||
|
output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA;
|
||||||
|
input PORT_R_RD_SRST;
|
||||||
|
|
||||||
|
`include "brams_defs.vh"
|
||||||
|
|
||||||
|
|
||||||
|
// address wires
|
||||||
|
wire [ADDR_BITS-1:0] A_address;
|
||||||
|
wire [ADDR_BITS-1:0] B_address;
|
||||||
|
assign A_address = (OPTION_WIDTH_CONFIG == "REGULAR") ? PORT_R_ADDR : {PORT_R_ADDR, 2'b00};
|
||||||
|
assign B_address = (OPTION_WIDTH_CONFIG == "REGULAR") ? PORT_W_ADDR : {PORT_W_ADDR, 2'b00};
|
||||||
|
|
||||||
|
// if port is not used, set block sel to 0 to disable it (read-data output is set to 0)
|
||||||
|
// port A is for read, port B for write
|
||||||
|
parameter PORT_W_USED = 0;
|
||||||
|
parameter PORT_R_USED = 0;
|
||||||
|
wire [2:0] A_BLK_SEL = (PORT_R_USED == 1) ? 3'b111 : 3'b000;
|
||||||
|
wire [2:0] B_BLK_SEL = (PORT_W_USED == 1) ? 3'b111 : 3'b000;
|
||||||
|
|
||||||
|
// read/write data & write enables
|
||||||
|
// Currently support only wide write, width = {32, 40}
|
||||||
|
generate
|
||||||
|
wire [19:0] A_write_data;
|
||||||
|
wire [19:0] B_write_data;
|
||||||
|
wire [1:0] A_write_EN;
|
||||||
|
wire [1:0] B_write_EN;
|
||||||
|
|
||||||
|
// write port (A provides MSB)
|
||||||
|
if (PORT_W_WIDTH == 32) begin
|
||||||
|
|
||||||
|
assign B_write_data[3:0] = PORT_W_WR_DATA[3:0];
|
||||||
|
assign B_write_data[8:5] = PORT_W_WR_DATA[7:4];
|
||||||
|
assign B_write_data[13:10] = PORT_W_WR_DATA[11:8];
|
||||||
|
assign B_write_data[18:15] = PORT_W_WR_DATA[15:12];
|
||||||
|
assign B_write_data[4] = 1'b0;
|
||||||
|
assign B_write_data[9] = 1'b0;
|
||||||
|
assign B_write_data[14] = 1'b0;
|
||||||
|
assign B_write_data[19] = 1'b0;
|
||||||
|
|
||||||
|
assign A_write_data[3:0] = PORT_W_WR_DATA[19:16];
|
||||||
|
assign A_write_data[8:5] = PORT_W_WR_DATA[23:20];
|
||||||
|
assign A_write_data[13:10] = PORT_W_WR_DATA[27:24];
|
||||||
|
assign A_write_data[18:15] = PORT_W_WR_DATA[31:28];
|
||||||
|
assign A_write_data[4] = 1'b0;
|
||||||
|
assign A_write_data[9] = 1'b0;
|
||||||
|
assign A_write_data[14] = 1'b0;
|
||||||
|
assign A_write_data[19] = 1'b0;
|
||||||
|
|
||||||
|
end else if (PORT_W_WIDTH == 40) begin
|
||||||
|
assign B_write_data = PORT_W_WR_DATA[19:0];
|
||||||
|
assign A_write_data = PORT_W_WR_DATA[39:20];
|
||||||
|
end
|
||||||
|
|
||||||
|
// byte-write enables
|
||||||
|
assign A_write_EN = PORT_W_WR_EN[1:0];
|
||||||
|
assign B_write_EN = PORT_W_WR_EN[3:2];
|
||||||
|
|
||||||
|
// read ports (A provides MSB)
|
||||||
|
wire [19:0] A_read_data;
|
||||||
|
wire [19:0] B_read_data;
|
||||||
|
if (PORT_R_WIDTH == 32) begin
|
||||||
|
assign PORT_R_RD_DATA[3:0] = B_read_data[3:0];
|
||||||
|
assign PORT_R_RD_DATA[8:5] = B_read_data[7:4];
|
||||||
|
assign PORT_R_RD_DATA[13:10] = B_read_data[11:8];
|
||||||
|
assign PORT_R_RD_DATA[18:15] = B_read_data[15:12];
|
||||||
|
|
||||||
|
assign PORT_R_RD_DATA[19:16] = A_read_data[3:0];
|
||||||
|
assign PORT_R_RD_DATA[23:20] = A_read_data[8:5];
|
||||||
|
assign PORT_R_RD_DATA[27:24] = A_read_data[13:10];
|
||||||
|
assign PORT_R_RD_DATA[31:28] = A_read_data[18:15];
|
||||||
|
end else if (PORT_R_WIDTH == 40) begin
|
||||||
|
assign PORT_R_RD_DATA[19:0] = B_read_data[19:0];
|
||||||
|
assign PORT_R_RD_DATA[39:20] = A_read_data[19:0];
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
// port width
|
||||||
|
wire [2:0] A_width = (PORT_R_WIDTH == 1) ? 3'b000 :
|
||||||
|
(PORT_R_WIDTH == 2) ? 3'b001 :
|
||||||
|
(PORT_R_WIDTH == 4 || PORT_R_WIDTH == 5) ? 3'b010 :
|
||||||
|
(PORT_R_WIDTH == 8 || PORT_R_WIDTH == 10) ? 3'b011 :
|
||||||
|
(PORT_R_WIDTH == 16 || PORT_R_WIDTH == 20) ? 3'b100 : 3'b101;
|
||||||
|
wire [2:0] B_width = (PORT_W_WIDTH == 1) ? 3'b000 :
|
||||||
|
(PORT_W_WIDTH == 2) ? 3'b001 :
|
||||||
|
(PORT_W_WIDTH == 4 || PORT_W_WIDTH == 5) ? 3'b010 :
|
||||||
|
(PORT_W_WIDTH == 8 || PORT_W_WIDTH == 10) ? 3'b011 :
|
||||||
|
(PORT_W_WIDTH == 16 || PORT_W_WIDTH == 20) ? 3'b100 : 3'b101;
|
||||||
|
|
||||||
|
// write modes
|
||||||
|
wire [1:0] A_write_mode = 2'b00;
|
||||||
|
wire [1:0] B_write_mode = 2'b00;
|
||||||
|
|
||||||
|
RAM1K20 #(
|
||||||
|
`PARAMS_INIT_LSRAM
|
||||||
|
) _TECHMAP_REPLACE_ (
|
||||||
|
// port A - read
|
||||||
|
.A_ADDR(A_address),
|
||||||
|
.A_BLK_EN(A_BLK_SEL),
|
||||||
|
.A_CLK(PORT_R_CLK),
|
||||||
|
.A_DIN(A_write_data),
|
||||||
|
.A_DOUT(A_read_data),
|
||||||
|
.A_WEN(A_write_EN),
|
||||||
|
.A_REN(PORT_R_RD_EN),
|
||||||
|
.A_WIDTH(A_width),
|
||||||
|
.A_WMODE(A_write_mode),
|
||||||
|
.A_BYPASS(1'b1),
|
||||||
|
.A_DOUT_EN(1'b1),
|
||||||
|
.A_DOUT_SRST_N(1'b1),
|
||||||
|
.A_DOUT_ARST_N(1'b1),
|
||||||
|
|
||||||
|
// port B - write
|
||||||
|
.B_ADDR(B_address),
|
||||||
|
.B_BLK_EN(B_BLK_SEL),
|
||||||
|
.B_CLK(PORT_W_CLK),
|
||||||
|
.B_DIN(B_write_data),
|
||||||
|
.B_DOUT(B_read_data),
|
||||||
|
.B_WEN(B_write_EN),
|
||||||
|
.B_REN(PORT_R_RD_EN),
|
||||||
|
.B_WIDTH(B_width),
|
||||||
|
.B_WMODE(B_write_mode),
|
||||||
|
.B_BYPASS(1'b1),
|
||||||
|
.B_DOUT_EN(1'b1),
|
||||||
|
.B_DOUT_SRST_N(1'b1),
|
||||||
|
.B_DOUT_ARST_N(1'b1),
|
||||||
|
|
||||||
|
// Disable ECC for SDP
|
||||||
|
.ECC_EN(1'b0),
|
||||||
|
.ECC_BYPASS(1'b1),
|
||||||
|
.BUSY_FB(1'b0)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,31 @@
|
||||||
|
# ISC License
|
||||||
|
#
|
||||||
|
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
OBJS += techlibs/microchip/synth_microchip.o
|
||||||
|
OBJS += techlibs/microchip/microchip_dffopt.o
|
||||||
|
|
||||||
|
$(eval $(call add_share_file,share/microchip,techlibs/microchip/arith_map.v))
|
||||||
|
$(eval $(call add_share_file,share/microchip,techlibs/microchip/cells_map.v))
|
||||||
|
$(eval $(call add_share_file,share/microchip,techlibs/microchip/cells_sim.v))
|
||||||
|
$(eval $(call add_share_file,share/microchip,techlibs/microchip/polarfire_dsp_map.v))
|
||||||
|
|
||||||
|
$(eval $(call add_share_file,share/microchip,techlibs/microchip/brams_defs.vh))
|
||||||
|
$(eval $(call add_share_file,share/microchip,techlibs/microchip/LSRAM_map.v))
|
||||||
|
$(eval $(call add_share_file,share/microchip,techlibs/microchip/LSRAM.txt))
|
||||||
|
$(eval $(call add_share_file,share/microchip,techlibs/microchip/uSRAM_map.v))
|
||||||
|
$(eval $(call add_share_file,share/microchip,techlibs/microchip/uSRAM.txt))
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
ISC License
|
||||||
|
|
||||||
|
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Based on Macro Library for PolarFire https://coredocs.s3.amazonaws.com/Libero/2021_2/Tool/pf_mlg.pdf
|
||||||
|
// NOTE: prefix module names with \$__ so that mapping prioritizes these cells over internal Yosys cells
|
||||||
|
|
||||||
|
|
||||||
|
(* techmap_celltype = "$_MUX4_" *)
|
||||||
|
module \$__microchip_MUX4_ (A, B, C, D, S, T, Y);
|
||||||
|
input A, B, C, D, S, T;
|
||||||
|
output Y;
|
||||||
|
MX4 _TECHMAP_REPLACE_.MUX4(.D3(D), .D2(C), .D1(B), .D0(A), .S1(T), .S0(S), .Y(Y));
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
(* techmap_celltype = "$reduce_xor" *)
|
||||||
|
module \$__microchip_XOR8_ (A, Y);
|
||||||
|
parameter A_SIGNED = 1;
|
||||||
|
parameter A_WIDTH = 8;
|
||||||
|
parameter Y_WIDTH = 1;
|
||||||
|
|
||||||
|
input [A_WIDTH-1:0] A;
|
||||||
|
output [Y_WIDTH-1:0] Y;
|
||||||
|
|
||||||
|
// check if mapping should proceed
|
||||||
|
generate
|
||||||
|
if (A_WIDTH != 8 || A_SIGNED || Y_WIDTH != 1) begin
|
||||||
|
wire _TECHMAP_FAIL_ = 1;
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
|
||||||
|
XOR8 _TECHMAP_REPLACE_.XOR8 (.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]), .E(A[4]), .F(A[5]), .G(A[6]), .H(A[7]), .Y(Y));
|
||||||
|
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
(* techmap_celltype = "$alu" *)
|
||||||
|
module \$__SF2_ALU (A, B, CI, BI, X, Y, CO);
|
||||||
|
parameter A_SIGNED = 0;
|
||||||
|
parameter B_SIGNED = 0;
|
||||||
|
parameter A_WIDTH = 1;
|
||||||
|
parameter B_WIDTH = 1;
|
||||||
|
parameter Y_WIDTH = 1;
|
||||||
|
|
||||||
|
(* force_downto *)
|
||||||
|
input [A_WIDTH-1:0] A;
|
||||||
|
(* force_downto *)
|
||||||
|
input [B_WIDTH-1:0] B;
|
||||||
|
(* force_downto *)
|
||||||
|
output [Y_WIDTH-1:0] X, Y;
|
||||||
|
|
||||||
|
input CI, BI;
|
||||||
|
(* force_downto *)
|
||||||
|
output [Y_WIDTH-1:0] CO;
|
||||||
|
|
||||||
|
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
|
||||||
|
|
||||||
|
(* force_downto *)
|
||||||
|
wire [Y_WIDTH-1:0] AA, BB;
|
||||||
|
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(AA));
|
||||||
|
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(BB));
|
||||||
|
|
||||||
|
(* force_downto *)
|
||||||
|
wire [Y_WIDTH-1:0] C = {CO, CI};
|
||||||
|
|
||||||
|
genvar i;
|
||||||
|
generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
|
||||||
|
ARI1 #(
|
||||||
|
// See section 1.4 of PolarFire Macro Library
|
||||||
|
|
||||||
|
// G = F1 = A[i] & (B[i]^BI)
|
||||||
|
// Y = F0 = A[i]^B[i]^BI
|
||||||
|
// P = Y
|
||||||
|
// ADCB
|
||||||
|
.INIT(20'b 01_11_0010_1000_1001_0110)
|
||||||
|
) carry (
|
||||||
|
.A(1'b0),
|
||||||
|
.B(AA[i]),
|
||||||
|
.C(BB[i]),
|
||||||
|
.D(BI),
|
||||||
|
.FCI(C[i]),
|
||||||
|
.Y(X[i]),
|
||||||
|
.S(Y[i]),
|
||||||
|
.FCO(CO[i])
|
||||||
|
);
|
||||||
|
end endgenerate
|
||||||
|
endmodule
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
ISC License
|
||||||
|
|
||||||
|
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`define PARAMS_INIT_LSRAM \
|
||||||
|
.INIT0(slice_init_LSRAM(00)), \
|
||||||
|
.INIT1(slice_init_LSRAM(01)), \
|
||||||
|
.INIT2(slice_init_LSRAM(02)), \
|
||||||
|
.INIT3(slice_init_LSRAM(03)), \
|
||||||
|
.INIT4(slice_init_LSRAM(04)), \
|
||||||
|
.INIT5(slice_init_LSRAM(05)), \
|
||||||
|
.INIT6(slice_init_LSRAM(06)), \
|
||||||
|
.INIT7(slice_init_LSRAM(07)), \
|
||||||
|
.INIT8(slice_init_LSRAM(08)), \
|
||||||
|
.INIT9(slice_init_LSRAM(09)), \
|
||||||
|
.INIT10(slice_init_LSRAM(10)), \
|
||||||
|
.INIT11(slice_init_LSRAM(11)), \
|
||||||
|
.INIT12(slice_init_LSRAM(12)), \
|
||||||
|
.INIT13(slice_init_LSRAM(13)), \
|
||||||
|
.INIT14(slice_init_LSRAM(14)), \
|
||||||
|
.INIT15(slice_init_LSRAM(15)), \
|
||||||
|
.INIT16(slice_init_LSRAM(16)), \
|
||||||
|
.INIT17(slice_init_LSRAM(17)), \
|
||||||
|
.INIT18(slice_init_LSRAM(18)), \
|
||||||
|
.INIT19(slice_init_LSRAM(19))
|
||||||
|
|
||||||
|
`define PARAMS_INIT_uSRAM \
|
||||||
|
.INIT0(slice_init_uSRAM(00)), \
|
||||||
|
.INIT1(slice_init_uSRAM(01)), \
|
||||||
|
.INIT2(slice_init_uSRAM(02)), \
|
||||||
|
.INIT3(slice_init_uSRAM(03)), \
|
||||||
|
.INIT4(slice_init_uSRAM(04)), \
|
||||||
|
.INIT5(slice_init_uSRAM(05)), \
|
||||||
|
.INIT6(slice_init_uSRAM(06)), \
|
||||||
|
.INIT7(slice_init_uSRAM(07)), \
|
||||||
|
.INIT8(slice_init_uSRAM(08)), \
|
||||||
|
.INIT9(slice_init_uSRAM(09)), \
|
||||||
|
.INIT10(slice_init_uSRAM(10)), \
|
||||||
|
.INIT11(slice_init_uSRAM(11)) \
|
||||||
|
|
||||||
|
// Helper function for initializing the LSRAM
|
||||||
|
function [1023:0] slice_init_LSRAM;
|
||||||
|
input integer slice_idx;
|
||||||
|
integer i;
|
||||||
|
for (i = 0; i < 1024; i = i + 1)
|
||||||
|
slice_init_LSRAM[i] = INIT[(slice_idx * 1024 + i)];
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
// Helper function for initializing the uSRAM
|
||||||
|
function [63:0] slice_init_uSRAM;
|
||||||
|
input integer slice_idx;
|
||||||
|
integer i;
|
||||||
|
for (i = 0; i < 64; i = i + 1)
|
||||||
|
slice_init_uSRAM[i] = INIT[(slice_idx * 64 + i)];
|
||||||
|
endfunction
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
ISC License
|
||||||
|
|
||||||
|
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// DFFs
|
||||||
|
module \$_DFFE_PN0P_ (input D, C, R, E, output Q);
|
||||||
|
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(E), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module \$_DFFE_PN1P_ (input D, C, R, E, output Q);
|
||||||
|
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(E), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// for sync set/reset registers, we can pass them into ABC9. So we need to follow the simplification idiom
|
||||||
|
// and map to intermediate cell types
|
||||||
|
module \$_SDFFCE_PN0P_ (input D, C, R, E, output Q);
|
||||||
|
MICROCHIP_SYNC_RESET_DFF _TECHMAP_REPLACE_ (.D(D), .CLK(C), .Reset(R), .En(E), .Q(Q));
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module \$_SDFFCE_PN1P_ (input D, C, R, E, output Q);
|
||||||
|
MICROCHIP_SYNC_SET_DFF _TECHMAP_REPLACE_ (.D(D), .CLK(C), .Set(R), .En(E), .Q(Q));
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
// LATCHES
|
||||||
|
|
||||||
|
module \$_DLATCH_PN0_ (input D, R, E, output Q);
|
||||||
|
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(E), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b1), .Q(Q));
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module \$_DLATCH_PN1_ (input D, R, E, output Q);
|
||||||
|
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(E), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b1), .Q(Q));
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module \$_DLATCH_P_ (input D, E, output Q);
|
||||||
|
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(E), .EN(1'b1), .ALn(1'b1), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b1), .Q(Q));
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// map intermediate flops to SLE
|
||||||
|
`ifdef FINAL_MAP
|
||||||
|
module MICROCHIP_SYNC_SET_DFF(
|
||||||
|
input D,
|
||||||
|
input CLK,
|
||||||
|
input Set,
|
||||||
|
input En,
|
||||||
|
output Q);
|
||||||
|
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(CLK), .EN(En), .ALn(1'b1), .ADn(1'b0), .SLn(Set), .SD(1'b1), .LAT(1'b0), .Q(Q));
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module MICROCHIP_SYNC_RESET_DFF(
|
||||||
|
input D,
|
||||||
|
input CLK,
|
||||||
|
input Reset,
|
||||||
|
input En,
|
||||||
|
output Q);
|
||||||
|
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(CLK), .EN(En), .ALn(1'b1), .ADn(1'b0), .SLn(Reset), .SD(1'b0), .LAT(1'b0), .Q(Q));
|
||||||
|
endmodule
|
||||||
|
`endif
|
||||||
|
|
||||||
|
|
||||||
|
// LUT
|
||||||
|
|
||||||
|
`ifndef NO_LUT
|
||||||
|
module \$lut (A, Y);
|
||||||
|
parameter WIDTH = 0;
|
||||||
|
parameter LUT = 0;
|
||||||
|
|
||||||
|
(* force_downto *)
|
||||||
|
input [WIDTH-1:0] A;
|
||||||
|
output Y;
|
||||||
|
|
||||||
|
generate
|
||||||
|
if (WIDTH == 1) begin
|
||||||
|
CFG1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0]));
|
||||||
|
end else
|
||||||
|
if (WIDTH == 2) begin
|
||||||
|
CFG2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0]), .B(A[1]));
|
||||||
|
end else
|
||||||
|
if (WIDTH == 3) begin
|
||||||
|
CFG3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0]), .B(A[1]), .C(A[2]));
|
||||||
|
end else
|
||||||
|
if (WIDTH == 4) begin
|
||||||
|
CFG4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
|
||||||
|
end else begin
|
||||||
|
wire _TECHMAP_FAIL_ = 1;
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
endmodule
|
||||||
|
`endif
|
||||||
|
|
|
@ -0,0 +1,719 @@
|
||||||
|
/*
|
||||||
|
ISC License
|
||||||
|
|
||||||
|
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Macro Library for PolarFire https://coredocs.s3.amazonaws.com/Libero/2021_2/Tool/pf_mlg.pdf
|
||||||
|
|
||||||
|
module AND2 (
|
||||||
|
input A, B,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A & B;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module AND3 (
|
||||||
|
input A, B, C,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A & B & C;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module AND4 (
|
||||||
|
input A, B, C, D,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A & B & C & D;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
(* abc9_lut=1 *)
|
||||||
|
module CFG1 (
|
||||||
|
output Y,
|
||||||
|
input A
|
||||||
|
);
|
||||||
|
parameter [1:0] INIT = 2'h0;
|
||||||
|
assign Y = INIT >> A;
|
||||||
|
specify
|
||||||
|
(A => Y) = 127;
|
||||||
|
endspecify
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
(* abc9_lut=1 *)
|
||||||
|
module CFG2 (
|
||||||
|
output Y,
|
||||||
|
input A,
|
||||||
|
input B
|
||||||
|
);
|
||||||
|
parameter [3:0] INIT = 4'h0;
|
||||||
|
assign Y = INIT >> {B, A};
|
||||||
|
specify
|
||||||
|
(A => Y) = 238;
|
||||||
|
(B => Y) = 127;
|
||||||
|
endspecify
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
(* abc9_lut=1 *)
|
||||||
|
module CFG3 (
|
||||||
|
output Y,
|
||||||
|
input A,
|
||||||
|
input B,
|
||||||
|
input C
|
||||||
|
);
|
||||||
|
parameter [7:0] INIT = 8'h0;
|
||||||
|
assign Y = INIT >> {C, B, A};
|
||||||
|
specify
|
||||||
|
(A => Y) = 407;
|
||||||
|
(B => Y) = 238;
|
||||||
|
(C => Y) = 127;
|
||||||
|
endspecify
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
(* abc9_lut=1 *)
|
||||||
|
module CFG4 (
|
||||||
|
output Y,
|
||||||
|
input A,
|
||||||
|
input B,
|
||||||
|
input C,
|
||||||
|
input D
|
||||||
|
);
|
||||||
|
parameter [15:0] INIT = 16'h0;
|
||||||
|
assign Y = INIT >> {D, C, B, A};
|
||||||
|
specify
|
||||||
|
(A => Y) = 472;
|
||||||
|
(B => Y) = 407;
|
||||||
|
(C => Y) = 238;
|
||||||
|
(D => Y) = 127;
|
||||||
|
endspecify
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module BUFF (
|
||||||
|
input A,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module BUFD (
|
||||||
|
input A,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module CLKINT (
|
||||||
|
input A,
|
||||||
|
(* clkbuf_driver *)
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module CLKINT_PRESERVE (
|
||||||
|
input A,
|
||||||
|
(* clkbuf_driver *)
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module GCLKINT (
|
||||||
|
input A, EN,
|
||||||
|
(* clkbuf_driver *)
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A & EN;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module RCLKINT (
|
||||||
|
input A,
|
||||||
|
(* clkbuf_driver *)
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module RGCLKINT (
|
||||||
|
input A, EN,
|
||||||
|
(* clkbuf_driver *)
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A & EN;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// sequential elements
|
||||||
|
|
||||||
|
// MICROCHIP_SYNC_SET_DFF and MICROCHIP_SYNC_RESET_DFF are intermediate cell types to implement the simplification idiom for abc9 flow
|
||||||
|
// see: https://yosyshq.readthedocs.io/projects/yosys/en/latest/yosys_internals/extending_yosys/abc_flow.html
|
||||||
|
|
||||||
|
(* abc9_flop, lib_whitebox *)
|
||||||
|
module MICROCHIP_SYNC_SET_DFF(
|
||||||
|
input D,
|
||||||
|
input CLK,
|
||||||
|
input Set,
|
||||||
|
input En,
|
||||||
|
output reg Q);
|
||||||
|
parameter [0:0] INIT = 1'b0; // unused
|
||||||
|
|
||||||
|
always @(posedge CLK) begin
|
||||||
|
if (En == 1) begin
|
||||||
|
if (Set == 0)
|
||||||
|
Q <= 1;
|
||||||
|
else
|
||||||
|
Q <= D;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
specify
|
||||||
|
$setup(D , posedge CLK &&& En && Set, 0); // neg setup not supported?
|
||||||
|
$setup(En, posedge CLK, 109);
|
||||||
|
$setup(Set, posedge CLK &&& En, 404);
|
||||||
|
if (En && !Set) (posedge CLK => (Q : 1'b1)) = 303;
|
||||||
|
if (En && Set) (posedge CLK => (Q : D)) = 303;
|
||||||
|
endspecify
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
(* abc9_flop, lib_whitebox *)
|
||||||
|
module MICROCHIP_SYNC_RESET_DFF(
|
||||||
|
input D,
|
||||||
|
input CLK,
|
||||||
|
input Reset,
|
||||||
|
input En,
|
||||||
|
output reg Q);
|
||||||
|
parameter [0:0] INIT = 1'b0; // unused
|
||||||
|
|
||||||
|
always @(posedge CLK) begin
|
||||||
|
if (En == 1) begin
|
||||||
|
if (Reset == 0)
|
||||||
|
Q <= 0;
|
||||||
|
else
|
||||||
|
Q <= D;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
specify
|
||||||
|
$setup(D , posedge CLK &&& En && Reset, 0); // neg setup not supported?
|
||||||
|
$setup(En, posedge CLK, 109);
|
||||||
|
$setup(Reset, posedge CLK &&& En, 404);
|
||||||
|
if (En && !Reset) (posedge CLK => (Q : 1'b0)) = 303;
|
||||||
|
if (En && Reset) (posedge CLK => (Q : D)) = 303;
|
||||||
|
endspecify
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module SLE (
|
||||||
|
output Q,
|
||||||
|
input ADn,
|
||||||
|
input ALn,
|
||||||
|
(* clkbuf_sink *)
|
||||||
|
input CLK,
|
||||||
|
input D,
|
||||||
|
input LAT,
|
||||||
|
input SD,
|
||||||
|
input EN,
|
||||||
|
input SLn
|
||||||
|
);
|
||||||
|
reg q_latch, q_ff;
|
||||||
|
|
||||||
|
always @(posedge CLK, negedge ALn) begin
|
||||||
|
if (!ALn) begin
|
||||||
|
q_ff <= !ADn;
|
||||||
|
end else if (EN) begin
|
||||||
|
if (!SLn)
|
||||||
|
q_ff <= SD;
|
||||||
|
else
|
||||||
|
q_ff <= D;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always @* begin
|
||||||
|
if (!ALn) begin
|
||||||
|
q_latch <= !ADn;
|
||||||
|
end else if (CLK && EN) begin
|
||||||
|
if (!SLn)
|
||||||
|
q_ff <= SD;
|
||||||
|
else
|
||||||
|
q_ff <= D;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign Q = LAT ? q_latch : q_ff;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
(* abc9_box, lib_whitebox *)
|
||||||
|
module ARI1 (
|
||||||
|
(* abc9_carry *)
|
||||||
|
input FCI,
|
||||||
|
(* abc9_carry *)
|
||||||
|
output FCO,
|
||||||
|
|
||||||
|
input A, B, C, D,
|
||||||
|
output Y, S
|
||||||
|
);
|
||||||
|
parameter [19:0] INIT = 20'h0;
|
||||||
|
wire [2:0] Fsel = {D, C, B};
|
||||||
|
wire F0 = INIT[Fsel];
|
||||||
|
wire F1 = INIT[8 + Fsel];
|
||||||
|
wire Yout = A ? F1 : F0;
|
||||||
|
assign Y = Yout;
|
||||||
|
assign S = FCI ^ Yout;
|
||||||
|
wire G = INIT[16] ? (INIT[17] ? F1 : F0) : INIT[17];
|
||||||
|
wire P = INIT[19] ? 1'b1 : (INIT[18] ? Yout : 1'b0);
|
||||||
|
assign FCO = P ? FCI : G;
|
||||||
|
|
||||||
|
specify
|
||||||
|
//pin to pin path delay
|
||||||
|
(A => Y ) = 472;
|
||||||
|
(B => Y ) = 407;
|
||||||
|
(C => Y ) = 238;
|
||||||
|
(D => Y ) = 127;
|
||||||
|
(A => S ) = 572;
|
||||||
|
(B => S ) = 507;
|
||||||
|
(C => S ) = 338;
|
||||||
|
(D => S ) = 227;
|
||||||
|
(FCI => S ) = 100;
|
||||||
|
(A => FCO ) = 522;
|
||||||
|
(B => FCO ) = 457;
|
||||||
|
(C => FCO ) = 288;
|
||||||
|
(D => FCO ) = 177;
|
||||||
|
(FCI => FCO ) = 50;
|
||||||
|
endspecify
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
(* blackbox *)
|
||||||
|
module GCLKBUF (
|
||||||
|
(* iopad_external_pin *)
|
||||||
|
input PAD,
|
||||||
|
input EN,
|
||||||
|
(* clkbuf_driver *)
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
(* blackbox *)
|
||||||
|
module GCLKBUF_DIFF (
|
||||||
|
(* iopad_external_pin *)
|
||||||
|
input PADP,
|
||||||
|
(* iopad_external_pin *)
|
||||||
|
input PADN,
|
||||||
|
input EN,
|
||||||
|
(* clkbuf_driver *)
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module INV (
|
||||||
|
input A,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = !A;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module INVD (
|
||||||
|
input A,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = !A;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module MX2 (
|
||||||
|
input A, B, S,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = S ? B : A;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module MX4 (
|
||||||
|
input D0, D1, D2, D3, S0, S1,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = S1 ? (S0 ? D3 : D2) : (S0 ? D1 : D0);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module NAND2 (
|
||||||
|
input A, B,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = !(A & B);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module NAND3 (
|
||||||
|
input A, B, C,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = !(A & B & C);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module NAND4 (
|
||||||
|
input A, B, C, D,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = !(A & B & C & D);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module NOR2 (
|
||||||
|
input A, B,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = !(A | B);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module NOR3 (
|
||||||
|
input A, B, C,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = !(A | B | C);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module NOR4 (
|
||||||
|
input A, B, C, D,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = !(A | B | C | D);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module OR2 (
|
||||||
|
input A, B,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A | B;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module OR3 (
|
||||||
|
input A, B, C,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A | B | C;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module OR4 (
|
||||||
|
input A, B, C, D,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A | B | C | D;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module XOR2 (
|
||||||
|
input A, B,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A ^ B;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module XOR3 (
|
||||||
|
input A, B, C,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A ^ B ^ C;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module XOR4 (
|
||||||
|
input A, B, C, D,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A ^ B ^ C ^ D;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module XOR8 (
|
||||||
|
input A, B, C, D, E, F, G, H,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A ^ B ^ C ^ D ^ E ^ F ^ G ^ H;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// module UJTAG
|
||||||
|
|
||||||
|
module BIBUF (
|
||||||
|
input D,
|
||||||
|
input E,
|
||||||
|
(* iopad_external_pin *)
|
||||||
|
inout PAD,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
parameter IOSTD = "";
|
||||||
|
assign PAD = E ? D : 1'bz;
|
||||||
|
assign Y = PAD;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
(* blackbox *)
|
||||||
|
module BIBUF_DIFF (
|
||||||
|
input D,
|
||||||
|
input E,
|
||||||
|
(* iopad_external_pin *)
|
||||||
|
inout PADP,
|
||||||
|
(* iopad_external_pin *)
|
||||||
|
inout PADN,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
parameter IOSTD = "";
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module CLKBIBUF (
|
||||||
|
input D,
|
||||||
|
input E,
|
||||||
|
(* iopad_external_pin *)
|
||||||
|
inout PAD,
|
||||||
|
(* clkbuf_driver *)
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
parameter IOSTD = "";
|
||||||
|
assign PAD = E ? D : 1'bz;
|
||||||
|
assign Y = PAD;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module CLKBUF (
|
||||||
|
(* iopad_external_pin *)
|
||||||
|
input PAD,
|
||||||
|
(* clkbuf_driver *)
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
parameter IOSTD = "";
|
||||||
|
assign Y = PAD;
|
||||||
|
specify
|
||||||
|
(PAD => Y) = 50;
|
||||||
|
endspecify
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
(* blackbox *)
|
||||||
|
module CLKBUF_DIFF (
|
||||||
|
(* iopad_external_pin *)
|
||||||
|
input PADP,
|
||||||
|
(* iopad_external_pin *)
|
||||||
|
input PADN,
|
||||||
|
(* clkbuf_driver *)
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
parameter IOSTD = "";
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module INBUF (
|
||||||
|
(* iopad_external_pin *)
|
||||||
|
input PAD,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
parameter IOSTD = "";
|
||||||
|
assign Y = PAD;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
(* blackbox *)
|
||||||
|
module INBUF_DIFF (
|
||||||
|
(* iopad_external_pin *)
|
||||||
|
input PADP,
|
||||||
|
(* iopad_external_pin *)
|
||||||
|
input PADN,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
parameter IOSTD = "";
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module OUTBUF (
|
||||||
|
input D,
|
||||||
|
(* iopad_external_pin *)
|
||||||
|
output PAD
|
||||||
|
);
|
||||||
|
parameter IOSTD = "";
|
||||||
|
assign PAD = D;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
(* blackbox *)
|
||||||
|
module OUTBUF_DIFF (
|
||||||
|
input D,
|
||||||
|
(* iopad_external_pin *)
|
||||||
|
output PADP,
|
||||||
|
(* iopad_external_pin *)
|
||||||
|
output PADN
|
||||||
|
);
|
||||||
|
parameter IOSTD = "";
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module TRIBUFF (
|
||||||
|
input D,
|
||||||
|
input E,
|
||||||
|
(* iopad_external_pin *)
|
||||||
|
output PAD
|
||||||
|
);
|
||||||
|
parameter IOSTD = "";
|
||||||
|
assign PAD = E ? D : 1'bz;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
(* blackbox *)
|
||||||
|
module TRIBUFF_DIFF (
|
||||||
|
input D,
|
||||||
|
input E,
|
||||||
|
(* iopad_external_pin *)
|
||||||
|
output PADP,
|
||||||
|
(* iopad_external_pin *)
|
||||||
|
output PADN
|
||||||
|
);
|
||||||
|
parameter IOSTD = "";
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
(* blackbox *)
|
||||||
|
module MACC_PA (
|
||||||
|
input DOTP,
|
||||||
|
input SIMD,
|
||||||
|
input OVFL_CARRYOUT_SEL,
|
||||||
|
input CLK,
|
||||||
|
input AL_N,
|
||||||
|
input [17:0] A,
|
||||||
|
input A_BYPASS,
|
||||||
|
input A_SRST_N,
|
||||||
|
input A_EN,
|
||||||
|
input [17:0] B,
|
||||||
|
input B_BYPASS,
|
||||||
|
input B_SRST_N,
|
||||||
|
input B_EN,
|
||||||
|
input [17:0] D,
|
||||||
|
input D_BYPASS,
|
||||||
|
input D_ARST_N,
|
||||||
|
input D_SRST_N,
|
||||||
|
input D_EN,
|
||||||
|
input CARRYIN,
|
||||||
|
input [47:0] C,
|
||||||
|
input C_BYPASS,
|
||||||
|
input C_ARST_N,
|
||||||
|
input C_SRST_N,
|
||||||
|
input C_EN,
|
||||||
|
input [47:0] CDIN,
|
||||||
|
output [47:0] P,
|
||||||
|
output OVFL_CARRYOUT,
|
||||||
|
input P_BYPASS,
|
||||||
|
input P_SRST_N,
|
||||||
|
input P_EN,
|
||||||
|
output [47:0] CDOUT,
|
||||||
|
input PASUB,
|
||||||
|
input PASUB_BYPASS,
|
||||||
|
input PASUB_AD_N,
|
||||||
|
input PASUB_SL_N,
|
||||||
|
input PASUB_SD_N,
|
||||||
|
input PASUB_EN,
|
||||||
|
input [1:0] CDIN_FDBK_SEL,
|
||||||
|
input CDIN_FDBK_SEL_BYPASS,
|
||||||
|
input [1:0] CDIN_FDBK_SEL_AD_N,
|
||||||
|
input CDIN_FDBK_SEL_SL_N,
|
||||||
|
input [1:0] CDIN_FDBK_SEL_SD_N,
|
||||||
|
input CDIN_FDBK_SEL_EN,
|
||||||
|
input ARSHFT17,
|
||||||
|
input ARSHFT17_BYPASS,
|
||||||
|
input ARSHFT17_AD_N,
|
||||||
|
input ARSHFT17_SL_N,
|
||||||
|
input ARSHFT17_SD_N,
|
||||||
|
input ARSHFT17_EN,
|
||||||
|
input SUB,
|
||||||
|
input SUB_BYPASS,
|
||||||
|
input SUB_AD_N,
|
||||||
|
input SUB_SL_N,
|
||||||
|
input SUB_SD_N,
|
||||||
|
input SUB_EN
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
(* blackbox *)
|
||||||
|
module RAM1K20 (
|
||||||
|
input [13:0] A_ADDR,
|
||||||
|
input [2:0] A_BLK_EN,
|
||||||
|
input A_CLK,
|
||||||
|
input [19:0] A_DIN,
|
||||||
|
output [19:0] A_DOUT,
|
||||||
|
input [1:0] A_WEN,
|
||||||
|
input A_REN,
|
||||||
|
input [2:0] A_WIDTH,
|
||||||
|
input [1:0] A_WMODE,
|
||||||
|
input A_BYPASS,
|
||||||
|
input A_DOUT_EN,
|
||||||
|
input A_DOUT_SRST_N,
|
||||||
|
input A_DOUT_ARST_N,
|
||||||
|
input [13:0] B_ADDR,
|
||||||
|
input [2:0] B_BLK_EN,
|
||||||
|
input B_CLK,
|
||||||
|
input [19:0] B_DIN,
|
||||||
|
output [19:0] B_DOUT,
|
||||||
|
input [1:0] B_WEN,
|
||||||
|
input B_REN,
|
||||||
|
input [2:0] B_WIDTH,
|
||||||
|
input [1:0] B_WMODE,
|
||||||
|
input B_BYPASS,
|
||||||
|
input B_DOUT_EN,
|
||||||
|
input B_DOUT_SRST_N,
|
||||||
|
input B_DOUT_ARST_N,
|
||||||
|
input ECC_EN,
|
||||||
|
input ECC_BYPASS,
|
||||||
|
output SB_CORRECT,
|
||||||
|
output DB_DETECT,
|
||||||
|
input BUSY_FB,
|
||||||
|
output ACCESS_BUSY
|
||||||
|
);
|
||||||
|
parameter INIT0 = 1024'h0;
|
||||||
|
parameter INIT1 = 1024'h0;
|
||||||
|
parameter INIT2 = 1024'h0;
|
||||||
|
parameter INIT3 = 1024'h0;
|
||||||
|
parameter INIT4 = 1024'h0;
|
||||||
|
parameter INIT5 = 1024'h0;
|
||||||
|
parameter INIT6 = 1024'h0;
|
||||||
|
parameter INIT7 = 1024'h0;
|
||||||
|
parameter INIT8 = 1024'h0;
|
||||||
|
parameter INIT9 = 1024'h0;
|
||||||
|
parameter INIT10 = 1024'h0;
|
||||||
|
parameter INIT11 = 1024'h0;
|
||||||
|
parameter INIT12 = 1024'h0;
|
||||||
|
parameter INIT13 = 1024'h0;
|
||||||
|
parameter INIT14 = 1024'h0;
|
||||||
|
parameter INIT15 = 1024'h0;
|
||||||
|
parameter INIT16 = 1024'h0;
|
||||||
|
parameter INIT17 = 1024'h0;
|
||||||
|
parameter INIT18 = 1024'h0;
|
||||||
|
parameter INIT19 = 1024'h0;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
(* blackbox *)
|
||||||
|
module RAM64x12 (
|
||||||
|
input R_CLK,
|
||||||
|
input [5:0] R_ADDR,
|
||||||
|
input R_ADDR_BYPASS,
|
||||||
|
input R_ADDR_EN,
|
||||||
|
input R_ADDR_SL_N,
|
||||||
|
input R_ADDR_SD,
|
||||||
|
input R_ADDR_AL_N,
|
||||||
|
input R_ADDR_AD_N,
|
||||||
|
input BLK_EN,
|
||||||
|
output [11:0] R_DATA,
|
||||||
|
input R_DATA_BYPASS,
|
||||||
|
input R_DATA_EN,
|
||||||
|
input R_DATA_SL_N,
|
||||||
|
input R_DATA_SD,
|
||||||
|
input R_DATA_AL_N,
|
||||||
|
input R_DATA_AD_N,
|
||||||
|
|
||||||
|
input W_CLK,
|
||||||
|
input [5:0] W_ADDR,
|
||||||
|
input [11:0]W_DATA,
|
||||||
|
input W_EN,
|
||||||
|
|
||||||
|
input BUSY_FB,
|
||||||
|
output ACCESS_BUSY
|
||||||
|
);
|
||||||
|
parameter INIT0 = 64'h0;
|
||||||
|
parameter INIT1 = 64'h0;
|
||||||
|
parameter INIT2 = 64'h0;
|
||||||
|
parameter INIT3 = 64'h0;
|
||||||
|
parameter INIT4 = 64'h0;
|
||||||
|
parameter INIT5 = 64'h0;
|
||||||
|
parameter INIT6 = 64'h0;
|
||||||
|
parameter INIT7 = 64'h0;
|
||||||
|
parameter INIT8 = 64'h0;
|
||||||
|
parameter INIT9 = 64'h0;
|
||||||
|
parameter INIT10 = 64'h0;
|
||||||
|
parameter INIT11 = 64'h0;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,343 @@
|
||||||
|
/*
|
||||||
|
ISC License
|
||||||
|
|
||||||
|
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kernel/sigtools.h"
|
||||||
|
#include "kernel/yosys.h"
|
||||||
|
|
||||||
|
USING_YOSYS_NAMESPACE
|
||||||
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
typedef std::pair<Const, std::vector<SigBit>> LutData;
|
||||||
|
|
||||||
|
// Compute a LUT implementing (select ^ select_inv) ? alt_data : data. Returns true if successful.
|
||||||
|
bool merge_lut(LutData &result, const LutData &data, const LutData select, bool select_inv, SigBit alt_data, int max_lut_size)
|
||||||
|
{
|
||||||
|
// First, gather input signals -- insert new signals at the beginning
|
||||||
|
// of the vector, so they don't disturb the likely-critical D LUT input
|
||||||
|
// timings.
|
||||||
|
result.second = data.second;
|
||||||
|
// D lut inputs initially start at 0.
|
||||||
|
int idx_data = 0;
|
||||||
|
// Now add the control input LUT inputs.
|
||||||
|
std::vector<int> idx_sel;
|
||||||
|
for (auto bit : select.second) {
|
||||||
|
int idx = -1;
|
||||||
|
for (int i = 0; i < GetSize(result.second); i++)
|
||||||
|
if (result.second[i] == bit)
|
||||||
|
idx = i;
|
||||||
|
if (idx == -1) {
|
||||||
|
idx = 0;
|
||||||
|
// Insert new signal at the beginning and bump all indices.
|
||||||
|
result.second.insert(result.second.begin(), bit);
|
||||||
|
idx_data++;
|
||||||
|
for (int &sidx : idx_sel)
|
||||||
|
sidx++;
|
||||||
|
}
|
||||||
|
idx_sel.push_back(idx);
|
||||||
|
}
|
||||||
|
// Insert the Q signal, if any, to the slowest input -- it will have
|
||||||
|
// no problem meeting timing.
|
||||||
|
// This is to emulate CLK_EN, where output data is retained
|
||||||
|
int idx_alt = -1;
|
||||||
|
if (alt_data.wire) {
|
||||||
|
// Check if we already have it.
|
||||||
|
for (int i = 0; i < GetSize(result.second); i++)
|
||||||
|
if (result.second[i] == alt_data)
|
||||||
|
idx_alt = i;
|
||||||
|
// If not, add it.
|
||||||
|
if (idx_alt == -1) {
|
||||||
|
idx_alt = 0;
|
||||||
|
result.second.insert(result.second.begin(), alt_data);
|
||||||
|
idx_data++;
|
||||||
|
for (int &sidx : idx_sel)
|
||||||
|
sidx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If LUT would be too large, bail.
|
||||||
|
if (GetSize(result.second) > max_lut_size)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Okay, we're doing it — compute the LUT mask.
|
||||||
|
result.first = Const(0, 1 << GetSize(result.second));
|
||||||
|
for (int i = 0; i < GetSize(result.first); i++) {
|
||||||
|
int sel_lut_idx = 0;
|
||||||
|
for (int j = 0; j < GetSize(select.second); j++)
|
||||||
|
if (i & 1 << idx_sel[j])
|
||||||
|
sel_lut_idx |= 1 << j;
|
||||||
|
bool select_val = (select.first.bits[sel_lut_idx] == State::S1);
|
||||||
|
bool new_bit;
|
||||||
|
if (select_val ^ select_inv) {
|
||||||
|
// Use alt_data.
|
||||||
|
if (alt_data.wire)
|
||||||
|
new_bit = (i & 1 << idx_alt) != 0;
|
||||||
|
else
|
||||||
|
new_bit = alt_data.data == State::S1;
|
||||||
|
} else {
|
||||||
|
// Use original LUT.
|
||||||
|
int lut_idx = i >> idx_data & ((1 << GetSize(data.second)) - 1);
|
||||||
|
new_bit = data.first.bits[lut_idx] == State::S1;
|
||||||
|
}
|
||||||
|
result.first.bits[i] = new_bit ? State::S1 : State::S0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MicrochipDffOptPass : public Pass {
|
||||||
|
MicrochipDffOptPass() : Pass("microchip_dffopt", "MICROCHIP: optimize FF control signal usage") {}
|
||||||
|
void help() override
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" microchip_dffopt [options] [selection]\n");
|
||||||
|
log("\n");
|
||||||
|
log("Converts hardware clock enable and set/reset signals on FFs to emulation\n");
|
||||||
|
log("using LUTs, if doing so would improve area. Operates on post-techmap LUT, DFF\n");
|
||||||
|
log("cells. \n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||||
|
{
|
||||||
|
log_header(design, "Executing MICROCHIP_DFFOPT pass (optimize FF control signal usage).\n");
|
||||||
|
|
||||||
|
size_t argidx = 1;
|
||||||
|
int max_lut_size = 4;
|
||||||
|
|
||||||
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
|
for (auto module : design->selected_modules()) {
|
||||||
|
log("Optimizing FFs in %s.\n", log_id(module));
|
||||||
|
|
||||||
|
SigMap sigmap(module);
|
||||||
|
dict<SigBit, pair<LutData, Cell *>> bit_to_lut;
|
||||||
|
dict<SigBit, int> bit_uses;
|
||||||
|
|
||||||
|
// Gather LUTs.
|
||||||
|
for (auto cell : module->selected_cells()) {
|
||||||
|
for (auto port : cell->connections())
|
||||||
|
for (auto bit : port.second)
|
||||||
|
bit_uses[sigmap(bit)]++;
|
||||||
|
if (cell->get_bool_attribute(ID::keep))
|
||||||
|
continue;
|
||||||
|
if (cell->type == ID(INV)) {
|
||||||
|
SigBit sigout = sigmap(cell->getPort(ID::Y));
|
||||||
|
SigBit sigin = sigmap(cell->getPort(ID::A));
|
||||||
|
bit_to_lut[sigout] = make_pair(LutData(Const(1, 2), {sigin}), cell); // INIT = 01
|
||||||
|
} else if (cell->type.in(ID(CFG1), ID(CFG2), ID(CFG3), ID(CFG4))) {
|
||||||
|
SigBit sigout = sigmap(cell->getPort(ID::Y));
|
||||||
|
const Const &init = cell->getParam(ID::INIT);
|
||||||
|
std::vector<SigBit> sigin;
|
||||||
|
sigin.push_back(sigmap(cell->getPort(ID(A))));
|
||||||
|
if (cell->type == ID(CFG1))
|
||||||
|
goto lut_sigin_done;
|
||||||
|
sigin.push_back(sigmap(cell->getPort(ID(B))));
|
||||||
|
if (cell->type == ID(CFG2))
|
||||||
|
goto lut_sigin_done;
|
||||||
|
sigin.push_back(sigmap(cell->getPort(ID(C))));
|
||||||
|
if (cell->type == ID(CFG3))
|
||||||
|
goto lut_sigin_done;
|
||||||
|
sigin.push_back(sigmap(cell->getPort(ID(D))));
|
||||||
|
|
||||||
|
lut_sigin_done:
|
||||||
|
bit_to_lut[sigout] = make_pair(LutData(init, sigin), cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto wire : module->wires())
|
||||||
|
if (wire->port_output || wire->port_input)
|
||||||
|
for (int i = 0; i < GetSize(wire); i++)
|
||||||
|
bit_uses[sigmap(SigBit(wire, i))]++;
|
||||||
|
|
||||||
|
// Iterate through FFs.
|
||||||
|
for (auto cell : module->selected_cells()) {
|
||||||
|
|
||||||
|
if (!cell->type.in(ID(SLE))) // not a SLE
|
||||||
|
continue;
|
||||||
|
if (cell->getPort(ID(LAT)).is_fully_ones()) // skip latch
|
||||||
|
continue;
|
||||||
|
if (cell->get_bool_attribute(ID::keep)) // keep attribute
|
||||||
|
continue;
|
||||||
|
if (!cell->getPort(ID(ALn)).is_fully_ones()) // async FF
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const bool hasSyncLoad = cell->getPort(ID(SLn)).is_wire();
|
||||||
|
const bool has_s = hasSyncLoad && cell->getPort(ID(SD)).is_fully_ones();
|
||||||
|
const bool has_r = hasSyncLoad && cell->getPort(ID(SD)).is_fully_zero();
|
||||||
|
|
||||||
|
// SLE cannot have both synchronous set and reset implemented at the same time
|
||||||
|
log_assert(!(has_s && has_r));
|
||||||
|
|
||||||
|
// Don't bother if D has more than one use.
|
||||||
|
SigBit sig_D = sigmap(cell->getPort(ID::D));
|
||||||
|
if (bit_uses[sig_D] > 2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Find the D LUT.
|
||||||
|
auto it_D = bit_to_lut.find(sig_D);
|
||||||
|
if (it_D == bit_to_lut.end())
|
||||||
|
continue;
|
||||||
|
LutData lut_d = it_D->second.first;
|
||||||
|
Cell *cell_d = it_D->second.second;
|
||||||
|
|
||||||
|
LutData lut_d_post_ce;
|
||||||
|
LutData lut_d_post_s;
|
||||||
|
LutData lut_d_post_r;
|
||||||
|
bool worthy_post_ce = false;
|
||||||
|
bool worthy_post_s = false;
|
||||||
|
bool worthy_post_r = false;
|
||||||
|
|
||||||
|
// First, unmap CE.
|
||||||
|
SigBit sig_Q = sigmap(cell->getPort(ID::Q));
|
||||||
|
SigBit sig_CE = sigmap(cell->getPort(ID(EN)));
|
||||||
|
LutData lut_ce = LutData(Const(2, 2), {sig_CE}); // INIT = 10
|
||||||
|
auto it_CE = bit_to_lut.find(sig_CE);
|
||||||
|
if (it_CE != bit_to_lut.end())
|
||||||
|
lut_ce = it_CE->second.first;
|
||||||
|
if (sig_CE.wire) {
|
||||||
|
// Merge CE LUT and D LUT into one. If it cannot be done, nothing to do about this FF.
|
||||||
|
if (!merge_lut(lut_d_post_ce, lut_d, lut_ce, true, sig_Q, max_lut_size))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If this gets rid of a CE LUT, it's worth it. If not, it still may be worth it, if we can remove set/reset
|
||||||
|
// as well.
|
||||||
|
if (it_CE != bit_to_lut.end())
|
||||||
|
worthy_post_ce = true;
|
||||||
|
} else if (sig_CE.data != State::S1) {
|
||||||
|
// Strange. Should not happen in a reasonable flow, so bail.
|
||||||
|
log_assert(false); // This DFF is always off
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
lut_d_post_ce = lut_d;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second, unmap S, if any.
|
||||||
|
lut_d_post_s = lut_d_post_ce;
|
||||||
|
if (has_s) {
|
||||||
|
SigBit sig_S = sigmap(cell->getPort(ID(SLn)));
|
||||||
|
LutData lut_s = LutData(Const(2, 2), {sig_S}); // INIT = 10
|
||||||
|
bool inv_s = true; // active low
|
||||||
|
auto it_S = bit_to_lut.find(sig_S);
|
||||||
|
if (it_S != bit_to_lut.end())
|
||||||
|
lut_s = it_S->second.first;
|
||||||
|
if (sig_S.wire) {
|
||||||
|
// Merge S LUT and D LUT into one. If it cannot be done, try to at least merge CE.
|
||||||
|
if (!merge_lut(lut_d_post_s, lut_d_post_ce, lut_s, inv_s, SigBit(State::S1), max_lut_size))
|
||||||
|
goto unmap;
|
||||||
|
// If this gets rid of an S LUT, it's worth it.
|
||||||
|
if (it_S != bit_to_lut.end())
|
||||||
|
worthy_post_s = true;
|
||||||
|
} else if (sig_S.data != (inv_s ? State::S1 : State::S0)) {
|
||||||
|
// Strange. Should not happen in a reasonable flow, so bail.
|
||||||
|
log_assert(false); // DFF is always in set mode
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Third, unmap R, if any.
|
||||||
|
lut_d_post_r = lut_d_post_s;
|
||||||
|
if (has_r) {
|
||||||
|
SigBit sig_R = sigmap(cell->getPort(ID(SLn)));
|
||||||
|
LutData lut_r = LutData(Const(2, 2), {sig_R}); // INIT = 10
|
||||||
|
bool inv_r = true; // active low
|
||||||
|
auto it_R = bit_to_lut.find(sig_R);
|
||||||
|
if (it_R != bit_to_lut.end())
|
||||||
|
lut_r = it_R->second.first;
|
||||||
|
if (sig_R.wire) {
|
||||||
|
// Merge R LUT and D LUT into one. If it cannot be done, try to at least merge CE/S.
|
||||||
|
if (!merge_lut(lut_d_post_r, lut_d_post_s, lut_r, inv_r, SigBit(State::S0), max_lut_size))
|
||||||
|
goto unmap;
|
||||||
|
// If this gets rid of an S LUT, it's worth it.
|
||||||
|
if (it_R != bit_to_lut.end())
|
||||||
|
worthy_post_r = true;
|
||||||
|
} else if (sig_R.data != (inv_r ? State::S1 : State::S0)) {
|
||||||
|
// Strange. Should not happen in a reasonable flow, so bail.
|
||||||
|
log_assert(false); // DFF is always in reset mode
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unmap:
|
||||||
|
|
||||||
|
// SLE cannot have both synchronous set and reset implemented at the same time
|
||||||
|
log_assert(!(worthy_post_r && worthy_post_s));
|
||||||
|
|
||||||
|
LutData final_lut;
|
||||||
|
if (worthy_post_r) {
|
||||||
|
final_lut = lut_d_post_r;
|
||||||
|
} else if (worthy_post_s) {
|
||||||
|
final_lut = lut_d_post_s;
|
||||||
|
} else if (worthy_post_ce) {
|
||||||
|
final_lut = lut_d_post_ce;
|
||||||
|
} else {
|
||||||
|
// Nothing to do here.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ports;
|
||||||
|
if (worthy_post_r)
|
||||||
|
ports += " + R";
|
||||||
|
if (worthy_post_s)
|
||||||
|
ports += " + S";
|
||||||
|
if (worthy_post_ce)
|
||||||
|
ports += " + CE";
|
||||||
|
log(" Merging D%s LUTs for %s/%s (%d -> %d)\n", ports.c_str(), log_id(cell), log_id(sig_Q.wire),
|
||||||
|
GetSize(lut_d.second), GetSize(final_lut.second));
|
||||||
|
|
||||||
|
// Okay, we're doing it. Unmap ports.
|
||||||
|
if ((has_s && worthy_post_s) || worthy_post_r) {
|
||||||
|
cell->setPort(ID(SLn), Const(1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we made it this far, clk enable is always merged into D
|
||||||
|
cell->setPort(ID(EN), Const(1, 1));
|
||||||
|
|
||||||
|
// Create the new LUT.
|
||||||
|
Cell *lut_cell = nullptr;
|
||||||
|
switch (GetSize(final_lut.second)) {
|
||||||
|
case 1:
|
||||||
|
lut_cell = module->addCell(NEW_ID, ID(CFG1));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
lut_cell = module->addCell(NEW_ID, ID(CFG2));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
lut_cell = module->addCell(NEW_ID, ID(CFG3));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
lut_cell = module->addCell(NEW_ID, ID(CFG4));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log_assert(!"unknown lut size");
|
||||||
|
}
|
||||||
|
lut_cell->attributes = cell_d->attributes;
|
||||||
|
Wire *lut_out = module->addWire(NEW_ID);
|
||||||
|
lut_cell->setParam(ID::INIT, final_lut.first);
|
||||||
|
cell->setPort(ID::D, lut_out);
|
||||||
|
lut_cell->setPort(ID::Y, lut_out);
|
||||||
|
lut_cell->setPort(ID(A), final_lut.second[0]);
|
||||||
|
if (GetSize(final_lut.second) >= 2)
|
||||||
|
lut_cell->setPort(ID(B), final_lut.second[1]);
|
||||||
|
if (GetSize(final_lut.second) >= 3)
|
||||||
|
lut_cell->setPort(ID(C), final_lut.second[2]);
|
||||||
|
if (GetSize(final_lut.second) >= 4)
|
||||||
|
lut_cell->setPort(ID(D), final_lut.second[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} MicrochipDffOptPass;
|
||||||
|
|
||||||
|
PRIVATE_NAMESPACE_END
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
ISC License
|
||||||
|
|
||||||
|
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y);
|
||||||
|
parameter A_SIGNED = 0;
|
||||||
|
parameter B_SIGNED = 0;
|
||||||
|
parameter A_WIDTH = 0;
|
||||||
|
parameter B_WIDTH = 0;
|
||||||
|
parameter Y_WIDTH = 0;
|
||||||
|
|
||||||
|
wire [47:0] P_48;
|
||||||
|
// For pin descriptions, see Section 9 of PolarFire FPGA Macro Library Guide:
|
||||||
|
// https://coredocs.s3.amazonaws.com/Libero/2021_2/Tool/pf_mlg.pdf
|
||||||
|
MACC_PA _TECHMAP_REPLACE_ (
|
||||||
|
.DOTP(1'b0),
|
||||||
|
.SIMD(1'b0),
|
||||||
|
.OVFL_CARRYOUT_SEL(1'b0),
|
||||||
|
|
||||||
|
.AL_N(1'b1),
|
||||||
|
.A(A),
|
||||||
|
.A_BYPASS(1'b1),
|
||||||
|
.A_SRST_N(1'b1),
|
||||||
|
.A_EN(1'b1),
|
||||||
|
|
||||||
|
.B(B),
|
||||||
|
.B_BYPASS(1'b1),
|
||||||
|
.B_SRST_N(1'b1),
|
||||||
|
.B_EN(1'b1),
|
||||||
|
|
||||||
|
.D(18'b0),
|
||||||
|
.D_BYPASS(1'b1),
|
||||||
|
.D_ARST_N(1'b1),
|
||||||
|
.D_SRST_N(1'b1),
|
||||||
|
.D_EN(1'b1),
|
||||||
|
|
||||||
|
.CARRYIN(1'b0),
|
||||||
|
.C(48'b0),
|
||||||
|
.C_BYPASS(1'b1),
|
||||||
|
.C_ARST_N(1'b1),
|
||||||
|
.C_SRST_N(1'b1),
|
||||||
|
.C_EN(1'b1),
|
||||||
|
|
||||||
|
|
||||||
|
.P(P_48),
|
||||||
|
|
||||||
|
.P_BYPASS(1'b1),
|
||||||
|
.P_SRST_N(1'b1),
|
||||||
|
.P_EN(1'b1),
|
||||||
|
|
||||||
|
.PASUB(1'b0),
|
||||||
|
.PASUB_BYPASS(1'b1),
|
||||||
|
.PASUB_AD_N(1'b0),
|
||||||
|
.PASUB_SL_N(1'b1),
|
||||||
|
.PASUB_SD_N(1'b0),
|
||||||
|
.PASUB_EN(1'b1),
|
||||||
|
|
||||||
|
.CDIN_FDBK_SEL(2'b00),
|
||||||
|
.CDIN_FDBK_SEL_BYPASS(1'b1),
|
||||||
|
.CDIN_FDBK_SEL_AD_N(2'b00),
|
||||||
|
.CDIN_FDBK_SEL_SL_N(1'b1),
|
||||||
|
.CDIN_FDBK_SEL_SD_N(2'b00),
|
||||||
|
.CDIN_FDBK_SEL_EN(1'b1),
|
||||||
|
|
||||||
|
.ARSHFT17(1'b0),
|
||||||
|
.ARSHFT17_BYPASS(1'b1),
|
||||||
|
.ARSHFT17_AD_N(1'b0),
|
||||||
|
.ARSHFT17_SL_N(1'b1),
|
||||||
|
.ARSHFT17_SD_N(1'b0),
|
||||||
|
.ARSHFT17_EN(1'b1),
|
||||||
|
|
||||||
|
.SUB(1'b0),
|
||||||
|
.SUB_BYPASS(1'b1),
|
||||||
|
.SUB_AD_N(1'b0),
|
||||||
|
.SUB_SL_N(1'b1),
|
||||||
|
.SUB_SD_N(1'b0),
|
||||||
|
.SUB_EN(1'b1)
|
||||||
|
|
||||||
|
);
|
||||||
|
assign Y = P_48;
|
||||||
|
endmodule
|
|
@ -0,0 +1,553 @@
|
||||||
|
/*
|
||||||
|
ISC License
|
||||||
|
|
||||||
|
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kernel/celltypes.h"
|
||||||
|
#include "kernel/log.h"
|
||||||
|
#include "kernel/register.h"
|
||||||
|
#include "kernel/rtlil.h"
|
||||||
|
|
||||||
|
USING_YOSYS_NAMESPACE
|
||||||
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
struct SynthMicrochipPass : public ScriptPass {
|
||||||
|
SynthMicrochipPass() : ScriptPass("synth_microchip", "synthesis for Microchip FPGAs") {}
|
||||||
|
|
||||||
|
void help() override
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" synth_microchip [options]\n");
|
||||||
|
log("\n");
|
||||||
|
log("This command runs synthesis for Microchip FPGAs. This command creates \n");
|
||||||
|
log("netlists that are compatible with Microchip PolarFire devices. \n");
|
||||||
|
log("\n");
|
||||||
|
log(" -top <module>\n");
|
||||||
|
log(" use the specified module as the top module\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -family <family>\n");
|
||||||
|
log(" Run synthesis for the specified Microchip architecture. \n");
|
||||||
|
log(" Generate the synthesis netlist for the specified family.\n");
|
||||||
|
log(" supported values:\n");
|
||||||
|
log(" - polarfire: PolarFire\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -edif <file>\n");
|
||||||
|
log(" Write the design to the specified edif file. Writing of an output file\n");
|
||||||
|
log(" is omitted if this parameter is not specified.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -blif <file>\n");
|
||||||
|
log(" Write the design to the specified BLIF file. Writing of an output file\n");
|
||||||
|
log(" is omitted if this parameter is not specified.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -vlog <file>\n");
|
||||||
|
log(" write the design to the specified Verilog file. writing of an output\n");
|
||||||
|
log(" file is omitted if this parameter is not specified.\n");
|
||||||
|
log(" -nobram\n");
|
||||||
|
log(" Do not use block RAM cells in output netlist\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -nocarry\n");
|
||||||
|
log(" Do not use ARI1 cells in output netlist\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -nodsp\n");
|
||||||
|
log(" Do not use MATH blocks to implement multipliers and associated logic\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -noiopad\n");
|
||||||
|
log(" Disable I/O buffer insertion (useful for hierarchical or \n");
|
||||||
|
log(" out-of-context flows)\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -noclkbuf\n");
|
||||||
|
log(" Disable automatic clock buffer insertion\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -run <from_label>:<to_label>\n");
|
||||||
|
log(" Only run the commands between the labels (see below). an empty\n");
|
||||||
|
log(" 'from_label' is synonymous to 'begin', and empty 'to_label' is\n");
|
||||||
|
log(" synonymous to the end of the command list.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -noflatten\n");
|
||||||
|
log(" do not flatten design before synthesis\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -dff\n");
|
||||||
|
log(" Run 'abc'/'abc9' with -dff option\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -retime\n");
|
||||||
|
log(" Run 'abc' with '-D 1' option to enable flip-flop retiming.\n");
|
||||||
|
log(" implies -dff.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -noabc9\n");
|
||||||
|
log(" Use classic ABC flow instead of ABC9\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -discard-ffinit\n");
|
||||||
|
log(" discard FF init value instead of emitting an error\n");
|
||||||
|
log("\n");
|
||||||
|
log("\n");
|
||||||
|
log("The following commands are executed by this synthesis command:\n");
|
||||||
|
help_script();
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string top_opt, edif_file, blif_file, vlog_file, family;
|
||||||
|
bool flatten, retime, noiopad, noclkbuf, nobram, nocarry, nowidelut, nodsp;
|
||||||
|
bool abc9, dff;
|
||||||
|
bool discard_ffinit;
|
||||||
|
int lut_size;
|
||||||
|
|
||||||
|
// debug dump switches
|
||||||
|
bool debug_memory, debug_carry;
|
||||||
|
|
||||||
|
void clear_flags() override
|
||||||
|
{
|
||||||
|
top_opt = "-auto-top";
|
||||||
|
edif_file.clear();
|
||||||
|
blif_file.clear();
|
||||||
|
vlog_file.clear();
|
||||||
|
family = "polarfire";
|
||||||
|
flatten = true;
|
||||||
|
retime = false;
|
||||||
|
noiopad = false;
|
||||||
|
noclkbuf = false;
|
||||||
|
nocarry = false;
|
||||||
|
nobram = false;
|
||||||
|
nowidelut = false;
|
||||||
|
nodsp = false;
|
||||||
|
abc9 = true;
|
||||||
|
dff = false;
|
||||||
|
lut_size = 4;
|
||||||
|
discard_ffinit = false;
|
||||||
|
|
||||||
|
debug_memory = false;
|
||||||
|
debug_carry = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||||
|
{
|
||||||
|
std::string run_from, run_to;
|
||||||
|
clear_flags();
|
||||||
|
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||||
|
if (args[argidx] == "-top" && argidx + 1 < args.size()) {
|
||||||
|
top_opt = "-top " + args[++argidx];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((args[argidx] == "-family" || args[argidx] == "-arch") && argidx + 1 < args.size()) {
|
||||||
|
family = args[++argidx];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-edif" && argidx + 1 < args.size()) {
|
||||||
|
edif_file = args[++argidx];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-blif" && argidx + 1 < args.size()) {
|
||||||
|
blif_file = args[++argidx];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-vlog" && argidx + 1 < args.size()) {
|
||||||
|
vlog_file = args[++argidx];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-run" && argidx + 1 < args.size()) {
|
||||||
|
size_t pos = args[argidx + 1].find(':');
|
||||||
|
if (pos == std::string::npos)
|
||||||
|
break;
|
||||||
|
run_from = args[++argidx].substr(0, pos);
|
||||||
|
run_to = args[argidx].substr(pos + 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-noflatten") {
|
||||||
|
flatten = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-retime") {
|
||||||
|
dff = true;
|
||||||
|
retime = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-nocarry") {
|
||||||
|
nocarry = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-nowidelut") {
|
||||||
|
nowidelut = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-iopad") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-noiopad") {
|
||||||
|
noiopad = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-noclkbuf") {
|
||||||
|
noclkbuf = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-nocarry") {
|
||||||
|
nocarry = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-nobram") {
|
||||||
|
nobram = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-noabc9") {
|
||||||
|
abc9 = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-nodsp") {
|
||||||
|
nodsp = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-dff") {
|
||||||
|
dff = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-debug_memory") {
|
||||||
|
debug_memory = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-debug_carry") {
|
||||||
|
debug_carry = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-discard-ffinit") {
|
||||||
|
discard_ffinit = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
|
if (family == "polarfire") {
|
||||||
|
lut_size = 4;
|
||||||
|
} else {
|
||||||
|
log_cmd_error("Invalid Microchip -family setting: '%s'.\n", family.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!design->full_selection())
|
||||||
|
log_cmd_error("This command only operates on fully selected designs!\n");
|
||||||
|
|
||||||
|
if (abc9 && retime)
|
||||||
|
log_cmd_error("-retime option not currently compatible with -abc9!\n");
|
||||||
|
|
||||||
|
log_header(design, "Executing SYNTH_MICROCHIP pass.\n");
|
||||||
|
log_push();
|
||||||
|
|
||||||
|
run_script(design, run_from, run_to);
|
||||||
|
|
||||||
|
log_pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void script() override
|
||||||
|
{
|
||||||
|
std::string lut_size_s = std::to_string(lut_size);
|
||||||
|
if (help_mode)
|
||||||
|
lut_size_s = "[4]";
|
||||||
|
|
||||||
|
if (check_label("begin")) {
|
||||||
|
std::string read_args;
|
||||||
|
read_args += " -lib -specify +/microchip/cells_sim.v";
|
||||||
|
run("read_verilog" + read_args);
|
||||||
|
|
||||||
|
run(stringf("hierarchy -check %s", top_opt.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_label("prepare")) {
|
||||||
|
run("proc");
|
||||||
|
if (flatten || help_mode)
|
||||||
|
run("flatten", "(with '-flatten')");
|
||||||
|
if (active_design)
|
||||||
|
active_design->scratchpad_unset("tribuf.added_something");
|
||||||
|
run("tribuf -logic");
|
||||||
|
if (noiopad && active_design && active_design->scratchpad_get_bool("tribuf.added_something"))
|
||||||
|
log_error("Tristate buffers are unsupported without the '-iopad' option.\n");
|
||||||
|
run("deminout");
|
||||||
|
run("opt_expr");
|
||||||
|
run("opt_clean");
|
||||||
|
run("check");
|
||||||
|
run("opt -nodffe -nosdff");
|
||||||
|
run("fsm");
|
||||||
|
run("opt");
|
||||||
|
|
||||||
|
run("wreduce");
|
||||||
|
run("peepopt");
|
||||||
|
run("opt_clean");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_label("map_dsp", "(skip if '-nodsp')")) {
|
||||||
|
if (!nodsp || help_mode) {
|
||||||
|
run("memory_dff"); // microchip_dsp will merge registers, reserve memory port registers first
|
||||||
|
if (help_mode)
|
||||||
|
run("techmap -map +/mul2dsp.v -map +/microchip/{family}_dsp_map.v {options}");
|
||||||
|
else if (family == "polarfire") // Microchip - map multipliers to DSP
|
||||||
|
run("techmap -map +/mul2dsp.v -map +/microchip/polarfire_dsp_map.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 "
|
||||||
|
"-D DSP_A_MAXWIDTH_PARTIAL=18 " // Partial multipliers are intentionally
|
||||||
|
// limited to 18x18 in order to take
|
||||||
|
// advantage of the (PCOUT >> 17) -> PCIN
|
||||||
|
// dedicated cascade chain capability
|
||||||
|
"-D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 " // Blocks Nx1 multipliers
|
||||||
|
"-D DSP_Y_MINWIDTH=9 "
|
||||||
|
"-D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL18X18");
|
||||||
|
|
||||||
|
run("select a:mul2dsp");
|
||||||
|
run("setattr -unset mul2dsp");
|
||||||
|
run("opt_expr -fine");
|
||||||
|
run("wreduce");
|
||||||
|
run("select -clear");
|
||||||
|
if (help_mode)
|
||||||
|
run("microchip_dsp -family <family>");
|
||||||
|
else if (family == "polarfire") // Microchip - absorb cells into DSP
|
||||||
|
run("microchip_dsp -family " + family);
|
||||||
|
|
||||||
|
run("chtype -set $mul t:$__soft_mul");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_label("coarse")) {
|
||||||
|
run("techmap -map +/cmp2lut.v -map +/cmp2lcu.v -D LUT_WIDTH=" + lut_size_s);
|
||||||
|
run("alumacc");
|
||||||
|
run("share");
|
||||||
|
run("opt");
|
||||||
|
run("memory -nomap");
|
||||||
|
run("opt_clean");
|
||||||
|
if (discard_ffinit || help_mode)
|
||||||
|
run("attrmap -remove init", "(only if -discard-ffinit)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_label("map_memory")) {
|
||||||
|
std::string params = "";
|
||||||
|
std::string LSRAM_map = "+/microchip/LSRAM_map.v";
|
||||||
|
std::string uSRAM_map = "+/microchip/uSRAM_map.v";
|
||||||
|
if (debug_memory)
|
||||||
|
run("write_verilog -noexpr memory_map_pre.vm");
|
||||||
|
if (help_mode) {
|
||||||
|
params = " [...]";
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (family == "polarfire") {
|
||||||
|
// cost of a single bit for memory lowered to soft logic
|
||||||
|
params += " -logic-cost-rom 0.015625";
|
||||||
|
|
||||||
|
params += " -lib +/microchip/LSRAM.txt";
|
||||||
|
params += " -lib +/microchip/uSRAM.txt";
|
||||||
|
LSRAM_map = "+/microchip/LSRAM_map.v";
|
||||||
|
uSRAM_map = "+/microchip/uSRAM_map.v";
|
||||||
|
}
|
||||||
|
if (nobram)
|
||||||
|
params += " -no-auto-block";
|
||||||
|
}
|
||||||
|
|
||||||
|
// transform memories into intermediate cells
|
||||||
|
// Cost based transformation. The cost is assigned by us for each cell.
|
||||||
|
run("memory_libmap" + params);
|
||||||
|
if (debug_memory)
|
||||||
|
run("write_verilog -noexpr memory_map_libmap.vm");
|
||||||
|
|
||||||
|
// map intermediate cells to actual RAM macros
|
||||||
|
// NOTE: order doesnt matter here
|
||||||
|
run("techmap -map " + LSRAM_map);
|
||||||
|
run("techmap -map " + uSRAM_map);
|
||||||
|
if (debug_memory)
|
||||||
|
run("write_verilog -noexpr memory_map_final.vm");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_label("map_ffram")) {
|
||||||
|
run("opt -fast -full");
|
||||||
|
|
||||||
|
// blast unmapped RAM to flops or LUTs
|
||||||
|
run("memory_map");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_label("fine")) {
|
||||||
|
run("opt -full");
|
||||||
|
|
||||||
|
if (debug_carry)
|
||||||
|
run("write_verilog -noexpr ARI1_cells.vm");
|
||||||
|
|
||||||
|
if (!nocarry) {
|
||||||
|
// converts $mux -> $_MUX_ to allow muxcover to work
|
||||||
|
run("simplemap t:$mux");
|
||||||
|
|
||||||
|
// converts $and/$or/$xor to gate representation for extract_reduce to work
|
||||||
|
run("simplemap t:$xor"); // only mapping reduce_xor
|
||||||
|
|
||||||
|
// mapping based on Yosys internal gates
|
||||||
|
if (debug_carry)
|
||||||
|
run("write_verilog -noexpr ARI1_pre.vm");
|
||||||
|
|
||||||
|
// collapse $_AND_/$_OR_/$_XOR_ chains into reduction cells
|
||||||
|
run("extract_reduce");
|
||||||
|
|
||||||
|
if (debug_carry)
|
||||||
|
run("write_verilog -noexpr ARI1_extract_reduce.vm");
|
||||||
|
|
||||||
|
// pack mux trees into $_MUX4_
|
||||||
|
run("muxcover -nodecode -mux4=220");
|
||||||
|
|
||||||
|
if (debug_carry)
|
||||||
|
run("write_verilog -noexpr ARI1_muxcover.vm");
|
||||||
|
|
||||||
|
run("techmap -map +/microchip/arith_map.v");
|
||||||
|
if (debug_carry)
|
||||||
|
run("write_verilog -noexpr ARI1_post.vm");
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert all remaining cells to gates
|
||||||
|
run("techmap -map +/techmap.v");
|
||||||
|
|
||||||
|
run("opt -fast");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_label("map_cells")) {
|
||||||
|
// Needs to be done before logic optimization, so that inverters (inserted
|
||||||
|
// here because of negative-polarity output enable) are handled.
|
||||||
|
if (help_mode || !noiopad) {
|
||||||
|
run("iopadmap -bits -inpad INBUF Y:PAD -outpad OUTBUF D:PAD -toutpad TRIBUFF E:D:PAD -tinoutpad BIBUF E:Y:D:PAD",
|
||||||
|
"(unless -noiobs)");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string techmap_args = "-map +/techmap.v -map +/microchip/cells_map.v";
|
||||||
|
run("techmap " + techmap_args);
|
||||||
|
run("clean");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_label("map_ffs")) {
|
||||||
|
// dfflegalize : Converts FFs to types supported by the target
|
||||||
|
// this can convert less capable cells into more capable cells (e.g. dff -> dffe)
|
||||||
|
|
||||||
|
// Based on PolarFire® FPGA Macro Library Guide
|
||||||
|
// D-flop:
|
||||||
|
// active high enable
|
||||||
|
// active low clear or active low set
|
||||||
|
// Latch:
|
||||||
|
// active low clear or active low set
|
||||||
|
// SLE (can implement D-flop/Latch):
|
||||||
|
// active high EN
|
||||||
|
// active low async load (set/reset) with static load configuration via ADn (Q = ~ADn)
|
||||||
|
// active low sync load (set/reset) with static load configuration via SD
|
||||||
|
// static latch configuration bit
|
||||||
|
// init not supported
|
||||||
|
|
||||||
|
// Yosys internal cell description
|
||||||
|
// see: https://yosyshq.readthedocs.io/projects/yosys/en/latest/yosys_internals/formats/cell_library.html
|
||||||
|
// see: common/simcells.v
|
||||||
|
// $_DFF_[NP]_ (regular dff)
|
||||||
|
// $_DFFE_[NP][NP]_ (enable)
|
||||||
|
// $_DFF_[NP][NP][01]_ (async reset to 0/1)
|
||||||
|
// $_DFFE_[NP][NP][01][NP]_ (async reset to 0/1 + enable)
|
||||||
|
// $_ALDFF_[NP][NP]_ (async load)
|
||||||
|
// $_ALDFFE_[NP][NP][NP]_ (async load + enable)
|
||||||
|
// $_DFFSR_[NP][NP][NP]_ (async set & reset)
|
||||||
|
// $_DFFSRE_[NP][NP][NP][NP]_ (async set & reset + enable)
|
||||||
|
// $_SDFF_[NP][NP][01]_ (sync reset to 0/1)
|
||||||
|
// $_SDFFE_[NP][NP][01][NP]_ (sync reset to 0/1 + enable, reset prioritize over enable)
|
||||||
|
// $_SDFFCE_[NP][NP][01][NP]_ (sync reset to 0/1 + enable, enable prioritize over reset)
|
||||||
|
// $_SR_[NP][NP]_ (set/reset latch)
|
||||||
|
// $_DLATCH_[NP]_ (D-latch)
|
||||||
|
// $_DLATCH_[NP][NP][01]_ (D-latch + reset to 0/1)
|
||||||
|
// $_DLATCHSR_[NP][NP][NP]_ (D-latch + set + reset)
|
||||||
|
|
||||||
|
if (family == "polarfire") {
|
||||||
|
std::string params = "";
|
||||||
|
|
||||||
|
// D-flop with async reset and enable
|
||||||
|
// posedge CLK, active low reset to 1 or 0, active high EN
|
||||||
|
params += " -cell $_DFFE_PN?P_ x";
|
||||||
|
|
||||||
|
// D-flop with sync reset and enable, enable takes priority over reset
|
||||||
|
// posedge CLK, active low reset to 1 or 0, active high EN
|
||||||
|
params += " -cell $_SDFFCE_PN?P_ x";
|
||||||
|
|
||||||
|
// D-latch + reset to 0/1
|
||||||
|
// posedge CLK, active low reset to 1 or 0
|
||||||
|
params += " -cell $_DLATCH_PN?_ x";
|
||||||
|
|
||||||
|
run("dfflegalize" + params, "(Converts FFs to supported types)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abc9 || help_mode) {
|
||||||
|
if (dff || help_mode)
|
||||||
|
run("zinit -all w:* t:$_SDFFCE_*", "('-dff' only)");
|
||||||
|
run("techmap -D NO_LUT -map +/microchip/cells_map.v", "('-abc9' only)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_label("map_luts")) {
|
||||||
|
run("opt_expr -mux_undef -noclkinv");
|
||||||
|
if (help_mode)
|
||||||
|
run("abc -luts 2:2,3,6:5[,10,20] [-dff] [-D 1]", "(option for '-nowidelut', '-dff', '-retime')");
|
||||||
|
else if (abc9) {
|
||||||
|
|
||||||
|
std::string abc9_opts;
|
||||||
|
// for the if command in abc to specify wire delay between adjacent LUTs (default = 0)
|
||||||
|
// NOTE: should not have 0 wire delay between LUTs,
|
||||||
|
// otherwise abc might use LUT2+LUT3 instead of single LUT4
|
||||||
|
abc9_opts += " -W 300";
|
||||||
|
if (nowidelut)
|
||||||
|
abc9_opts += stringf(" -maxlut %d", lut_size);
|
||||||
|
if (dff)
|
||||||
|
abc9_opts += " -dff";
|
||||||
|
run("abc9" + abc9_opts);
|
||||||
|
} else {
|
||||||
|
std::string abc_opts = " -lut " + lut_size_s;
|
||||||
|
if (dff)
|
||||||
|
abc_opts += " -dff";
|
||||||
|
if (retime)
|
||||||
|
abc_opts += " -D 1";
|
||||||
|
run("abc" + abc_opts);
|
||||||
|
}
|
||||||
|
run("clean");
|
||||||
|
|
||||||
|
if (help_mode || !abc9)
|
||||||
|
run("techmap -D NO_LUT -map +/microchip/cells_map.v", "(only if not '-abc9')");
|
||||||
|
std::string techmap_args = "-map +/microchip/cells_map.v -D FINAL_MAP";
|
||||||
|
techmap_args += " -D LUT_WIDTH=" + lut_size_s;
|
||||||
|
run("techmap " + techmap_args);
|
||||||
|
|
||||||
|
if (help_mode || lut_size == 4)
|
||||||
|
run("microchip_dffopt");
|
||||||
|
}
|
||||||
|
|
||||||
|
run("clkbufmap -buf CLKINT Y:A -inpad CLKBUF Y:PAD");
|
||||||
|
|
||||||
|
run("clean -purge");
|
||||||
|
|
||||||
|
if (check_label("check")) {
|
||||||
|
run("hierarchy -check");
|
||||||
|
run("stat");
|
||||||
|
run("check -noinit");
|
||||||
|
run("blackbox =A:whitebox");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_label("edif")) {
|
||||||
|
if (!edif_file.empty() || help_mode)
|
||||||
|
run(stringf("write_edif -pvector bra %s", edif_file.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_label("blif")) {
|
||||||
|
if (!blif_file.empty() || help_mode)
|
||||||
|
run(stringf("write_blif %s", blif_file.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_label("vlog"))
|
||||||
|
{
|
||||||
|
if (!vlog_file.empty() || help_mode)
|
||||||
|
run(stringf("write_verilog %s", help_mode ? "<file-name>" : vlog_file.c_str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} SynthMicrochipPass;
|
||||||
|
|
||||||
|
PRIVATE_NAMESPACE_END
|
|
@ -0,0 +1,69 @@
|
||||||
|
# ISC License
|
||||||
|
#
|
||||||
|
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
# asynchronous read
|
||||||
|
ram block $__uSRAM_AR_ {
|
||||||
|
|
||||||
|
#(LSRAM cost)/3
|
||||||
|
cost 43;
|
||||||
|
|
||||||
|
# INIT supported
|
||||||
|
init any;
|
||||||
|
|
||||||
|
abits 6;
|
||||||
|
widths 12 per_port;
|
||||||
|
|
||||||
|
# single write enable wire
|
||||||
|
port sw "W" {
|
||||||
|
clock posedge;
|
||||||
|
|
||||||
|
# collision not supported, but write takes precedence and read data is invalid while writing to
|
||||||
|
# the same address
|
||||||
|
wrtrans all new;
|
||||||
|
|
||||||
|
optional;
|
||||||
|
}
|
||||||
|
port ar "R" {
|
||||||
|
optional;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# synchronous read
|
||||||
|
# NOTE: synchronous read can be realized by the address pipeline register or data pipeline register.
|
||||||
|
# This assumes address is synchronized
|
||||||
|
ram block $__uSRAM_SR_ {
|
||||||
|
|
||||||
|
cost 42;
|
||||||
|
|
||||||
|
init any;
|
||||||
|
abits 6;
|
||||||
|
widths 12 per_port;
|
||||||
|
|
||||||
|
port sw "W" {
|
||||||
|
clock posedge;
|
||||||
|
|
||||||
|
# collision not supported
|
||||||
|
wrtrans all new;
|
||||||
|
|
||||||
|
optional;
|
||||||
|
}
|
||||||
|
port sr "R" {
|
||||||
|
clock posedge;
|
||||||
|
rden;
|
||||||
|
rdinit none;
|
||||||
|
optional;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
ISC License
|
||||||
|
|
||||||
|
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// See document PolarFire Family Fabric User Guide
|
||||||
|
// section 4.2 for port list.
|
||||||
|
|
||||||
|
// Asynchronous read
|
||||||
|
module $__uSRAM_AR_ (...);
|
||||||
|
|
||||||
|
parameter INIT = 0;
|
||||||
|
parameter ADDR_BITS = 6;
|
||||||
|
|
||||||
|
parameter PORT_W_WIDTH = 12;
|
||||||
|
parameter PORT_R_WIDTH = 12;
|
||||||
|
parameter PORT_R_USED = 0;
|
||||||
|
parameter PORT_W_USED = 0;
|
||||||
|
|
||||||
|
input PORT_W_CLK;
|
||||||
|
input [ADDR_BITS-1:0] PORT_W_ADDR;
|
||||||
|
input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
|
||||||
|
input PORT_W_WR_EN;
|
||||||
|
|
||||||
|
input [ADDR_BITS-1:0] PORT_R_ADDR;
|
||||||
|
output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA;
|
||||||
|
|
||||||
|
`include "brams_defs.vh"
|
||||||
|
|
||||||
|
RAM64x12 #(
|
||||||
|
`PARAMS_INIT_uSRAM
|
||||||
|
) _TECHMAP_REPLACE_ (
|
||||||
|
.R_ADDR(PORT_R_ADDR),
|
||||||
|
.R_ADDR_BYPASS(1'b1),
|
||||||
|
.R_ADDR_EN(1'b0),
|
||||||
|
.R_ADDR_SL_N(1'b1),
|
||||||
|
.R_ADDR_SD(1'b0),
|
||||||
|
.R_ADDR_AL_N(1'b1),
|
||||||
|
.R_ADDR_AD_N(1'b0),
|
||||||
|
.BLK_EN(PORT_R_USED ? 1'b1 : 1'b0),
|
||||||
|
.R_DATA(PORT_R_RD_DATA),
|
||||||
|
.R_DATA_BYPASS(1'b1),
|
||||||
|
.R_DATA_EN(1'b0),
|
||||||
|
.R_DATA_SL_N(1'b1),
|
||||||
|
.R_DATA_SD(1'b0),
|
||||||
|
.R_DATA_AL_N(1'b1),
|
||||||
|
.R_DATA_AD_N(1'b0),
|
||||||
|
|
||||||
|
.W_CLK(PORT_W_CLK),
|
||||||
|
.W_ADDR(PORT_W_ADDR),
|
||||||
|
.W_DATA(PORT_W_WR_DATA),
|
||||||
|
.W_EN(PORT_W_WR_EN),
|
||||||
|
|
||||||
|
.BUSY_FB(1'b0)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// Synchronous read
|
||||||
|
module $__uSRAM_SR_ (...);
|
||||||
|
|
||||||
|
parameter INIT = 0;
|
||||||
|
parameter ADDR_BITS = 6;
|
||||||
|
|
||||||
|
parameter PORT_W_WIDTH = 12;
|
||||||
|
parameter PORT_R_WIDTH = 12;
|
||||||
|
parameter PORT_R_USED = 0;
|
||||||
|
parameter PORT_W_USED = 0;
|
||||||
|
|
||||||
|
input PORT_W_CLK;
|
||||||
|
input [ADDR_BITS-1:0] PORT_W_ADDR;
|
||||||
|
input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
|
||||||
|
input PORT_W_WR_EN;
|
||||||
|
|
||||||
|
// Read port clock and enable signal
|
||||||
|
// that async read uSRAM doesn't have
|
||||||
|
input PORT_R_CLK;
|
||||||
|
input PORT_R_RD_EN;
|
||||||
|
input [ADDR_BITS-1:0] PORT_R_ADDR;
|
||||||
|
output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA;
|
||||||
|
|
||||||
|
`include "brams_defs.vh"
|
||||||
|
|
||||||
|
RAM64x12 #(
|
||||||
|
`PARAMS_INIT_uSRAM
|
||||||
|
) _TECHMAP_REPLACE_ (
|
||||||
|
.R_CLK(PORT_R_CLK),
|
||||||
|
.R_ADDR(PORT_R_ADDR),
|
||||||
|
.R_ADDR_BYPASS(1'b0),
|
||||||
|
.R_ADDR_EN(PORT_R_RD_EN),
|
||||||
|
.R_ADDR_SL_N(1'b1),
|
||||||
|
.R_ADDR_SD(1'b0),
|
||||||
|
.R_ADDR_AL_N(1'b1),
|
||||||
|
.R_ADDR_AD_N(1'b0),
|
||||||
|
.BLK_EN(PORT_R_USED ? 1'b1 : 1'b0),
|
||||||
|
.R_DATA(PORT_R_RD_DATA),
|
||||||
|
.R_DATA_BYPASS(1'b1),
|
||||||
|
.R_DATA_EN(1'b0),
|
||||||
|
.R_DATA_SL_N(1'b1),
|
||||||
|
.R_DATA_SD(1'b0),
|
||||||
|
.R_DATA_AL_N(1'b1),
|
||||||
|
.R_DATA_AD_N(1'b0),
|
||||||
|
|
||||||
|
.W_CLK(PORT_W_CLK),
|
||||||
|
.W_ADDR(PORT_W_ADDR),
|
||||||
|
.W_DATA(PORT_W_WR_DATA),
|
||||||
|
.W_EN(PORT_W_WR_EN),
|
||||||
|
|
||||||
|
.BUSY_FB(1'b0)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
*.log
|
||||||
|
/run-test.mk
|
||||||
|
*.vm
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
# ISC License
|
||||||
|
#
|
||||||
|
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
# active low async reset with enable
|
||||||
|
read_verilog <<EOT
|
||||||
|
module top(
|
||||||
|
input clk,
|
||||||
|
input en,
|
||||||
|
input rst,
|
||||||
|
input D,
|
||||||
|
output reg Q
|
||||||
|
);
|
||||||
|
always @(posedge clk, negedge rst) begin
|
||||||
|
if (rst == 0) begin
|
||||||
|
Q <= 1;
|
||||||
|
end else if(en) begin
|
||||||
|
Q <= D;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
synth_microchip -top top -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:SLE
|
||||||
|
select -assert-count 1 t:CLKBUF
|
||||||
|
select -assert-none t:SLE t:CLKBUF %% t:* %D
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog -D NO_INIT ../common/dffs.v
|
||||||
|
synth_microchip -top dff -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:SLE
|
||||||
|
select -assert-count 1 t:CLKBUF
|
||||||
|
select -assert-none t:SLE t:CLKBUF %% t:* %D
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog -D NO_INIT ../common/dffs.v
|
||||||
|
synth_microchip -top dffe -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:SLE
|
||||||
|
select -assert-count 1 t:CLKBUF
|
||||||
|
select -assert-none t:SLE t:CLKBUF %% t:* %D
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog -D NO_INIT ../common/adffs.v
|
||||||
|
synth_microchip -top adff -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:SLE
|
||||||
|
select -assert-count 1 t:CLKBUF
|
||||||
|
select -assert-count 1 t:CFG1
|
||||||
|
select -assert-none t:SLE t:CLKBUF t:CFG1 %% t:* %D
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog -D NO_INIT ../common/adffs.v
|
||||||
|
synth_microchip -top adffn -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:SLE
|
||||||
|
select -assert-count 1 t:CLKBUF
|
||||||
|
select -assert-none t:SLE t:CLKBUF %% t:* %D
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog -D NO_INIT ../common/adffs.v
|
||||||
|
synth_microchip -top dffs -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:SLE
|
||||||
|
select -assert-count 1 t:CLKBUF
|
||||||
|
select -assert-count 1 t:CFG1
|
||||||
|
select -assert-none t:SLE t:CLKBUF t:CFG1 %% t:* %D
|
|
@ -0,0 +1,42 @@
|
||||||
|
# ISC License
|
||||||
|
#
|
||||||
|
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
# reset can be merged into D LUT
|
||||||
|
read_verilog <<EOT
|
||||||
|
module dff_opt(
|
||||||
|
input clk,
|
||||||
|
input [1:0] D_comb,
|
||||||
|
input [1:0] EN_comb,
|
||||||
|
input [1:0] RST_comb,
|
||||||
|
output bar
|
||||||
|
);
|
||||||
|
reg foo;
|
||||||
|
assign bar = foo;
|
||||||
|
always@(posedge clk) begin
|
||||||
|
if (&RST_comb) begin
|
||||||
|
foo <= 0;
|
||||||
|
end else begin
|
||||||
|
foo <= &D_comb;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
synth_microchip -top dff_opt -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:SLE
|
||||||
|
select -assert-count 1 t:CFG4
|
||||||
|
select -assert-count 1 t:CLKBUF
|
||||||
|
select -assert-none t:SLE t:CFG4 t:CLKBUF %% t:* %D
|
|
@ -0,0 +1,211 @@
|
||||||
|
# ISC License
|
||||||
|
#
|
||||||
|
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
# pre-adder
|
||||||
|
design -reset
|
||||||
|
read_verilog <<EOT
|
||||||
|
module pre_adder(
|
||||||
|
input signed [5:0] in_A,
|
||||||
|
input signed [4:0] in_B,
|
||||||
|
input signed [4:0] in_D,
|
||||||
|
output [11:0] out_Y
|
||||||
|
);
|
||||||
|
assign out_Y = in_A * (in_B + in_D);
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
synth_microchip -top pre_adder -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:MACC_PA
|
||||||
|
select -assert-none t:MACC_PA %% t:* %D
|
||||||
|
|
||||||
|
# post-adder
|
||||||
|
design -reset
|
||||||
|
read_verilog <<EOT
|
||||||
|
module post_adder(
|
||||||
|
input signed[17:0] in_A,
|
||||||
|
input signed [17:0] in_B,
|
||||||
|
input signed [17:0] in_C,
|
||||||
|
output signed [35:0] out_Y
|
||||||
|
);
|
||||||
|
assign out_Y = (in_B*in_A)+in_C;
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
synth_microchip -top post_adder -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:MACC_PA
|
||||||
|
select -assert-none t:MACC_PA %% t:* %D
|
||||||
|
|
||||||
|
# pre-adder + post-adder
|
||||||
|
design -reset
|
||||||
|
read_verilog <<EOT
|
||||||
|
module pre_post_adder(
|
||||||
|
input signed[5:0] in_A,
|
||||||
|
input signed [4:0] in_B,
|
||||||
|
input signed [11:0] in_C,
|
||||||
|
input signed [4:0] in_D,
|
||||||
|
output signed [12:0] out_Y
|
||||||
|
);
|
||||||
|
assign out_Y = ((in_D + in_B)*in_A)+in_C;
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
synth_microchip -top pre_post_adder -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:MACC_PA
|
||||||
|
select -assert-none t:MACC_PA %% t:* %D
|
||||||
|
|
||||||
|
|
||||||
|
# multiply accumulate
|
||||||
|
design -reset
|
||||||
|
read_verilog <<EOT
|
||||||
|
module mac(
|
||||||
|
input clk,
|
||||||
|
input signed [4:0] in_A,
|
||||||
|
input signed [4:0] in_B,
|
||||||
|
input signed [4:0] in_D,
|
||||||
|
input srst_P,
|
||||||
|
output reg signed [11:0] out_P
|
||||||
|
);
|
||||||
|
always@(posedge clk) begin
|
||||||
|
if (~srst_P) begin
|
||||||
|
out_P <= 12'h000;
|
||||||
|
end else begin
|
||||||
|
out_P <= in_A * (in_B + in_D) + out_P;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
synth_microchip -top mac -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:MACC_PA
|
||||||
|
select -assert-none t:MACC_PA %% t:* %D
|
||||||
|
|
||||||
|
|
||||||
|
# cascade
|
||||||
|
design -reset
|
||||||
|
read_verilog <<EOT
|
||||||
|
module cas(
|
||||||
|
input signed [5:0] in_A,
|
||||||
|
input signed [4:0] in_B,
|
||||||
|
input signed [4:0] in_D,
|
||||||
|
input signed [4:0] casA,
|
||||||
|
input signed [4:0] casB,
|
||||||
|
output signed [11:0] out_P
|
||||||
|
);
|
||||||
|
wire signed [9:0] cascade;
|
||||||
|
assign cascade = casA * casB;
|
||||||
|
assign out_P = in_A * (in_B + in_D) + cascade;
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
synth_microchip -top cas -family polarfire -noiopad
|
||||||
|
select -assert-count 2 t:MACC_PA
|
||||||
|
select -assert-none t:MACC_PA %% t:* %D
|
||||||
|
|
||||||
|
# carryout
|
||||||
|
design -reset
|
||||||
|
read_verilog <<EOT
|
||||||
|
module carryout (cout,out,a, b,c);
|
||||||
|
parameter n = 6;
|
||||||
|
parameter k = 2;
|
||||||
|
output reg [k*(n+1)-1:0] out;
|
||||||
|
output reg cout;
|
||||||
|
input [n:0] a;
|
||||||
|
input [n:0] b;
|
||||||
|
input [n-1:0] c;
|
||||||
|
always @(*)
|
||||||
|
begin
|
||||||
|
{cout,out} = a * b + c;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
synth_microchip -top carryout -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:MACC_PA
|
||||||
|
select -assert-none t:MACC_PA %% t:* %D
|
||||||
|
|
||||||
|
# pipeline registers
|
||||||
|
design -reset
|
||||||
|
read_verilog <<EOT
|
||||||
|
module pipeline(
|
||||||
|
input clk,
|
||||||
|
input srst_A,
|
||||||
|
input srst_B,
|
||||||
|
input srst_D,
|
||||||
|
input srst_P,
|
||||||
|
input arst_D,
|
||||||
|
input srst_C,
|
||||||
|
input signed [5:0] in_A,
|
||||||
|
input signed [4:0] in_B,
|
||||||
|
input signed [4:0] in_C,
|
||||||
|
input signed [4:0] in_D,
|
||||||
|
output reg [11:0] out_P
|
||||||
|
);
|
||||||
|
wire srst_A_N;
|
||||||
|
wire srst_B_N;
|
||||||
|
wire srst_C_N;
|
||||||
|
wire srst_D_N;
|
||||||
|
wire srst_P_N;
|
||||||
|
assign srst_A_N = ~srst_A;
|
||||||
|
assign srst_B_N = ~srst_B;
|
||||||
|
assign srst_C_N = ~srst_C;
|
||||||
|
assign srst_D_N = ~srst_D;
|
||||||
|
assign srst_P_N = ~srst_P;
|
||||||
|
|
||||||
|
reg signed [5:0] reg_A;
|
||||||
|
reg signed [4:0] reg_B;
|
||||||
|
reg signed [4:0] reg_C;
|
||||||
|
reg signed [4:0] reg_D;
|
||||||
|
|
||||||
|
always@(posedge clk) begin // sync reset A
|
||||||
|
// if (~srst_A_N) begin
|
||||||
|
if (srst_A_N) begin
|
||||||
|
reg_A = 6'b000000;
|
||||||
|
end else begin
|
||||||
|
reg_A = in_A;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always@(posedge clk) begin // sync reset B
|
||||||
|
if (srst_B_N) begin
|
||||||
|
reg_B = 5'b00000;
|
||||||
|
end else begin
|
||||||
|
reg_B = in_B;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always@(posedge clk, negedge arst_D) begin // async reset D
|
||||||
|
if (~arst_D) begin
|
||||||
|
reg_D = 5'b00000;
|
||||||
|
end else begin
|
||||||
|
reg_D = in_D;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always@(posedge clk) begin // sync reset C
|
||||||
|
if (srst_C_N) begin
|
||||||
|
reg_C = 5'b00000;
|
||||||
|
end else begin
|
||||||
|
reg_C = in_C;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// sync reset P
|
||||||
|
always@(posedge clk) begin
|
||||||
|
if (srst_P_N) begin
|
||||||
|
out_P = 12'h000;
|
||||||
|
end else begin
|
||||||
|
out_P = reg_A * (reg_B + reg_D) + reg_C;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
synth_microchip -top pipeline -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:MACC_PA
|
||||||
|
select -assert-none t:MACC_PA %% t:* %D
|
|
@ -0,0 +1,51 @@
|
||||||
|
# ISC License
|
||||||
|
#
|
||||||
|
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
# regular unsigned multiply
|
||||||
|
read_verilog ../common/mul.v
|
||||||
|
chparam -set X_WIDTH 8 -set Y_WIDTH 8 -set A_WIDTH 16
|
||||||
|
hierarchy -top top
|
||||||
|
proc
|
||||||
|
synth_microchip -family polarfire -noiopad
|
||||||
|
cd top # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 1 t:MACC_PA
|
||||||
|
select -assert-none t:MACC_PA %% t:* %D
|
||||||
|
|
||||||
|
# regular signed multiply
|
||||||
|
design -reset
|
||||||
|
read_verilog <<EOT
|
||||||
|
module signed_mult(
|
||||||
|
input signed [17:0] in_A,
|
||||||
|
input signed [17:0] in_B,
|
||||||
|
output signed [35:0] out_Y
|
||||||
|
);
|
||||||
|
assign out_Y = in_A * in_B;
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
synth_microchip -top signed_mult -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:MACC_PA
|
||||||
|
select -assert-none t:MACC_PA %% t:* %D
|
||||||
|
|
||||||
|
# wide multiply
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/mul.v
|
||||||
|
chparam -set X_WIDTH 30 -set Y_WIDTH 16 -set A_WIDTH 46
|
||||||
|
hierarchy -top top
|
||||||
|
proc
|
||||||
|
synth_microchip -family polarfire -noiopad
|
||||||
|
cd top # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 2 t:MACC_PA
|
||||||
|
select -assert-none t:MACC_PA %% t:* %D
|
|
@ -0,0 +1,50 @@
|
||||||
|
# ISC License
|
||||||
|
#
|
||||||
|
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
read_verilog <<EOT
|
||||||
|
module ram_SDP(data,waddr,we,clk,q);
|
||||||
|
parameter d_width = 32;
|
||||||
|
parameter addr_width = 8;
|
||||||
|
parameter mem_depth = 256;
|
||||||
|
input [d_width-1:0] data;
|
||||||
|
input [addr_width-1:0] waddr;
|
||||||
|
input we, clk;
|
||||||
|
output reg [d_width-1:0] q;
|
||||||
|
|
||||||
|
reg [d_width-1:0] mem [mem_depth-1:0];
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (we) begin
|
||||||
|
mem[waddr] <= data;
|
||||||
|
end else begin
|
||||||
|
q <= mem[waddr];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
synth_microchip -top ram_SDP -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:RAM1K20
|
||||||
|
select -assert-count 1 t:CFG1
|
||||||
|
select -assert-none t:RAM1K20 t:CFG1 %% t:* %D
|
||||||
|
|
||||||
|
# very similar to ram_SDP.v, except read enable is always active
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/blockram.v
|
||||||
|
hierarchy -top sync_ram_sdp
|
||||||
|
chparam -set DATA_WIDTH 32 -set ADDRESS_WIDTH 8
|
||||||
|
synth_microchip -top sync_ram_sdp -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:RAM1K20
|
||||||
|
select -assert-none t:RAM1K20 %% t:* %D
|
|
@ -0,0 +1,64 @@
|
||||||
|
# ISC License
|
||||||
|
#
|
||||||
|
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
read_verilog <<EOT
|
||||||
|
module ram_TDP (clka,clkb,wea,addra,dataina,qa,web,addrb,datainb,qb);
|
||||||
|
parameter addr_width = 10;
|
||||||
|
parameter data_width = 2;
|
||||||
|
input clka,clkb,wea,web;
|
||||||
|
input [data_width - 1 : 0] dataina,datainb;
|
||||||
|
input [addr_width - 1 : 0] addra,addrb;
|
||||||
|
output reg [data_width - 1 : 0] qa,qb;
|
||||||
|
reg [addr_width - 1 : 0] addra_reg, addrb_reg;
|
||||||
|
reg [data_width - 1 : 0] mem [(2**addr_width) - 1 : 0];
|
||||||
|
|
||||||
|
always @ (posedge clka)
|
||||||
|
begin
|
||||||
|
addra_reg <= addra;
|
||||||
|
|
||||||
|
if(wea) begin
|
||||||
|
mem[addra] <= dataina;
|
||||||
|
qa <= dataina;
|
||||||
|
end else begin
|
||||||
|
qa <= mem[addra];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always @ (posedge clkb)
|
||||||
|
begin
|
||||||
|
addrb_reg <= addrb;
|
||||||
|
if(web) begin
|
||||||
|
mem[addrb] <= datainb;
|
||||||
|
qb <= datainb;
|
||||||
|
end else begin
|
||||||
|
qb <= mem[addrb];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
synth_microchip -top ram_TDP -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:RAM1K20
|
||||||
|
select -assert-none t:RAM1K20 %% t:* %D
|
||||||
|
|
||||||
|
# similar to ram_TDP.v, but different write mode and read_enable=~write_enable
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/blockram.v
|
||||||
|
hierarchy -top sync_ram_tdp
|
||||||
|
chparam -set DATA_WIDTH 2 -set ADDRESS_WIDTH 10
|
||||||
|
synth_microchip -top sync_ram_tdp -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:RAM1K20
|
||||||
|
select -assert-count 2 t:CFG1
|
||||||
|
select -assert-none t:RAM1K20 t:CFG1 %% t:* %D
|
|
@ -0,0 +1,28 @@
|
||||||
|
# ISC License
|
||||||
|
#
|
||||||
|
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
read_verilog <<EOT
|
||||||
|
module reduce(
|
||||||
|
input [7:0] data,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = ^data;
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
synth_microchip -top reduce -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:XOR8
|
||||||
|
select -assert-none t:XOR8 %% t:* %D
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -eu
|
||||||
|
source ../../gen-tests-makefile.sh
|
||||||
|
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
|
@ -0,0 +1,22 @@
|
||||||
|
# ISC License
|
||||||
|
#
|
||||||
|
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
read_verilog ../common/blockram.v
|
||||||
|
hierarchy -top sync_ram_sp
|
||||||
|
chparam -set DATA_WIDTH 20 -set ADDRESS_WIDTH 10
|
||||||
|
synth_microchip -top sync_ram_sp -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:RAM1K20
|
||||||
|
select -assert-none t:RAM1K20 %% t:* %D
|
|
@ -0,0 +1,40 @@
|
||||||
|
# ISC License
|
||||||
|
#
|
||||||
|
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
read_verilog <<EOT
|
||||||
|
module uram_ar(data,waddr,we,clk,q);
|
||||||
|
parameter d_width = 12;
|
||||||
|
parameter addr_width = 2;
|
||||||
|
parameter mem_depth = 12;
|
||||||
|
input [d_width-1:0] data;
|
||||||
|
input [addr_width-1:0] waddr;
|
||||||
|
input we, clk;
|
||||||
|
output [d_width-1:0] q;
|
||||||
|
|
||||||
|
reg [d_width-1:0] mem [mem_depth-1:0];
|
||||||
|
assign q = mem[waddr];
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (we)
|
||||||
|
mem[waddr] <= data;
|
||||||
|
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
synth_microchip -top uram_ar -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:RAM64x12
|
||||||
|
select -assert-none t:RAM64x12 %% t:* %D
|
|
@ -0,0 +1,45 @@
|
||||||
|
# ISC License
|
||||||
|
#
|
||||||
|
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
read_verilog <<EOT
|
||||||
|
module uram_sr(clk, wr, raddr, din, waddr, dout);
|
||||||
|
input clk;
|
||||||
|
input [11:0] din;
|
||||||
|
input wr;
|
||||||
|
input [5:0] waddr, raddr;
|
||||||
|
output [11:0] dout;
|
||||||
|
reg [5:0] raddr_reg;
|
||||||
|
reg [11:0] mem [0:63];
|
||||||
|
assign dout = mem[raddr_reg];
|
||||||
|
integer i;
|
||||||
|
initial begin
|
||||||
|
for (i = 0; i < 64; i = i + 1) begin
|
||||||
|
mem[i] = 12'hfff;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always@(posedge clk) begin
|
||||||
|
raddr_reg <= raddr;
|
||||||
|
if(wr)
|
||||||
|
mem[waddr]<= din;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
synth_microchip -top uram_sr -family polarfire -noiopad
|
||||||
|
|
||||||
|
select -assert-count 1 t:RAM64x12
|
||||||
|
select -assert-none t:RAM64x12 %% t:* %D
|
|
@ -0,0 +1,41 @@
|
||||||
|
# ISC License
|
||||||
|
#
|
||||||
|
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
read_verilog <<EOT
|
||||||
|
module widemux(
|
||||||
|
input [3:0] data,
|
||||||
|
input S0,
|
||||||
|
input S1,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = S1 ? (S0 ? data[3] : data[1]) : (S0 ? data[2] : data[0]);
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
synth_microchip -top widemux -family polarfire -noiopad
|
||||||
|
select -assert-count 1 t:MX4
|
||||||
|
select -assert-none t:MX4 %% t:* %D
|
||||||
|
|
||||||
|
# RTL style is different here forming a different structure
|
||||||
|
read_verilog ../common/mux.v
|
||||||
|
design -save read
|
||||||
|
|
||||||
|
hierarchy -top mux4
|
||||||
|
proc
|
||||||
|
equiv_opt -assert -map +/microchip/cells_sim.v synth_microchip -top mux4 -family polarfire -noiopad
|
||||||
|
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||||
|
cd mux4 # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 3 t:CFG3
|
||||||
|
select -assert-none t:CFG3 %% t:* %D
|
Loading…
Reference in New Issue