Merge branch 'master' into clock-wip
This commit is contained in:
commit
3364a3b674
@ -216,7 +216,12 @@ configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/common/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/generated/version.h
|
||||
)
|
||||
|
||||
include_directories(common/kernel/ common/place/ common/route/ json/ frontend/ 3rdparty/json11/ 3rdparty/pybind11/include ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS})
|
||||
if (NOT DEFINED PYBIND11_INCLUDE_DIR)
|
||||
# Use bundled pybind11
|
||||
set(PYBIND11_INCLUDE_DIR "3rdparty/pybind11/include")
|
||||
endif()
|
||||
|
||||
include_directories(common/kernel/ common/place/ common/route/ json/ frontend/ 3rdparty/json11/ ${PYBIND11_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS})
|
||||
|
||||
if(BUILD_HEAP)
|
||||
find_package (Eigen3 REQUIRED NO_MODULE)
|
||||
|
@ -145,3 +145,9 @@ fn_wrapper_1a<Context, decltype(&Context::getBelsInBucket), &Context::getBelsInB
|
||||
// bool isValidBelForCellType(IdString cell\_type, BelId bel) const
|
||||
fn_wrapper_2a<Context, decltype(&Context::isValidBelForCellType), &Context::isValidBelForCellType, pass_through<bool>,
|
||||
conv_from_str<IdString>, conv_from_str<BelId>>::def_wrap(ctx_cls, "isValidBelForCellType");
|
||||
|
||||
fn_wrapper_1a<Context, decltype(&Context::getDelayFromNS), &Context::getDelayFromNS, pass_through<delay_t>,
|
||||
pass_through<double>>::def_wrap(ctx_cls, "getDelayFromNS");
|
||||
|
||||
fn_wrapper_1a<Context, decltype(&Context::getDelayNS), &Context::getDelayNS, pass_through<double>,
|
||||
pass_through<delay_t>>::def_wrap(ctx_cls, "getDelayNS");
|
@ -46,6 +46,13 @@ void arch_wrap_python(py::module &m)
|
||||
typedef linear_range<WireId> WireRange;
|
||||
typedef linear_range<PipId> AllPipRange;
|
||||
|
||||
typedef const std::vector<PipId> &UphillPipRange;
|
||||
typedef const std::vector<PipId> &DownhillPipRange;
|
||||
|
||||
typedef const std::vector<BelBucketId> &BelBucketRange;
|
||||
typedef const std::vector<BelId> &BelRangeForBelBucket;
|
||||
typedef const std::vector<BelPin> &BelPinRange;
|
||||
|
||||
auto arch_cls = py::class_<Arch, BaseCtx>(m, "Arch").def(py::init<ArchArgs>());
|
||||
|
||||
auto dxy_cls = py::class_<ContextualWrapper<DecalXY>>(m, "DecalXY_");
|
||||
@ -62,82 +69,8 @@ void arch_wrap_python(py::module &m)
|
||||
.def("place", &Context::place)
|
||||
.def("route", &Context::route);
|
||||
|
||||
py::class_<BelPin>(m, "BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin);
|
||||
|
||||
fn_wrapper_1a<Context, decltype(&Context::getBelType), &Context::getBelType, conv_to_str<IdString>,
|
||||
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType");
|
||||
fn_wrapper_1a<Context, decltype(&Context::checkBelAvail), &Context::checkBelAvail, pass_through<bool>,
|
||||
conv_from_str<BelId>>::def_wrap(ctx_cls, "checkBelAvail");
|
||||
fn_wrapper_1a<Context, decltype(&Context::getBelChecksum), &Context::getBelChecksum, pass_through<uint32_t>,
|
||||
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelChecksum");
|
||||
fn_wrapper_3a_v<Context, decltype(&Context::bindBel), &Context::bindBel, conv_from_str<BelId>,
|
||||
addr_and_unwrap<CellInfo>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindBel");
|
||||
fn_wrapper_1a_v<Context, decltype(&Context::unbindBel), &Context::unbindBel, conv_from_str<BelId>>::def_wrap(
|
||||
ctx_cls, "unbindBel");
|
||||
fn_wrapper_1a<Context, decltype(&Context::getBoundBelCell), &Context::getBoundBelCell, deref_and_wrap<CellInfo>,
|
||||
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBoundBelCell");
|
||||
fn_wrapper_1a<Context, decltype(&Context::getConflictingBelCell), &Context::getConflictingBelCell,
|
||||
deref_and_wrap<CellInfo>, conv_from_str<BelId>>::def_wrap(ctx_cls, "getConflictingBelCell");
|
||||
fn_wrapper_0a<Context, decltype(&Context::getBels), &Context::getBels, wrap_context<BelRange>>::def_wrap(ctx_cls,
|
||||
"getBels");
|
||||
|
||||
fn_wrapper_2a<Context, decltype(&Context::getBelPinWire), &Context::getBelPinWire, conv_to_str<WireId>,
|
||||
conv_from_str<BelId>, conv_from_str<IdString>>::def_wrap(ctx_cls, "getBelPinWire");
|
||||
fn_wrapper_1a<Context, decltype(&Context::getWireBelPins), &Context::getWireBelPins,
|
||||
wrap_context<const std::vector<BelPin> &>, conv_from_str<WireId>>::def_wrap(ctx_cls,
|
||||
"getWireBelPins");
|
||||
|
||||
fn_wrapper_1a<Context, decltype(&Context::getWireChecksum), &Context::getWireChecksum, pass_through<uint32_t>,
|
||||
conv_from_str<WireId>>::def_wrap(ctx_cls, "getWireChecksum");
|
||||
fn_wrapper_3a_v<Context, decltype(&Context::bindWire), &Context::bindWire, conv_from_str<WireId>,
|
||||
addr_and_unwrap<NetInfo>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindWire");
|
||||
fn_wrapper_1a_v<Context, decltype(&Context::unbindWire), &Context::unbindWire, conv_from_str<WireId>>::def_wrap(
|
||||
ctx_cls, "unbindWire");
|
||||
fn_wrapper_1a<Context, decltype(&Context::checkWireAvail), &Context::checkWireAvail, pass_through<bool>,
|
||||
conv_from_str<WireId>>::def_wrap(ctx_cls, "checkWireAvail");
|
||||
fn_wrapper_1a<Context, decltype(&Context::getBoundWireNet), &Context::getBoundWireNet, deref_and_wrap<NetInfo>,
|
||||
conv_from_str<WireId>>::def_wrap(ctx_cls, "getBoundWireNet");
|
||||
fn_wrapper_1a<Context, decltype(&Context::getConflictingWireNet), &Context::getConflictingWireNet,
|
||||
deref_and_wrap<NetInfo>, conv_from_str<WireId>>::def_wrap(ctx_cls, "getConflictingWireNet");
|
||||
|
||||
fn_wrapper_0a<Context, decltype(&Context::getWires), &Context::getWires, wrap_context<WireRange>>::def_wrap(
|
||||
ctx_cls, "getWires");
|
||||
|
||||
fn_wrapper_0a<Context, decltype(&Context::getPips), &Context::getPips, wrap_context<AllPipRange>>::def_wrap(
|
||||
ctx_cls, "getPips");
|
||||
fn_wrapper_1a<Context, decltype(&Context::getPipChecksum), &Context::getPipChecksum, pass_through<uint32_t>,
|
||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipChecksum");
|
||||
fn_wrapper_3a_v<Context, decltype(&Context::bindPip), &Context::bindPip, conv_from_str<PipId>,
|
||||
addr_and_unwrap<NetInfo>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindPip");
|
||||
fn_wrapper_1a_v<Context, decltype(&Context::unbindPip), &Context::unbindPip, conv_from_str<PipId>>::def_wrap(
|
||||
ctx_cls, "unbindPip");
|
||||
fn_wrapper_1a<Context, decltype(&Context::checkPipAvail), &Context::checkPipAvail, pass_through<bool>,
|
||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "checkPipAvail");
|
||||
fn_wrapper_1a<Context, decltype(&Context::getBoundPipNet), &Context::getBoundPipNet, deref_and_wrap<NetInfo>,
|
||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getBoundPipNet");
|
||||
fn_wrapper_1a<Context, decltype(&Context::getConflictingPipNet), &Context::getConflictingPipNet,
|
||||
deref_and_wrap<NetInfo>, conv_from_str<PipId>>::def_wrap(ctx_cls, "getConflictingPipNet");
|
||||
|
||||
fn_wrapper_1a<Context, decltype(&Context::getPipsDownhill), &Context::getPipsDownhill,
|
||||
wrap_context<const std::vector<PipId> &>, conv_from_str<WireId>>::def_wrap(ctx_cls,
|
||||
"getPipsDownhill");
|
||||
fn_wrapper_1a<Context, decltype(&Context::getPipsUphill), &Context::getPipsUphill,
|
||||
wrap_context<const std::vector<PipId> &>, conv_from_str<WireId>>::def_wrap(ctx_cls, "getPipsUphill");
|
||||
|
||||
fn_wrapper_1a<Context, decltype(&Context::getPipSrcWire), &Context::getPipSrcWire, conv_to_str<WireId>,
|
||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipSrcWire");
|
||||
fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>,
|
||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDstWire");
|
||||
fn_wrapper_1a<Context, decltype(&Context::getPipDelay), &Context::getPipDelay, pass_through<DelayQuad>,
|
||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDelay");
|
||||
|
||||
fn_wrapper_1a<Context, decltype(&Context::getDelayFromNS), &Context::getDelayFromNS, pass_through<delay_t>,
|
||||
pass_through<double>>::def_wrap(ctx_cls, "getDelayFromNS");
|
||||
|
||||
fn_wrapper_0a<Context, decltype(&Context::getChipName), &Context::getChipName, pass_through<std::string>>::def_wrap(
|
||||
ctx_cls, "getChipName");
|
||||
fn_wrapper_0a<Context, decltype(&Context::archId), &Context::archId, conv_to_str<IdString>>::def_wrap(ctx_cls,
|
||||
"archId");
|
||||
auto belpin_cls =
|
||||
py::class_<BelPin>(m, "BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin);
|
||||
|
||||
fn_wrapper_3a<Context, decltype(&Context::constructDecalXY), &Context::constructDecalXY, wrap_context<DecalXY>,
|
||||
conv_from_str<DecalId>, pass_through<float>, pass_through<float>>::def_wrap(ctx_cls, "DecalXY");
|
||||
@ -145,14 +78,10 @@ void arch_wrap_python(py::module &m)
|
||||
typedef dict<IdString, std::unique_ptr<CellInfo>> CellMap;
|
||||
typedef dict<IdString, std::unique_ptr<NetInfo>> NetMap;
|
||||
typedef dict<IdString, HierarchicalCell> HierarchyMap;
|
||||
typedef dict<IdString, IdString> AliasMap;
|
||||
typedef dict<IdString, HierarchicalCell> HierarchyMap;
|
||||
|
||||
readonly_wrapper<Context, decltype(&Context::cells), &Context::cells, wrap_context<CellMap &>>::def_wrap(ctx_cls,
|
||||
"cells");
|
||||
readonly_wrapper<Context, decltype(&Context::nets), &Context::nets, wrap_context<NetMap &>>::def_wrap(ctx_cls,
|
||||
"nets");
|
||||
|
||||
fn_wrapper_2a_v<Context, decltype(&Context::addClock), &Context::addClock, conv_from_str<IdString>,
|
||||
pass_through<float>>::def_wrap(ctx_cls, "addClock");
|
||||
#include "arch_pybindings_shared.h"
|
||||
|
||||
// Generic arch construction API
|
||||
fn_wrapper_4a_v<Context, decltype(&Context::addWire), &Context::addWire, conv_from_str<IdStringList>,
|
||||
@ -236,28 +165,6 @@ void arch_wrap_python(py::module &m)
|
||||
conv_from_str<IdString>>::def_wrap(ctx_cls, "addCellBelPinMapping", "cell"_a, "cell_pin"_a,
|
||||
"bel_pin"_a);
|
||||
|
||||
// const\_range\<BelBucketId\> getBelBuckets() const
|
||||
fn_wrapper_0a<Context, decltype(&Context::getBelBuckets), &Context::getBelBuckets,
|
||||
wrap_context<const std::vector<BelBucketId> &>>::def_wrap(ctx_cls, "getBelBuckets");
|
||||
|
||||
// BelBucketId getBelBucketForBel(BelId bel) const
|
||||
fn_wrapper_1a<Context, decltype(&Context::getBelBucketForBel), &Context::getBelBucketForBel,
|
||||
conv_to_str<BelBucketId>, conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelBucketForBel");
|
||||
|
||||
// BelBucketId getBelBucketForCellType(IdString cell\_type) const
|
||||
fn_wrapper_1a<Context, decltype(&Context::getBelBucketForCellType), &Context::getBelBucketForCellType,
|
||||
conv_to_str<BelBucketId>, conv_from_str<IdString>>::def_wrap(ctx_cls, "getBelBucketForCellType");
|
||||
|
||||
// const\_range\<BelId\> getBelsInBucket(BelBucketId bucket) const
|
||||
fn_wrapper_1a<Context, decltype(&Context::getBelsInBucket), &Context::getBelsInBucket,
|
||||
wrap_context<const std::vector<BelId> &>, conv_from_str<BelBucketId>>::def_wrap(ctx_cls,
|
||||
"getBelsInBucket");
|
||||
|
||||
// bool isValidBelForCellType(IdString cell\_type, BelId bel) const
|
||||
fn_wrapper_2a<Context, decltype(&Context::isValidBelForCellType), &Context::isValidBelForCellType,
|
||||
pass_through<bool>, conv_from_str<IdString>, conv_from_str<BelId>>::def_wrap(ctx_cls,
|
||||
"isValidBelForCellType");
|
||||
|
||||
WRAP_RANGE(m, Bel, conv_to_str<BelId>);
|
||||
WRAP_RANGE(m, Wire, conv_to_str<WireId>);
|
||||
WRAP_RANGE(m, AllPip, conv_to_str<PipId>);
|
||||
|
@ -1307,6 +1307,36 @@ Arch::Arch(ArchArgs args) : args(args)
|
||||
snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this));
|
||||
addBelInput(belname, id_OSCEN, id(buf));
|
||||
break;
|
||||
case ID_RAM16:
|
||||
snprintf(buf, 32, "R%dC%d_RAMW", row + 1, col + 1);
|
||||
belname = id(buf);
|
||||
addBel(belname, id_RAMW, Loc(col, row, BelZ::lutram_0_z), false);
|
||||
|
||||
snprintf(buf, 32, "R%dC%d_A%d", row + 1, col + 1, 4);
|
||||
addBelInput(belname, id_A4, id(buf));
|
||||
snprintf(buf, 32, "R%dC%d_B%d", row + 1, col + 1, 4);
|
||||
addBelInput(belname, id_B4, id(buf));
|
||||
snprintf(buf, 32, "R%dC%d_C%d", row + 1, col + 1, 4);
|
||||
addBelInput(belname, id_C4, id(buf));
|
||||
snprintf(buf, 32, "R%dC%d_D%d", row + 1, col + 1, 4);
|
||||
addBelInput(belname, id_D4, id(buf));
|
||||
|
||||
snprintf(buf, 32, "R%dC%d_A%d", row + 1, col + 1, 5);
|
||||
addBelInput(belname, id_A5, id(buf));
|
||||
snprintf(buf, 32, "R%dC%d_B%d", row + 1, col + 1, 5);
|
||||
addBelInput(belname, id_B5, id(buf));
|
||||
snprintf(buf, 32, "R%dC%d_C%d", row + 1, col + 1, 5);
|
||||
addBelInput(belname, id_C5, id(buf));
|
||||
snprintf(buf, 32, "R%dC%d_D%d", row + 1, col + 1, 5);
|
||||
addBelInput(belname, id_D5, id(buf));
|
||||
|
||||
snprintf(buf, 32, "R%dC%d_CLK%d", row + 1, col + 1, 2);
|
||||
addBelInput(belname, id_CLK, id(buf));
|
||||
snprintf(buf, 32, "R%dC%d_LSR%d", row + 1, col + 1, 2);
|
||||
addBelInput(belname, id_LSR, id(buf));
|
||||
snprintf(buf, 32, "R%dC%d_CE%d", row + 1, col + 1, 2);
|
||||
addBelInput(belname, id_CE, id(buf));
|
||||
break;
|
||||
// fall through the ++
|
||||
case ID_LUT7:
|
||||
z++;
|
||||
|
@ -506,6 +506,7 @@ enum
|
||||
{
|
||||
mux_0_z = 10, // start Z for the MUX2LUT5 bels
|
||||
iologic_0_z = 20, // start Z for the IOLOGIC bels
|
||||
lutram_0_z = 30, // start Z for the IOLOGIC bels
|
||||
vcc_0_z = 277, // virtual VCC bel Z
|
||||
gnd_0_z = 278, // virtual VSS bel Z
|
||||
osc_z = 280, // Z for the oscillator bels
|
||||
|
@ -48,6 +48,14 @@ std::unique_ptr<CellInfo> create_generic_cell(Context *ctx, IdString type, std::
|
||||
new_cell->addOutput(id_Q);
|
||||
new_cell->addInput(id_CE);
|
||||
new_cell->addInput(id_LSR);
|
||||
} else if (type == id_RAMW) {
|
||||
IdString names[8] = {id_A4, id_B4, id_C4, id_D4, id_A5, id_B5, id_C5, id_D5};
|
||||
for (int i = 0; i < 8; i++) {
|
||||
new_cell->addInput(names[i]);
|
||||
}
|
||||
new_cell->addInput(id_CLK);
|
||||
new_cell->addInput(id_CE);
|
||||
new_cell->addInput(id_LSR);
|
||||
} else if (type == id_GW_MUX2_LUT5 || type == id_GW_MUX2_LUT6 || type == id_GW_MUX2_LUT7 ||
|
||||
type == id_GW_MUX2_LUT7 || type == id_GW_MUX2_LUT8) {
|
||||
new_cell->addInput(id_I0);
|
||||
@ -169,4 +177,40 @@ void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, pool<IdString> &to
|
||||
}
|
||||
}
|
||||
|
||||
void sram_to_ramw_split(Context *ctx, CellInfo *ram, CellInfo *ramw)
|
||||
{
|
||||
if (ramw->hierpath == IdString())
|
||||
ramw->hierpath = ramw->hierpath;
|
||||
ram->movePortTo(ctx->id("WAD[0]"), ramw, id_A4);
|
||||
ram->movePortTo(ctx->id("WAD[1]"), ramw, id_B4);
|
||||
ram->movePortTo(ctx->id("WAD[2]"), ramw, id_C4);
|
||||
ram->movePortTo(ctx->id("WAD[3]"), ramw, id_D4);
|
||||
|
||||
ram->movePortTo(ctx->id("DI[0]"), ramw, id_A5);
|
||||
ram->movePortTo(ctx->id("DI[1]"), ramw, id_B5);
|
||||
ram->movePortTo(ctx->id("DI[2]"), ramw, id_C5);
|
||||
ram->movePortTo(ctx->id("DI[3]"), ramw, id_D5);
|
||||
|
||||
ram->movePortTo(ctx->id("CLK"), ramw, id_CLK);
|
||||
ram->movePortTo(ctx->id("WRE"), ramw, id_LSR);
|
||||
}
|
||||
|
||||
void sram_to_slice(Context *ctx, CellInfo *ram, CellInfo *slice, int index)
|
||||
{
|
||||
char buf1[32];
|
||||
if (slice->hierpath == IdString())
|
||||
slice->hierpath = slice->hierpath;
|
||||
|
||||
snprintf(buf1, 32, "INIT_%d", index);
|
||||
slice->params[id_INIT] = ram->params[ctx->id(buf1)];
|
||||
|
||||
snprintf(buf1, 32, "DO[%d]", index);
|
||||
ram->movePortTo(ctx->id(buf1), slice, id_F);
|
||||
|
||||
ram->copyPortTo(ctx->id("RAD[0]"), slice, id_A);
|
||||
ram->copyPortTo(ctx->id("RAD[1]"), slice, id_B);
|
||||
ram->copyPortTo(ctx->id("RAD[2]"), slice, id_C);
|
||||
ram->copyPortTo(ctx->id("RAD[3]"), slice, id_D);
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
@ -111,6 +111,8 @@ inline bool is_ff(const BaseCtx *ctx, const CellInfo *cell)
|
||||
|
||||
inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_SLICE; }
|
||||
|
||||
inline bool is_sram(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_RAM16SDP4; }
|
||||
|
||||
// Convert a LUT primitive to (part of) an GENERIC_SLICE, swapping ports
|
||||
// as needed. Set no_dff if a DFF is not being used, so that the output
|
||||
// can be reconnected
|
||||
@ -125,6 +127,12 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l
|
||||
// Convert a Gowin IO buffer to a IOB bel
|
||||
void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool<IdString> &todelete_cells);
|
||||
|
||||
// Convert RAM16 to write port
|
||||
void sram_to_ramw_split(Context *ctx, CellInfo *ram, CellInfo *ramw);
|
||||
|
||||
// Convert RAM16 to slice
|
||||
void sram_to_slice(Context *ctx, CellInfo *ram, CellInfo *slice, int index);
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
@ -823,6 +823,20 @@ X(DFFNPE)
|
||||
X(DFFNC)
|
||||
X(DFFNCE)
|
||||
|
||||
// Shadow RAM
|
||||
X(RAM16)
|
||||
X(RAMW)
|
||||
X(RAM16SDP4)
|
||||
X(WADA)
|
||||
X(WADB)
|
||||
X(WADC)
|
||||
X(WADD)
|
||||
X(DIA)
|
||||
X(DIB)
|
||||
X(DIC)
|
||||
X(DID)
|
||||
X(WRE)
|
||||
|
||||
// IOB types
|
||||
X(IBUF)
|
||||
X(OBUF)
|
||||
|
@ -694,6 +694,95 @@ static void pack_gsr(Context *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// Pack shadow RAM
|
||||
void pack_sram(Context *ctx)
|
||||
{
|
||||
log_info("Packing Shadow RAM..\n");
|
||||
|
||||
pool<IdString> packed_cells;
|
||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||
|
||||
for (auto &cell : ctx->cells) {
|
||||
CellInfo *ci = cell.second.get();
|
||||
if (is_sram(ctx, ci)) {
|
||||
|
||||
// Create RAMW slice
|
||||
std::unique_ptr<CellInfo> ramw_slice =
|
||||
create_generic_cell(ctx, id_RAMW, ci->name.str(ctx) + "$RAMW_SLICE");
|
||||
sram_to_ramw_split(ctx, ci, ramw_slice.get());
|
||||
ramw_slice->connectPort(id_CE, ctx->nets[ctx->id("$PACKER_VCC_NET")].get());
|
||||
|
||||
// Create actual RAM slices
|
||||
std::unique_ptr<CellInfo> ram_comb[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ram_comb[i] = create_generic_cell(ctx, id_SLICE,
|
||||
ci->name.str(ctx) + "$SRAM_SLICE" + std::to_string(i));
|
||||
ram_comb[i]->params[id_FF_USED] = 1;
|
||||
ram_comb[i]->params[id_FF_TYPE] = std::string("RAM");
|
||||
sram_to_slice(ctx, ci, ram_comb[i].get(), i);
|
||||
}
|
||||
// Create 'block' SLICEs as a placement hint that these cells are mutually exclusive with the RAMW
|
||||
std::unique_ptr<CellInfo> ramw_block[2];
|
||||
for (int i = 0; i < 2; i++) {
|
||||
ramw_block[i] = create_generic_cell(ctx, id_SLICE,
|
||||
ci->name.str(ctx) + "$RAMW_BLOCK" + std::to_string(i));
|
||||
ram_comb[i]->params[id_FF_USED] = 1;
|
||||
ramw_block[i]->params[id_FF_TYPE] = std::string("RAM");
|
||||
}
|
||||
|
||||
// Disconnect ports of original cell after packing
|
||||
// ci->disconnectPort(id_WCK);
|
||||
// ci->disconnectPort(id_WRE);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
ci->disconnectPort(ctx->id(stringf("RAD[%d]", i)));
|
||||
|
||||
// Setup placement constraints
|
||||
// Use the 0th bit as an anchor
|
||||
ram_comb[0]->constr_abs_z = true;
|
||||
ram_comb[0]->constr_z = 0;
|
||||
ram_comb[0]->cluster = ram_comb[0]->name;
|
||||
for (int i = 1; i < 4; i++) {
|
||||
ram_comb[i]->cluster = ram_comb[0]->name;
|
||||
ram_comb[i]->constr_abs_z = true;
|
||||
ram_comb[i]->constr_x = 0;
|
||||
ram_comb[i]->constr_y = 0;
|
||||
ram_comb[i]->constr_z = i;
|
||||
ram_comb[0]->constr_children.push_back(ram_comb[i].get());
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
ramw_block[i]->cluster = ram_comb[0]->name;
|
||||
ramw_block[i]->constr_abs_z = true;
|
||||
ramw_block[i]->constr_x = 0;
|
||||
ramw_block[i]->constr_y = 0;
|
||||
ramw_block[i]->constr_z = i + 4;
|
||||
ram_comb[0]->constr_children.push_back(ramw_block[i].get());
|
||||
}
|
||||
|
||||
ramw_slice->cluster = ram_comb[0]->name;
|
||||
ramw_slice->constr_abs_z = true;
|
||||
ramw_slice->constr_x = 0;
|
||||
ramw_slice->constr_y = 0;
|
||||
ramw_slice->constr_z = BelZ::lutram_0_z;
|
||||
ram_comb[0]->constr_children.push_back(ramw_slice.get());
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
new_cells.push_back(std::move(ram_comb[i]));
|
||||
for (int i = 0; i < 2; i++)
|
||||
new_cells.push_back(std::move(ramw_block[i]));
|
||||
new_cells.push_back(std::move(ramw_slice));
|
||||
packed_cells.insert(ci->name);
|
||||
}
|
||||
}
|
||||
for (auto pcell : packed_cells) {
|
||||
ctx->cells.erase(pcell);
|
||||
}
|
||||
for (auto &ncell : new_cells) {
|
||||
ctx->cells[ncell->name] = std::move(ncell);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool is_nextpnr_iob(const Context *ctx, CellInfo *cell)
|
||||
{
|
||||
return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") ||
|
||||
@ -1013,6 +1102,7 @@ bool Arch::pack()
|
||||
log_break();
|
||||
pre_pack(ctx);
|
||||
pack_constants(ctx);
|
||||
pack_sram(ctx);
|
||||
pack_gsr(ctx);
|
||||
pack_io(ctx);
|
||||
pack_diff_io(ctx);
|
||||
|
Loading…
Reference in New Issue
Block a user