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/qlf_k6n10f && 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/memfile && 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
|
||||
GENFILES += 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