mirror of https://github.com/YosysHQ/yosys.git
Merge pull request #4045 from povik/upstream-ql-k6n10f
Upstream QuickLogic k6n10f flow
This commit is contained in:
commit
8738143880
3
Makefile
3
Makefile
|
@ -880,7 +880,8 @@ endif
|
|||
+cd tests/arch/gowin && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/intel_alm && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/nexus && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/quicklogic && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/quicklogic/pp3 && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/quicklogic/qlf_k6n10f && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/gatemate && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/rpc && bash run-test.sh
|
||||
+cd tests/memfile && bash run-test.sh
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/*_pm.h
|
|
@ -1,13 +1,43 @@
|
|||
%_pm.h: passes/pmgen/pmgen.py %.pmg
|
||||
$(P) mkdir -p pmgen && $(PYTHON_EXECUTABLE) $< -o $@ -p $(subst _pm.h,,$(notdir $@)) $(filter-out $<,$^)
|
||||
|
||||
OBJS += techlibs/quicklogic/synth_quicklogic.o
|
||||
OBJS += techlibs/quicklogic/ql_bram_merge.o
|
||||
OBJS += techlibs/quicklogic/ql_bram_types.o
|
||||
OBJS += techlibs/quicklogic/ql_dsp_simd.o
|
||||
OBJS += techlibs/quicklogic/ql_dsp_io_regs.o
|
||||
|
||||
$(eval $(call add_share_file,share/quicklogic,techlibs/quicklogic/pp3_ffs_map.v))
|
||||
$(eval $(call add_share_file,share/quicklogic,techlibs/quicklogic/pp3_lut_map.v))
|
||||
$(eval $(call add_share_file,share/quicklogic,techlibs/quicklogic/pp3_latches_map.v))
|
||||
$(eval $(call add_share_file,share/quicklogic,techlibs/quicklogic/pp3_cells_map.v))
|
||||
$(eval $(call add_share_file,share/quicklogic,techlibs/quicklogic/cells_sim.v))
|
||||
$(eval $(call add_share_file,share/quicklogic,techlibs/quicklogic/lut_sim.v))
|
||||
$(eval $(call add_share_file,share/quicklogic,techlibs/quicklogic/pp3_cells_sim.v))
|
||||
# --------------------------------------
|
||||
|
||||
$(eval $(call add_share_file,share/quicklogic,techlibs/quicklogic/abc9_model.v))
|
||||
$(eval $(call add_share_file,share/quicklogic,techlibs/quicklogic/abc9_map.v))
|
||||
$(eval $(call add_share_file,share/quicklogic,techlibs/quicklogic/abc9_unmap.v))
|
||||
OBJS += techlibs/quicklogic/ql_dsp_macc.o
|
||||
GENFILES += techlibs/quicklogic/ql_dsp_macc_pm.h
|
||||
techlibs/quicklogic/ql_dsp_macc.o: techlibs/quicklogic/ql_dsp_macc_pm.h
|
||||
$(eval $(call add_extra_objs,techlibs/quicklogic/ql_dsp_macc_pm.h))
|
||||
|
||||
# --------------------------------------
|
||||
|
||||
$(eval $(call add_share_file,share/quicklogic/common,techlibs/quicklogic/common/cells_sim.v))
|
||||
|
||||
$(eval $(call add_share_file,share/quicklogic/pp3,techlibs/quicklogic/pp3/ffs_map.v))
|
||||
$(eval $(call add_share_file,share/quicklogic/pp3,techlibs/quicklogic/pp3/lut_map.v))
|
||||
$(eval $(call add_share_file,share/quicklogic/pp3,techlibs/quicklogic/pp3/latches_map.v))
|
||||
$(eval $(call add_share_file,share/quicklogic/pp3,techlibs/quicklogic/pp3/cells_map.v))
|
||||
$(eval $(call add_share_file,share/quicklogic/pp3,techlibs/quicklogic/pp3/cells_sim.v))
|
||||
$(eval $(call add_share_file,share/quicklogic/pp3,techlibs/quicklogic/pp3/abc9_model.v))
|
||||
$(eval $(call add_share_file,share/quicklogic/pp3,techlibs/quicklogic/pp3/abc9_map.v))
|
||||
$(eval $(call add_share_file,share/quicklogic/pp3,techlibs/quicklogic/pp3/abc9_unmap.v))
|
||||
|
||||
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/arith_map.v))
|
||||
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/libmap_brams.txt))
|
||||
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/libmap_brams_map.v))
|
||||
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/brams_map.v))
|
||||
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/brams_sim.v))
|
||||
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/bram_types_sim.v))
|
||||
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/cells_sim.v))
|
||||
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/ffs_map.v))
|
||||
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dsp_sim.v))
|
||||
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dsp_map.v))
|
||||
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dsp_final_map.v))
|
||||
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/TDP18K_FIFO.v))
|
||||
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/ufifo_ctl.v))
|
||||
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/sram1024x18_mem.v))
|
|
@ -1,76 +0,0 @@
|
|||
(* abc9_lut=1, lib_whitebox *)
|
||||
module LUT1 (
|
||||
output O,
|
||||
input I0
|
||||
);
|
||||
parameter [1:0] INIT = 0;
|
||||
parameter EQN = "(I0)";
|
||||
|
||||
// These timings are for PolarPro 3E; other families will need updating.
|
||||
specify
|
||||
(I0 => O) = 698; // FS -> FZ
|
||||
endspecify
|
||||
|
||||
assign O = I0 ? INIT[1] : INIT[0];
|
||||
endmodule
|
||||
|
||||
// TZ TSL TAB
|
||||
(* abc9_lut=2, lib_whitebox *)
|
||||
module LUT2 (
|
||||
output O,
|
||||
input I0, I1
|
||||
);
|
||||
parameter [3:0] INIT = 4'h0;
|
||||
parameter EQN = "(I0)";
|
||||
|
||||
// These timings are for PolarPro 3E; other families will need updating.
|
||||
specify
|
||||
(I0 => O) = 1251; // TAB -> TZ
|
||||
(I1 => O) = 1406; // TSL -> TZ
|
||||
endspecify
|
||||
|
||||
wire [1:0] s1 = I1 ? INIT[3:2] : INIT[1:0];
|
||||
assign O = I0 ? s1[1] : s1[0];
|
||||
endmodule
|
||||
|
||||
(* abc9_lut=2, lib_whitebox *)
|
||||
module LUT3 (
|
||||
output O,
|
||||
input I0, I1, I2
|
||||
);
|
||||
parameter [7:0] INIT = 8'h0;
|
||||
parameter EQN = "(I0)";
|
||||
|
||||
// These timings are for PolarPro 3E; other families will need updating.
|
||||
specify
|
||||
(I0 => O) = 1251; // TAB -> TZ
|
||||
(I1 => O) = 1406; // TSL -> TZ
|
||||
(I2 => O) = 1699; // ('TA1', 'TA2', 'TB1', 'TB2') -> TZ
|
||||
endspecify
|
||||
|
||||
wire [3:0] s2 = I2 ? INIT[7:4] : INIT[3:0];
|
||||
wire [1:0] s1 = I1 ? s2[3:2] : s2[1:0];
|
||||
assign O = I0 ? s1[1] : s1[0];
|
||||
endmodule
|
||||
|
||||
(* abc9_lut=4, lib_whitebox *)
|
||||
module LUT4 (
|
||||
output O,
|
||||
input I0, I1, I2, I3
|
||||
);
|
||||
parameter [15:0] INIT = 16'h0;
|
||||
parameter EQN = "(I0)";
|
||||
|
||||
// These timings are for PolarPro 3E; other families will need updating.
|
||||
specify
|
||||
(I0 => O) = 995; // TBS -> CZ
|
||||
(I1 => O) = 1437; // ('TAB', 'BAB') -> CZ
|
||||
(I2 => O) = 1593; // ('TSL', 'BSL') -> CZ
|
||||
(I3 => O) = 1887; // ('TA1', 'TA2', 'TB1', 'TB2', 'BA1', 'BA2', 'BB1', 'BB2') -> CZ
|
||||
endspecify
|
||||
|
||||
wire [7:0] s3 = I3 ? INIT[15:8] : INIT[7:0];
|
||||
wire [3:0] s2 = I2 ? s3[7:4] : s3[3:0];
|
||||
wire [1:0] s1 = I1 ? s2[3:2] : s2[1:0];
|
||||
assign O = I0 ? s1[1] : s1[0];
|
||||
endmodule
|
|
@ -327,3 +327,80 @@ module qlal4s3b_cell_macro (
|
|||
);
|
||||
|
||||
endmodule
|
||||
|
||||
(* abc9_lut=1, lib_whitebox *)
|
||||
module LUT1 (
|
||||
output O,
|
||||
input I0
|
||||
);
|
||||
parameter [1:0] INIT = 0;
|
||||
parameter EQN = "(I0)";
|
||||
|
||||
// These timings are for PolarPro 3E; other families will need updating.
|
||||
specify
|
||||
(I0 => O) = 698; // FS -> FZ
|
||||
endspecify
|
||||
|
||||
assign O = I0 ? INIT[1] : INIT[0];
|
||||
endmodule
|
||||
|
||||
// TZ TSL TAB
|
||||
(* abc9_lut=2, lib_whitebox *)
|
||||
module LUT2 (
|
||||
output O,
|
||||
input I0, I1
|
||||
);
|
||||
parameter [3:0] INIT = 4'h0;
|
||||
parameter EQN = "(I0)";
|
||||
|
||||
// These timings are for PolarPro 3E; other families will need updating.
|
||||
specify
|
||||
(I0 => O) = 1251; // TAB -> TZ
|
||||
(I1 => O) = 1406; // TSL -> TZ
|
||||
endspecify
|
||||
|
||||
wire [1:0] s1 = I1 ? INIT[3:2] : INIT[1:0];
|
||||
assign O = I0 ? s1[1] : s1[0];
|
||||
endmodule
|
||||
|
||||
(* abc9_lut=2, lib_whitebox *)
|
||||
module LUT3 (
|
||||
output O,
|
||||
input I0, I1, I2
|
||||
);
|
||||
parameter [7:0] INIT = 8'h0;
|
||||
parameter EQN = "(I0)";
|
||||
|
||||
// These timings are for PolarPro 3E; other families will need updating.
|
||||
specify
|
||||
(I0 => O) = 1251; // TAB -> TZ
|
||||
(I1 => O) = 1406; // TSL -> TZ
|
||||
(I2 => O) = 1699; // ('TA1', 'TA2', 'TB1', 'TB2') -> TZ
|
||||
endspecify
|
||||
|
||||
wire [3:0] s2 = I2 ? INIT[7:4] : INIT[3:0];
|
||||
wire [1:0] s1 = I1 ? s2[3:2] : s2[1:0];
|
||||
assign O = I0 ? s1[1] : s1[0];
|
||||
endmodule
|
||||
|
||||
(* abc9_lut=4, lib_whitebox *)
|
||||
module LUT4 (
|
||||
output O,
|
||||
input I0, I1, I2, I3
|
||||
);
|
||||
parameter [15:0] INIT = 16'h0;
|
||||
parameter EQN = "(I0)";
|
||||
|
||||
// These timings are for PolarPro 3E; other families will need updating.
|
||||
specify
|
||||
(I0 => O) = 995; // TBS -> CZ
|
||||
(I1 => O) = 1437; // ('TAB', 'BAB') -> CZ
|
||||
(I2 => O) = 1593; // ('TSL', 'BSL') -> CZ
|
||||
(I3 => O) = 1887; // ('TA1', 'TA2', 'TB1', 'TB2', 'BA1', 'BA2', 'BB1', 'BB2') -> CZ
|
||||
endspecify
|
||||
|
||||
wire [7:0] s3 = I3 ? INIT[15:8] : INIT[7:0];
|
||||
wire [3:0] s2 = I2 ? s3[7:4] : s3[3:0];
|
||||
wire [1:0] s1 = I1 ? s2[3:2] : s2[1:0];
|
||||
assign O = I0 ? s1[1] : s1[0];
|
||||
endmodule
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2023 N. Engelhardt <nak@yosyshq.com>
|
||||
*
|
||||
* 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/log.h"
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/rtlil.h"
|
||||
#include "kernel/sigtools.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
// ============================================================================
|
||||
|
||||
|
||||
|
||||
struct QlBramMergeWorker {
|
||||
|
||||
const RTLIL::IdString split_cell_type = ID($__QLF_TDP36K);
|
||||
const RTLIL::IdString merged_cell_type = ID($__QLF_TDP36K_MERGED);
|
||||
|
||||
// can be used to record parameter values that have to match on both sides
|
||||
typedef dict<RTLIL::IdString, RTLIL::Const> MergeableGroupKeyType;
|
||||
|
||||
RTLIL::Module *module;
|
||||
dict<MergeableGroupKeyType, pool<RTLIL::Cell*>> mergeable_groups;
|
||||
|
||||
QlBramMergeWorker(RTLIL::Module* module) : module(module)
|
||||
{
|
||||
for (RTLIL::Cell* cell : module->selected_cells())
|
||||
{
|
||||
if(cell->type != split_cell_type) continue;
|
||||
if(!cell->hasParam(ID(OPTION_SPLIT))) continue;
|
||||
if(cell->getParam(ID(OPTION_SPLIT)) != RTLIL::Const(1, 32)) continue;
|
||||
mergeable_groups[get_key(cell)].insert(cell);
|
||||
}
|
||||
}
|
||||
|
||||
static MergeableGroupKeyType get_key(RTLIL::Cell* cell)
|
||||
{
|
||||
MergeableGroupKeyType key;
|
||||
// For now, there are no restrictions on which cells can be merged
|
||||
(void) cell;
|
||||
return key;
|
||||
}
|
||||
|
||||
const dict<RTLIL::IdString, RTLIL::IdString>& param_map(bool second)
|
||||
{
|
||||
static const dict<RTLIL::IdString, RTLIL::IdString> bram1_map = {
|
||||
{ ID(INIT), ID(INIT1) },
|
||||
{ ID(PORT_A_WIDTH), ID(PORT_A1_WIDTH) },
|
||||
{ ID(PORT_B_WIDTH), ID(PORT_B1_WIDTH) },
|
||||
{ ID(PORT_A_WR_BE_WIDTH), ID(PORT_A1_WR_BE_WIDTH) },
|
||||
{ ID(PORT_B_WR_BE_WIDTH), ID(PORT_B1_WR_BE_WIDTH) }
|
||||
};
|
||||
static const dict<RTLIL::IdString, RTLIL::IdString> bram2_map = {
|
||||
{ ID(INIT), ID(INIT2) },
|
||||
{ ID(PORT_A_WIDTH), ID(PORT_A2_WIDTH) },
|
||||
{ ID(PORT_B_WIDTH), ID(PORT_B2_WIDTH) },
|
||||
{ ID(PORT_A_WR_BE_WIDTH), ID(PORT_A2_WR_BE_WIDTH) },
|
||||
{ ID(PORT_B_WR_BE_WIDTH), ID(PORT_B2_WR_BE_WIDTH) }
|
||||
};
|
||||
|
||||
if(second)
|
||||
return bram2_map;
|
||||
else
|
||||
return bram1_map;
|
||||
}
|
||||
|
||||
const dict<RTLIL::IdString, RTLIL::IdString>& port_map(bool second)
|
||||
{
|
||||
static const dict<RTLIL::IdString, RTLIL::IdString> bram1_map = {
|
||||
{ ID(PORT_A_CLK), ID(PORT_A1_CLK) },
|
||||
{ ID(PORT_B_CLK), ID(PORT_B1_CLK) },
|
||||
{ ID(PORT_A_CLK_EN), ID(PORT_A1_CLK_EN) },
|
||||
{ ID(PORT_B_CLK_EN), ID(PORT_B1_CLK_EN) },
|
||||
{ ID(PORT_A_ADDR), ID(PORT_A1_ADDR) },
|
||||
{ ID(PORT_B_ADDR), ID(PORT_B1_ADDR) },
|
||||
{ ID(PORT_A_WR_DATA), ID(PORT_A1_WR_DATA) },
|
||||
{ ID(PORT_B_WR_DATA), ID(PORT_B1_WR_DATA) },
|
||||
{ ID(PORT_A_WR_EN), ID(PORT_A1_WR_EN) },
|
||||
{ ID(PORT_B_WR_EN), ID(PORT_B1_WR_EN) },
|
||||
{ ID(PORT_A_WR_BE), ID(PORT_A1_WR_BE) },
|
||||
{ ID(PORT_B_WR_BE), ID(PORT_B1_WR_BE) },
|
||||
{ ID(PORT_A_RD_DATA), ID(PORT_A1_RD_DATA) },
|
||||
{ ID(PORT_B_RD_DATA), ID(PORT_B1_RD_DATA) }
|
||||
};
|
||||
static const dict<RTLIL::IdString, RTLIL::IdString> bram2_map = {
|
||||
{ ID(PORT_A_CLK), ID(PORT_A2_CLK) },
|
||||
{ ID(PORT_B_CLK), ID(PORT_B2_CLK) },
|
||||
{ ID(PORT_A_CLK_EN), ID(PORT_A2_CLK_EN) },
|
||||
{ ID(PORT_B_CLK_EN), ID(PORT_B2_CLK_EN) },
|
||||
{ ID(PORT_A_ADDR), ID(PORT_A2_ADDR) },
|
||||
{ ID(PORT_B_ADDR), ID(PORT_B2_ADDR) },
|
||||
{ ID(PORT_A_WR_DATA), ID(PORT_A2_WR_DATA) },
|
||||
{ ID(PORT_B_WR_DATA), ID(PORT_B2_WR_DATA) },
|
||||
{ ID(PORT_A_WR_EN), ID(PORT_A2_WR_EN) },
|
||||
{ ID(PORT_B_WR_EN), ID(PORT_B2_WR_EN) },
|
||||
{ ID(PORT_A_WR_BE), ID(PORT_A2_WR_BE) },
|
||||
{ ID(PORT_B_WR_BE), ID(PORT_B2_WR_BE) },
|
||||
{ ID(PORT_A_RD_DATA), ID(PORT_A2_RD_DATA) },
|
||||
{ ID(PORT_B_RD_DATA), ID(PORT_B2_RD_DATA) }
|
||||
};
|
||||
|
||||
if(second)
|
||||
return bram2_map;
|
||||
else
|
||||
return bram1_map;
|
||||
}
|
||||
|
||||
void merge_brams(RTLIL::Cell* bram1, RTLIL::Cell* bram2)
|
||||
{
|
||||
|
||||
// Create the new cell
|
||||
RTLIL::Cell* merged = module->addCell(NEW_ID, merged_cell_type);
|
||||
log_debug("Merging split BRAM cells %s and %s -> %s\n", log_id(bram1->name), log_id(bram2->name), log_id(merged->name));
|
||||
|
||||
for (auto &it : param_map(false))
|
||||
{
|
||||
if(bram1->hasParam(it.first))
|
||||
merged->setParam(it.second, bram1->getParam(it.first));
|
||||
}
|
||||
for (auto &it : param_map(true))
|
||||
{
|
||||
if(bram2->hasParam(it.first))
|
||||
merged->setParam(it.second, bram2->getParam(it.first));
|
||||
}
|
||||
|
||||
for (auto &it : port_map(false))
|
||||
{
|
||||
if (bram1->hasPort(it.first))
|
||||
merged->setPort(it.second, bram1->getPort(it.first));
|
||||
else
|
||||
log_error("Can't find port %s on cell %s!\n", log_id(it.first), log_id(bram1->name));
|
||||
}
|
||||
for (auto &it : port_map(true))
|
||||
{
|
||||
if (bram2->hasPort(it.first))
|
||||
merged->setPort(it.second, bram2->getPort(it.first));
|
||||
else
|
||||
log_error("Can't find port %s on cell %s!\n", log_id(it.first), log_id(bram2->name));
|
||||
}
|
||||
merged->attributes = bram1->attributes;
|
||||
for (auto attr: bram2->attributes)
|
||||
if (!merged->has_attribute(attr.first))
|
||||
merged->attributes.insert(attr);
|
||||
|
||||
// Remove the old cells
|
||||
module->remove(bram1);
|
||||
module->remove(bram2);
|
||||
|
||||
}
|
||||
|
||||
void merge_bram_groups()
|
||||
{
|
||||
for (auto &it : mergeable_groups)
|
||||
{
|
||||
while (it.second.size() > 1)
|
||||
{
|
||||
merge_brams(it.second.pop(), it.second.pop());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct QlBramMergePass : public Pass {
|
||||
|
||||
QlBramMergePass() : Pass("ql_bram_merge", "Infers QuickLogic k6n10f BRAM pairs that can operate independently") {}
|
||||
|
||||
void help() override
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" ql_bram_merge [selection]\n");
|
||||
log("\n");
|
||||
log(" This pass identifies k6n10f 18K BRAM cells and packs pairs of them together\n");
|
||||
log(" into a TDP36K cell operating in split mode\n");
|
||||
log("\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
log_header(design, "Executing QL_BRAM_MERGE pass.\n");
|
||||
|
||||
size_t argidx = 1;
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
for (RTLIL::Module* module : design->selected_modules())
|
||||
{
|
||||
QlBramMergeWorker worker(module);
|
||||
worker.merge_bram_groups();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} QlBramMergePass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2023 N. Engelhardt <nak@yosyshq.com>
|
||||
*
|
||||
* 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/log.h"
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/rtlil.h"
|
||||
#include "kernel/sigtools.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
// ============================================================================
|
||||
|
||||
|
||||
struct QlBramTypesPass : public Pass {
|
||||
|
||||
QlBramTypesPass() : Pass("ql_bram_types", "Change TDP36K type to subtypes") {}
|
||||
|
||||
void help() override
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" ql_bram_types [selection]\n");
|
||||
log("\n");
|
||||
log(" This pass changes the type of TDP36K cells to different types based on the\n");
|
||||
log(" configuration of the cell.\n");
|
||||
log("\n");
|
||||
}
|
||||
|
||||
int width_for_mode(int mode){
|
||||
// 1: mode = 3'b101;
|
||||
// 2: mode = 3'b110;
|
||||
// 4: mode = 3'b100;
|
||||
// 8,9: mode = 3'b001;
|
||||
// 16, 18: mode = 3'b010;
|
||||
// 32, 36: mode = 3'b011;
|
||||
switch (mode)
|
||||
{
|
||||
case 1:
|
||||
return 9;
|
||||
case 2:
|
||||
return 18;
|
||||
case 3:
|
||||
return 36;
|
||||
case 4:
|
||||
return 4;
|
||||
case 5:
|
||||
return 1;
|
||||
case 6:
|
||||
return 2;
|
||||
default:
|
||||
log_error("Invalid mode: %x", mode);
|
||||
}
|
||||
}
|
||||
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
log_header(design, "Executing QL_BRAM_TYPES pass.\n");
|
||||
|
||||
size_t argidx = 1;
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
for (RTLIL::Module* module : design->selected_modules())
|
||||
for (RTLIL::Cell* cell: module->selected_cells())
|
||||
{
|
||||
if (cell->type != ID(TDP36K) || !cell->hasParam(ID(MODE_BITS)))
|
||||
continue;
|
||||
|
||||
RTLIL::Const mode_bits = cell->getParam(ID(MODE_BITS));
|
||||
|
||||
bool split = mode_bits.extract(80).as_bool();
|
||||
|
||||
bool FMODE1_i = mode_bits.extract(13).as_bool();
|
||||
bool FMODE2_i = mode_bits.extract(54).as_bool();
|
||||
if (FMODE1_i != FMODE2_i) {
|
||||
log_debug("Can't change type of mixed use TDP36K block: FMODE1_i = %s, FMODE2_i = %s\n", FMODE1_i ? "true" : "false", FMODE2_i ? "true" : "false");
|
||||
continue;
|
||||
}
|
||||
bool is_fifo = FMODE1_i;
|
||||
|
||||
bool SYNC_FIFO1_i = mode_bits.extract(0).as_bool();
|
||||
bool SYNC_FIFO2_i = mode_bits.extract(41).as_bool();
|
||||
if (SYNC_FIFO1_i != SYNC_FIFO2_i) {
|
||||
log_debug("Can't change type of mixed use TDP36K block: SYNC_FIFO1_i = %s, SYNC_FIFO2_i = %s\n", SYNC_FIFO1_i ? "true" : "false", SYNC_FIFO2_i ? "true" : "false");
|
||||
continue;
|
||||
}
|
||||
bool sync_fifo = SYNC_FIFO1_i;
|
||||
|
||||
int RMODE_A1_i = mode_bits.extract(1, 3).as_int();
|
||||
int RMODE_B1_i = mode_bits.extract(4, 3).as_int();
|
||||
int WMODE_A1_i = mode_bits.extract(7, 3).as_int();
|
||||
int WMODE_B1_i = mode_bits.extract(10, 3).as_int();
|
||||
|
||||
int RMODE_A2_i = mode_bits.extract(42, 3).as_int();
|
||||
int RMODE_B2_i = mode_bits.extract(45, 3).as_int();
|
||||
int WMODE_A2_i = mode_bits.extract(48, 3).as_int();
|
||||
int WMODE_B2_i = mode_bits.extract(51, 3).as_int();
|
||||
|
||||
// TODO: should these be a warning or an error?
|
||||
if (RMODE_A1_i != WMODE_A1_i) {
|
||||
log_warning("Can't change type of misconfigured TDP36K block: Port A1 configured with read width = %d different from write width = %d\n", width_for_mode(RMODE_A1_i), width_for_mode(WMODE_A1_i));
|
||||
continue;
|
||||
}
|
||||
if (RMODE_B1_i != WMODE_B1_i) {
|
||||
log_warning("Can't change type of misconfigured TDP36K block: Port B1 configured with read width = %d different from write width = %d\n", width_for_mode(RMODE_B1_i), width_for_mode(WMODE_B1_i));
|
||||
continue;
|
||||
}
|
||||
if (RMODE_A2_i != WMODE_A2_i) {
|
||||
log_warning("Can't change type of misconfigured TDP36K block: Port A2 configured with read width = %d different from write width = %d\n", width_for_mode(RMODE_A2_i), width_for_mode(WMODE_A2_i));
|
||||
continue;
|
||||
}
|
||||
if (RMODE_B2_i != WMODE_B2_i) {
|
||||
log_warning("Can't change type of misconfigured TDP36K block: Port B2 configured with read width = %d different from write width = %d\n", width_for_mode(RMODE_B2_i), width_for_mode(WMODE_B2_i));
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: For nonsplit blocks, should RMODE_A1_i == RMODE_A2_i etc be checked/enforced?
|
||||
|
||||
std::string type = "TDP36K";
|
||||
if (is_fifo) {
|
||||
type += "_FIFO_";
|
||||
if (sync_fifo)
|
||||
type += "SYNC_";
|
||||
else
|
||||
type += "ASYNC_";
|
||||
} else
|
||||
type += "_BRAM_";
|
||||
|
||||
if (split) {
|
||||
type += stringf("A1_X%d_", width_for_mode(RMODE_A1_i));
|
||||
type += stringf("B1_X%d_", width_for_mode(RMODE_B1_i));
|
||||
type += stringf("A2_X%d_", width_for_mode(RMODE_A2_i));
|
||||
type += stringf("B2_X%d_", width_for_mode(RMODE_B2_i));
|
||||
type += "split";
|
||||
} else {
|
||||
type += stringf("A_X%d_", width_for_mode(RMODE_A1_i));
|
||||
type += stringf("B_X%d_", width_for_mode(RMODE_B1_i));
|
||||
type += "nonsplit";
|
||||
}
|
||||
|
||||
cell->type = RTLIL::escape_id(type);
|
||||
log_debug("Changed type of memory cell %s to %s\n", log_id(cell->name), log_id(cell->type));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} QlBramMergePass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright 2020-2022 F4PGA Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
#define MODE_BITS_REGISTER_INPUTS_ID 92
|
||||
#define MODE_BITS_OUTPUT_SELECT_START_ID 81
|
||||
#define MODE_BITS_OUTPUT_SELECT_WIDTH 3
|
||||
|
||||
// ============================================================================
|
||||
|
||||
struct QlDspIORegs : public Pass {
|
||||
const std::vector<IdString> ports2del_mult = {ID(load_acc), ID(subtract), ID(acc_fir), ID(dly_b),
|
||||
ID(saturate_enable), ID(shift_right), ID(round)};
|
||||
const std::vector<IdString> ports2del_mult_acc = {ID(acc_fir), ID(dly_b)};
|
||||
|
||||
SigMap sigmap;
|
||||
|
||||
// ..........................................
|
||||
|
||||
QlDspIORegs() : Pass("ql_dsp_io_regs", "change types of QL_DSP2 depending on configuration") {}
|
||||
|
||||
void help() override
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" ql_dsp_io_regs [options] [selection]\n");
|
||||
log("\n");
|
||||
log("This pass looks for QL_DSP2 cells and changes their cell type depending on their\n");
|
||||
log("configuration.\n");
|
||||
}
|
||||
|
||||
void execute(std::vector<std::string> a_Args, RTLIL::Design *a_Design) override
|
||||
{
|
||||
log_header(a_Design, "Executing QL_DSP_IO_REGS pass.\n");
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < a_Args.size(); argidx++) {
|
||||
break;
|
||||
}
|
||||
extra_args(a_Args, argidx, a_Design);
|
||||
|
||||
for (auto module : a_Design->selected_modules()) {
|
||||
ql_dsp_io_regs_pass(module);
|
||||
}
|
||||
}
|
||||
|
||||
void ql_dsp_io_regs_pass(RTLIL::Module *module)
|
||||
{
|
||||
sigmap.set(module);
|
||||
|
||||
for (auto cell : module->cells()) {
|
||||
if (cell->type != ID(QL_DSP2))
|
||||
continue;
|
||||
|
||||
// If the cell does not have the "is_inferred" attribute set
|
||||
// then don't touch it.
|
||||
if (!cell->get_bool_attribute(ID(is_inferred)))
|
||||
continue;
|
||||
|
||||
// Get DSP configuration
|
||||
for (auto cfg_port : {ID(register_inputs), ID(output_select)})
|
||||
if (!cell->hasPort(cfg_port) || !sigmap(cell->getPort(cfg_port)).is_fully_const())
|
||||
log_error("Missing or non-constant '%s' port on DSP cell %s\n",
|
||||
log_id(cfg_port), log_id(cell));
|
||||
int reg_in_i = sigmap(cell->getPort(ID(register_inputs))).as_int();
|
||||
int out_sel_i = sigmap(cell->getPort(ID(output_select))).as_int();
|
||||
|
||||
// Get the feedback port
|
||||
if (!cell->hasPort(ID(feedback)))
|
||||
log_error("Missing 'feedback' port on %s", log_id(cell));
|
||||
SigSpec feedback = sigmap(cell->getPort(ID(feedback)));
|
||||
|
||||
// Check the top two bits on 'feedback' to be constant zero.
|
||||
// That's what we are expecting from inference.
|
||||
if (feedback.extract(1, 2) != SigSpec(0, 2))
|
||||
log_error("Unexpected feedback configuration on %s\n", log_id(cell));
|
||||
|
||||
// Build new type name
|
||||
std::string new_type = "\\QL_DSP2_MULT";
|
||||
|
||||
// Decide if we should be deleting the clock port
|
||||
bool del_clk = true;
|
||||
|
||||
switch (out_sel_i) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
del_clk = false;
|
||||
new_type += "ACC";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (reg_in_i) {
|
||||
del_clk = false;
|
||||
new_type += "_REGIN";
|
||||
}
|
||||
|
||||
if (out_sel_i > 3) {
|
||||
del_clk = false;
|
||||
new_type += "_REGOUT";
|
||||
}
|
||||
|
||||
// Set new type name
|
||||
cell->type = RTLIL::IdString(new_type);
|
||||
|
||||
std::vector<std::string> ports2del;
|
||||
|
||||
if (del_clk)
|
||||
cell->unsetPort(ID(clk));
|
||||
|
||||
switch (out_sel_i) {
|
||||
case 0:
|
||||
case 4:
|
||||
case 6:
|
||||
for (auto port : ports2del_mult)
|
||||
cell->unsetPort(port);
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
for (auto port : ports2del_mult_acc)
|
||||
cell->unsetPort(port);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} QlDspIORegs;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* Copyright 2020-2022 F4PGA Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
#include "ql_dsp_macc_pm.h"
|
||||
|
||||
// ============================================================================
|
||||
|
||||
static void create_ql_macc_dsp(ql_dsp_macc_pm &pm)
|
||||
{
|
||||
auto &st = pm.st_ql_dsp_macc;
|
||||
|
||||
// Get port widths
|
||||
size_t a_width = GetSize(st.mul->getPort(ID(A)));
|
||||
size_t b_width = GetSize(st.mul->getPort(ID(B)));
|
||||
size_t z_width = GetSize(st.ff->getPort(ID(Q)));
|
||||
|
||||
size_t min_width = std::min(a_width, b_width);
|
||||
size_t max_width = std::max(a_width, b_width);
|
||||
|
||||
// Signed / unsigned
|
||||
bool ab_signed = st.mul->getParam(ID(A_SIGNED)).as_bool();
|
||||
log_assert(ab_signed == st.mul->getParam(ID(B_SIGNED)).as_bool());
|
||||
|
||||
// Determine DSP type or discard if too narrow / wide
|
||||
RTLIL::IdString type;
|
||||
size_t tgt_a_width;
|
||||
size_t tgt_b_width;
|
||||
size_t tgt_z_width;
|
||||
|
||||
string cell_base_name = "dsp_t1";
|
||||
string cell_size_name = "";
|
||||
string cell_cfg_name = "";
|
||||
string cell_full_name = "";
|
||||
|
||||
if (min_width <= 2 && max_width <= 2 && z_width <= 4) {
|
||||
log_debug("\trejected: too narrow (%zd %zd %zd)\n", min_width, max_width, z_width);
|
||||
return;
|
||||
} else if (min_width <= 9 && max_width <= 10 && z_width <= 19) {
|
||||
cell_size_name = "_10x9x32";
|
||||
tgt_a_width = 10;
|
||||
tgt_b_width = 9;
|
||||
tgt_z_width = 19;
|
||||
} else if (min_width <= 18 && max_width <= 20 && z_width <= 38) {
|
||||
cell_size_name = "_20x18x64";
|
||||
tgt_a_width = 20;
|
||||
tgt_b_width = 18;
|
||||
tgt_z_width = 38;
|
||||
} else {
|
||||
log_debug("\trejected: too wide (%zd %zd %zd)\n", min_width, max_width, z_width);
|
||||
return;
|
||||
}
|
||||
|
||||
type = RTLIL::escape_id(cell_base_name + cell_size_name + "_cfg_ports");
|
||||
log("Inferring MACC %zux%zu->%zu as %s from:\n", a_width, b_width, z_width, log_id(type));
|
||||
|
||||
for (auto cell : {st.mul, st.add, st.mux, st.ff})
|
||||
if (cell)
|
||||
log(" %s (%s)\n", log_id(cell), log_id(cell->type));
|
||||
|
||||
// Add the DSP cell
|
||||
RTLIL::Cell *cell = pm.module->addCell(NEW_ID, type);
|
||||
|
||||
// Set attributes
|
||||
cell->set_bool_attribute(ID(is_inferred), true);
|
||||
|
||||
// Get input/output data signals
|
||||
RTLIL::SigSpec sig_a, sig_b, sig_z;
|
||||
sig_a = st.mul->getPort(ID(A));
|
||||
sig_b = st.mul->getPort(ID(B));
|
||||
sig_z = st.output_registered ? st.ff->getPort(ID(Q)) : st.ff->getPort(ID(D));
|
||||
|
||||
if (a_width < b_width)
|
||||
std::swap(sig_a, sig_b);
|
||||
|
||||
// Connect input data ports, sign extend / pad with zeros
|
||||
sig_a.extend_u0(tgt_a_width, ab_signed);
|
||||
sig_b.extend_u0(tgt_b_width, ab_signed);
|
||||
cell->setPort(ID(a_i), sig_a);
|
||||
cell->setPort(ID(b_i), sig_b);
|
||||
|
||||
// Connect output data port, pad if needed
|
||||
if ((size_t) GetSize(sig_z) < tgt_z_width) {
|
||||
auto *wire = pm.module->addWire(NEW_ID, tgt_z_width - GetSize(sig_z));
|
||||
sig_z.append(wire);
|
||||
}
|
||||
cell->setPort(ID(z_o), sig_z);
|
||||
|
||||
// Connect clock, reset and enable
|
||||
cell->setPort(ID(clock_i), st.ff->getPort(ID(CLK)));
|
||||
|
||||
RTLIL::SigSpec rst;
|
||||
RTLIL::SigSpec ena;
|
||||
|
||||
if (st.ff->hasPort(ID(ARST))) {
|
||||
if (st.ff->getParam(ID(ARST_POLARITY)).as_int() != 1) {
|
||||
rst = pm.module->Not(NEW_ID, st.ff->getPort(ID(ARST)));
|
||||
} else {
|
||||
rst = st.ff->getPort(ID(ARST));
|
||||
}
|
||||
} else {
|
||||
rst = RTLIL::SigSpec(RTLIL::S0);
|
||||
}
|
||||
|
||||
if (st.ff->hasPort(ID(EN))) {
|
||||
if (st.ff->getParam(ID(EN_POLARITY)).as_int() != 1) {
|
||||
ena = pm.module->Not(NEW_ID, st.ff->getPort(ID(EN)));
|
||||
} else {
|
||||
ena = st.ff->getPort(ID(EN));
|
||||
}
|
||||
} else {
|
||||
ena = RTLIL::SigSpec(RTLIL::S1);
|
||||
}
|
||||
|
||||
cell->setPort(ID(reset_i), rst);
|
||||
cell->setPort(ID(load_acc_i), ena);
|
||||
|
||||
// Insert feedback_i control logic used for clearing / loading the accumulator
|
||||
if (st.mux_in_pattern) {
|
||||
RTLIL::SigSpec sig_s = st.mux->getPort(ID(S));
|
||||
|
||||
// Depending on the mux port ordering insert inverter if needed
|
||||
log_assert(st.mux_ab.in(ID(A), ID(B)));
|
||||
if (st.mux_ab == ID(A))
|
||||
sig_s = pm.module->Not(NEW_ID, sig_s);
|
||||
|
||||
// Assemble the full control signal for the feedback_i port
|
||||
RTLIL::SigSpec sig_f;
|
||||
sig_f.append(sig_s);
|
||||
sig_f.append(RTLIL::S0);
|
||||
sig_f.append(RTLIL::S0);
|
||||
cell->setPort(ID(feedback_i), sig_f);
|
||||
}
|
||||
// No acc clear/load
|
||||
else {
|
||||
cell->setPort(ID(feedback_i), RTLIL::SigSpec(RTLIL::S0, 3));
|
||||
}
|
||||
|
||||
// Connect control ports
|
||||
cell->setPort(ID(unsigned_a_i), RTLIL::SigSpec(ab_signed ? RTLIL::S0 : RTLIL::S1));
|
||||
cell->setPort(ID(unsigned_b_i), RTLIL::SigSpec(ab_signed ? RTLIL::S0 : RTLIL::S1));
|
||||
|
||||
// Connect config bits
|
||||
cell->setPort(ID(saturate_enable_i), RTLIL::SigSpec(RTLIL::S0));
|
||||
cell->setPort(ID(shift_right_i), RTLIL::SigSpec(RTLIL::S0, 6));
|
||||
cell->setPort(ID(round_i), RTLIL::SigSpec(RTLIL::S0));
|
||||
cell->setPort(ID(register_inputs_i), RTLIL::SigSpec(RTLIL::S0));
|
||||
// 3 - output post acc; 1 - output pre acc
|
||||
cell->setPort(ID(output_select_i), RTLIL::Const(st.output_registered ? 1 : 3, 3));
|
||||
|
||||
bool subtract = (st.add->type == ID($sub));
|
||||
cell->setPort(ID(subtract_i), RTLIL::SigSpec(subtract ? RTLIL::S1 : RTLIL::S0));
|
||||
|
||||
// Mark the cells for removal
|
||||
pm.autoremove(st.mul);
|
||||
pm.autoremove(st.add);
|
||||
if (st.mux != nullptr) {
|
||||
pm.autoremove(st.mux);
|
||||
}
|
||||
pm.autoremove(st.ff);
|
||||
}
|
||||
|
||||
struct QlDspMacc : public Pass {
|
||||
QlDspMacc() : Pass("ql_dsp_macc", "infer QuickLogic multiplier-accumulator DSP cells") {}
|
||||
|
||||
void help() override
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" ql_dsp_macc [selection]\n");
|
||||
log("\n");
|
||||
log("This pass looks for a multiply-accumulate pattern based on which it infers a\n");
|
||||
log("QuickLogic DSP cell.\n");
|
||||
log("\n");
|
||||
}
|
||||
|
||||
void execute(std::vector<std::string> a_Args, RTLIL::Design *a_Design) override
|
||||
{
|
||||
log_header(a_Design, "Executing QL_DSP_MACC pass.\n");
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < a_Args.size(); argidx++) {
|
||||
break;
|
||||
}
|
||||
extra_args(a_Args, argidx, a_Design);
|
||||
|
||||
for (auto module : a_Design->selected_modules())
|
||||
ql_dsp_macc_pm(module, module->selected_cells()).run_ql_dsp_macc(create_ql_macc_dsp);
|
||||
}
|
||||
|
||||
} QlDspMacc;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
|
@ -0,0 +1,77 @@
|
|||
pattern ql_dsp_macc
|
||||
// Rough sketch: (mux is optional)
|
||||
//
|
||||
// /-----------------------\
|
||||
// | |
|
||||
// \ / |
|
||||
// mul ----> add -----> mux -----> ff -+---->
|
||||
// | /\
|
||||
// | |
|
||||
// --------------
|
||||
|
||||
state <IdString> add_ba
|
||||
state <IdString> mux_ab
|
||||
|
||||
// Is the output taken from before or after the FF?
|
||||
state <bool> output_registered
|
||||
|
||||
// Is there a mux in the pattern?
|
||||
state <bool> mux_in_pattern
|
||||
|
||||
code mux_in_pattern
|
||||
mux_in_pattern = false;
|
||||
branch;
|
||||
mux_in_pattern = true;
|
||||
endcode
|
||||
|
||||
// The multiplier is at the center of our pattern
|
||||
match mul
|
||||
select mul->type.in($mul)
|
||||
// It has either two or three consumers depending on whether there's a mux
|
||||
// in the pattern or not
|
||||
select nusers(port(mul, \Y)) <= 3
|
||||
filter nusers(port(mul, \Y)) == (mux_in_pattern ? 3 : 2)
|
||||
endmatch
|
||||
|
||||
code output_registered
|
||||
output_registered = false;
|
||||
branch;
|
||||
output_registered = true;
|
||||
endcode
|
||||
|
||||
match add
|
||||
select add->type.in($add, $sub)
|
||||
choice <IdString> AB {\A, \B}
|
||||
define <IdString> BA (AB == \A ? \B : \A)
|
||||
// One input to the adder is fed by the multiplier
|
||||
index <SigSpec> port(add, AB) === port(mul, \Y)
|
||||
// Save the other input port, it needs to be fed by the flip-flop
|
||||
set add_ba BA
|
||||
// Adder has either two or three consumers; it will have three consumers
|
||||
// IFF there's no mux in the pattern and the multiplier-accumulator result
|
||||
// is taken unregistered
|
||||
filter nusers(port(add, \Y)) == (!mux_in_pattern && !output_registered ? 3 : 2)
|
||||
endmatch
|
||||
|
||||
match mux
|
||||
if mux_in_pattern
|
||||
select mux->type.in($mux)
|
||||
choice <IdString> AB {\A, \B}
|
||||
define <IdString> BA (AB == \A ? \B : \A)
|
||||
index <SigSpec> port(mux, AB) === port(mul, \Y)
|
||||
index <SigSpec> port(mux, BA) === port(add, \Y)
|
||||
filter nusers(port(mux, \Y)) == (output_registered ? 2 : 3)
|
||||
set mux_ab AB
|
||||
endmatch
|
||||
|
||||
match ff
|
||||
select ff->type.in($dff, $adff, $dffe, $adffe)
|
||||
select param(ff, \CLK_POLARITY).as_bool()
|
||||
index <SigSpec> port(ff, \D) === mux_in_pattern ? port(mux, \Y) : port(add, \Y);
|
||||
index <SigSpec> port(ff, \Q) === port(add, add_ba)
|
||||
filter nusers(port(ff, \Q)) == (output_registered ? 3 : 2)
|
||||
endmatch
|
||||
|
||||
code
|
||||
accept;
|
||||
endcode
|
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
* Copyright 2020-2022 F4PGA Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "kernel/log.h"
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/rtlil.h"
|
||||
#include "kernel/sigtools.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
// ============================================================================
|
||||
|
||||
struct QlDspSimdPass : public Pass {
|
||||
|
||||
QlDspSimdPass() : Pass("ql_dsp_simd", "merge QuickLogic K6N10f DSP pairs to operate in SIMD mode") {}
|
||||
|
||||
void help() override
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" ql_dsp_simd [selection]\n");
|
||||
log("\n");
|
||||
log("This pass identifies K6N10f DSP cells with identical configuration and pack pairs\n");
|
||||
log("of them together into other DSP cells that can perform SIMD operation.\n");
|
||||
}
|
||||
|
||||
// ..........................................
|
||||
|
||||
/// Describes DSP config unique to a whole DSP cell
|
||||
struct DspConfig {
|
||||
// Port connections
|
||||
dict<RTLIL::IdString, RTLIL::SigSpec> connections;
|
||||
|
||||
DspConfig() = default;
|
||||
|
||||
DspConfig(const DspConfig &ref) = default;
|
||||
DspConfig(DspConfig &&ref) = default;
|
||||
|
||||
unsigned int hash() const { return connections.hash(); }
|
||||
|
||||
bool operator==(const DspConfig &ref) const { return connections == ref.connections; }
|
||||
};
|
||||
|
||||
// ..........................................
|
||||
|
||||
// DSP control and config ports to consider and how to map them to ports
|
||||
// of the target DSP cell
|
||||
const std::vector<std::pair<IdString, IdString>> m_DspCfgPorts = {
|
||||
std::make_pair(ID(clock_i), ID(clk)),
|
||||
std::make_pair(ID(reset_i), ID(reset)),
|
||||
std::make_pair(ID(feedback_i), ID(feedback)),
|
||||
std::make_pair(ID(load_acc_i), ID(load_acc)),
|
||||
std::make_pair(ID(unsigned_a_i), ID(unsigned_a)),
|
||||
std::make_pair(ID(unsigned_b_i), ID(unsigned_b)),
|
||||
std::make_pair(ID(subtract_i), ID(subtract)),
|
||||
std::make_pair(ID(output_select_i), ID(output_select)),
|
||||
std::make_pair(ID(saturate_enable_i), ID(saturate_enable)),
|
||||
std::make_pair(ID(shift_right_i), ID(shift_right)),
|
||||
std::make_pair(ID(round_i), ID(round)),
|
||||
std::make_pair(ID(register_inputs_i), ID(register_inputs))
|
||||
};
|
||||
|
||||
const int m_ModeBitsSize = 80;
|
||||
|
||||
// DSP data ports and how to map them to ports of the target DSP cell
|
||||
const std::vector<std::pair<IdString, IdString>> m_DspDataPorts = {
|
||||
std::make_pair(ID(a_i), ID(a)),
|
||||
std::make_pair(ID(b_i), ID(b)),
|
||||
std::make_pair(ID(acc_fir_i), ID(acc_fir)),
|
||||
std::make_pair(ID(z_o), ID(z)),
|
||||
std::make_pair(ID(dly_b_o), ID(dly_b))
|
||||
};
|
||||
|
||||
// DSP parameters
|
||||
const std::vector<std::string> m_DspParams = {"COEFF_3", "COEFF_2", "COEFF_1", "COEFF_0"};
|
||||
|
||||
// Source DSP cell type (SISD)
|
||||
const IdString m_SisdDspType = ID(dsp_t1_10x9x32);
|
||||
|
||||
// Target DSP cell types for the SIMD mode
|
||||
const IdString m_SimdDspType = ID(QL_DSP2);
|
||||
|
||||
/// Temporary SigBit to SigBit helper map.
|
||||
SigMap sigmap;
|
||||
|
||||
// ..........................................
|
||||
|
||||
void execute(std::vector<std::string> a_Args, RTLIL::Design *a_Design) override
|
||||
{
|
||||
log_header(a_Design, "Executing QL_DSP_SIMD pass.\n");
|
||||
|
||||
// Parse args
|
||||
extra_args(a_Args, 1, a_Design);
|
||||
|
||||
// Process modules
|
||||
for (auto module : a_Design->selected_modules()) {
|
||||
// Setup the SigMap
|
||||
sigmap.set(module);
|
||||
|
||||
// Assemble DSP cell groups
|
||||
dict<DspConfig, std::vector<RTLIL::Cell *>> groups;
|
||||
for (auto cell : module->selected_cells()) {
|
||||
// Check if this is a DSP cell we are looking for (type starts with m_SisdDspType)
|
||||
if (cell->type != m_SisdDspType)
|
||||
continue;
|
||||
|
||||
// Skip if it has the (* keep *) attribute set
|
||||
if (cell->has_keep_attr())
|
||||
continue;
|
||||
|
||||
// Add to a group
|
||||
const auto key = getDspConfig(cell);
|
||||
groups[key].push_back(cell);
|
||||
}
|
||||
|
||||
std::vector<Cell *> cellsToRemove;
|
||||
|
||||
// Map cell pairs to the target DSP SIMD cell
|
||||
for (const auto &it : groups) {
|
||||
const auto &group = it.second;
|
||||
const auto &config = it.first;
|
||||
|
||||
// Ensure an even number
|
||||
size_t count = group.size();
|
||||
if (count & 1)
|
||||
count--;
|
||||
|
||||
// Map SIMD pairs
|
||||
for (size_t i = 0; i < count; i += 2) {
|
||||
Cell *dsp_a = group[i];
|
||||
Cell *dsp_b = group[i + 1];
|
||||
|
||||
// Create the new cell
|
||||
Cell *simd = module->addCell(NEW_ID, m_SimdDspType);
|
||||
|
||||
log(" SIMD: %s (%s) + %s (%s) => %s (%s)\n", log_id(dsp_a), log_id(dsp_a->type),
|
||||
log_id(dsp_b), log_id(dsp_b->type), log_id(simd), log_id(simd->type));
|
||||
|
||||
// Check if the target cell is known (important to know
|
||||
// its port widths)
|
||||
if (!simd->known())
|
||||
log_error(" The target cell type '%s' is not known!", log_id(simd));
|
||||
|
||||
// Connect common ports
|
||||
for (const auto &it : m_DspCfgPorts)
|
||||
simd->setPort(it.first, config.connections.at(it.second));
|
||||
|
||||
// Connect data ports
|
||||
for (const auto &it : m_DspDataPorts) {
|
||||
size_t width;
|
||||
bool isOutput;
|
||||
|
||||
std::tie(width, isOutput) = getPortInfo(simd, it.second);
|
||||
|
||||
auto getConnection = [&](const RTLIL::Cell *cell) {
|
||||
RTLIL::SigSpec sigspec;
|
||||
if (cell->hasPort(it.first)) {
|
||||
const auto &sig = cell->getPort(it.first);
|
||||
sigspec.append(sig);
|
||||
}
|
||||
|
||||
int padding = width / 2 - sigspec.bits().size();
|
||||
|
||||
if (padding) {
|
||||
if (!isOutput)
|
||||
sigspec.append(RTLIL::SigSpec(RTLIL::Sx, padding));
|
||||
else
|
||||
sigspec.append(module->addWire(NEW_ID, padding));
|
||||
}
|
||||
return sigspec;
|
||||
};
|
||||
|
||||
RTLIL::SigSpec sigspec;
|
||||
sigspec.append(getConnection(dsp_a));
|
||||
sigspec.append(getConnection(dsp_b));
|
||||
simd->setPort(it.second, sigspec);
|
||||
}
|
||||
|
||||
// Concatenate FIR coefficient parameters into the single
|
||||
// MODE_BITS parameter
|
||||
Const mode_bits;
|
||||
for (const auto &it : m_DspParams) {
|
||||
auto val_a = dsp_a->getParam(it);
|
||||
auto val_b = dsp_b->getParam(it);
|
||||
|
||||
mode_bits.bits.insert(mode_bits.end(), val_a.begin(), val_a.end());
|
||||
mode_bits.bits.insert(mode_bits.end(), val_b.begin(), val_b.end());
|
||||
}
|
||||
|
||||
// Enable the fractured mode by connecting the control
|
||||
// port.
|
||||
simd->setPort(ID(f_mode), State::S1);
|
||||
simd->setParam(ID(MODE_BITS), mode_bits);
|
||||
log_assert(mode_bits.size() == m_ModeBitsSize);
|
||||
|
||||
// Handle the "is_inferred" attribute. If one of the fragments
|
||||
// is not inferred mark the whole DSP as not inferred
|
||||
bool is_inferred_a = dsp_a->get_bool_attribute(ID(is_inferred));
|
||||
bool is_inferred_b = dsp_b->get_bool_attribute(ID(is_inferred));
|
||||
simd->set_bool_attribute(ID(is_inferred), is_inferred_a && is_inferred_b);
|
||||
|
||||
// Mark DSP parts for removal
|
||||
cellsToRemove.push_back(dsp_a);
|
||||
cellsToRemove.push_back(dsp_b);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove old cells
|
||||
for (auto cell : cellsToRemove)
|
||||
module->remove(cell);
|
||||
}
|
||||
}
|
||||
|
||||
// ..........................................
|
||||
|
||||
/// Looks up port width and direction in the cell definition and returns it.
|
||||
/// Returns (0, false) if it cannot be determined.
|
||||
std::pair<size_t, bool> getPortInfo(RTLIL::Cell *a_Cell, RTLIL::IdString a_Port)
|
||||
{
|
||||
if (!a_Cell->known()) {
|
||||
return std::make_pair(0, false);
|
||||
}
|
||||
|
||||
// Get the module defining the cell (the previous condition ensures
|
||||
// that the pointers are valid)
|
||||
RTLIL::Module *mod = a_Cell->module->design->module(a_Cell->type);
|
||||
if (mod == nullptr) {
|
||||
return std::make_pair(0, false);
|
||||
}
|
||||
|
||||
// Get the wire representing the port
|
||||
RTLIL::Wire *wire = mod->wire(a_Port);
|
||||
if (wire == nullptr) {
|
||||
return std::make_pair(0, false);
|
||||
}
|
||||
|
||||
return std::make_pair(wire->width, wire->port_output);
|
||||
}
|
||||
|
||||
/// Given a DSP cell populates and returns a DspConfig struct for it.
|
||||
DspConfig getDspConfig(RTLIL::Cell *a_Cell)
|
||||
{
|
||||
DspConfig config;
|
||||
|
||||
for (const auto &it : m_DspCfgPorts) {
|
||||
auto port = it.first;
|
||||
|
||||
// Port unconnected
|
||||
if (!a_Cell->hasPort(port))
|
||||
continue;
|
||||
|
||||
config.connections[port] = sigmap(a_Cell->getPort(port));
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
} QlDspSimdPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
|
@ -0,0 +1,344 @@
|
|||
// Copyright 2020-2022 F4PGA Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
`default_nettype wire
|
||||
module TDP18K_FIFO (
|
||||
RMODE_A_i,
|
||||
RMODE_B_i,
|
||||
WMODE_A_i,
|
||||
WMODE_B_i,
|
||||
WEN_A_i,
|
||||
WEN_B_i,
|
||||
REN_A_i,
|
||||
REN_B_i,
|
||||
CLK_A_i,
|
||||
CLK_B_i,
|
||||
BE_A_i,
|
||||
BE_B_i,
|
||||
ADDR_A_i,
|
||||
ADDR_B_i,
|
||||
WDATA_A_i,
|
||||
WDATA_B_i,
|
||||
RDATA_A_o,
|
||||
RDATA_B_o,
|
||||
EMPTY_o,
|
||||
EPO_o,
|
||||
EWM_o,
|
||||
UNDERRUN_o,
|
||||
FULL_o,
|
||||
FMO_o,
|
||||
FWM_o,
|
||||
OVERRUN_o,
|
||||
FLUSH_ni,
|
||||
FMODE_i,
|
||||
);
|
||||
parameter SYNC_FIFO_i = 1'b0;
|
||||
parameter POWERDN_i = 1'b0;
|
||||
parameter SLEEP_i = 1'b0;
|
||||
parameter PROTECT_i = 1'b0;
|
||||
parameter UPAF_i = 11'b0;
|
||||
parameter UPAE_i = 11'b0;
|
||||
parameter [18*1024-1:0] INIT_i = 18431'bx;
|
||||
|
||||
input wire [2:0] RMODE_A_i;
|
||||
input wire [2:0] RMODE_B_i;
|
||||
input wire [2:0] WMODE_A_i;
|
||||
input wire [2:0] WMODE_B_i;
|
||||
input wire WEN_A_i;
|
||||
input wire WEN_B_i;
|
||||
input wire REN_A_i;
|
||||
input wire REN_B_i;
|
||||
(* clkbuf_sink *)
|
||||
input wire CLK_A_i;
|
||||
(* clkbuf_sink *)
|
||||
input wire CLK_B_i;
|
||||
input wire [1:0] BE_A_i;
|
||||
input wire [1:0] BE_B_i;
|
||||
input wire [13:0] ADDR_A_i;
|
||||
input wire [13:0] ADDR_B_i;
|
||||
input wire [17:0] WDATA_A_i;
|
||||
input wire [17:0] WDATA_B_i;
|
||||
output reg [17:0] RDATA_A_o;
|
||||
output reg [17:0] RDATA_B_o;
|
||||
output wire EMPTY_o;
|
||||
output wire EPO_o;
|
||||
output wire EWM_o;
|
||||
output wire UNDERRUN_o;
|
||||
output wire FULL_o;
|
||||
output wire FMO_o;
|
||||
output wire FWM_o;
|
||||
output wire OVERRUN_o;
|
||||
input wire FLUSH_ni;
|
||||
input wire FMODE_i;
|
||||
reg [17:0] wmsk_a;
|
||||
reg [17:0] wmsk_b;
|
||||
wire [8:0] addr_a;
|
||||
wire [8:0] addr_b;
|
||||
reg [4:0] addr_a_d;
|
||||
reg [4:0] addr_b_d;
|
||||
wire [17:0] ram_rdata_a;
|
||||
wire [17:0] ram_rdata_b;
|
||||
reg [17:0] aligned_wdata_a;
|
||||
reg [17:0] aligned_wdata_b;
|
||||
wire ren_o;
|
||||
wire [10:0] ff_raddr;
|
||||
wire [10:0] ff_waddr;
|
||||
wire [13:0] ram_addr_a;
|
||||
wire [13:0] ram_addr_b;
|
||||
wire [3:0] ram_waddr_a;
|
||||
wire [3:0] ram_waddr_b;
|
||||
wire initn;
|
||||
wire smux_rclk;
|
||||
wire smux_wclk;
|
||||
wire real_fmode;
|
||||
wire [3:0] raw_fflags;
|
||||
reg [1:0] fifo_rmode;
|
||||
reg [1:0] fifo_wmode;
|
||||
wire smux_clk_a;
|
||||
wire smux_clk_b;
|
||||
wire ram_ren_a;
|
||||
wire ram_ren_b;
|
||||
wire ram_wen_a;
|
||||
wire ram_wen_b;
|
||||
wire cen_a;
|
||||
wire cen_b;
|
||||
wire cen_a_n;
|
||||
wire cen_b_n;
|
||||
wire ram_wen_a_n;
|
||||
wire ram_wen_b_n;
|
||||
localparam MODE_9 = 3'b001;
|
||||
always @(*) begin
|
||||
fifo_rmode = (RMODE_B_i == MODE_9 ? 2'b10 : 2'b01);
|
||||
fifo_wmode = (WMODE_A_i == MODE_9 ? 2'b10 : 2'b01);
|
||||
end
|
||||
assign smux_clk_a = CLK_A_i;
|
||||
assign smux_clk_b = CLK_B_i;
|
||||
assign real_fmode = FMODE_i;
|
||||
assign ram_ren_b = real_fmode ? ren_o : REN_B_i;
|
||||
assign ram_wen_a = FMODE_i ? ~FULL_o & WEN_A_i : WEN_A_i;
|
||||
assign ram_ren_a = FMODE_i ? 0 : REN_A_i;
|
||||
assign ram_wen_b = FMODE_i ? 1'b0 : WEN_B_i;
|
||||
assign cen_b = ram_ren_b | ram_wen_b;
|
||||
assign cen_a = ram_ren_a | ram_wen_a;
|
||||
assign ram_waddr_b = real_fmode ? {ff_raddr[0], 3'b000} : ADDR_B_i[3:0];
|
||||
assign ram_waddr_a = real_fmode ? {ff_waddr[0], 3'b000} : ADDR_A_i[3:0];
|
||||
assign ram_addr_b = real_fmode ? {ff_raddr[10:0], 3'h0} : {ADDR_B_i[13:4], addr_b_d[3:0]};
|
||||
assign ram_addr_a = real_fmode ? {ff_waddr[10:0], 3'h0} : {ADDR_A_i[13:4], addr_a_d[3:0]};
|
||||
always @(posedge CLK_A_i) addr_a_d[3:0] <= ADDR_A_i[3:0];
|
||||
always @(posedge CLK_B_i) addr_b_d[3:0] <= ADDR_B_i[3:0];
|
||||
assign cen_a_n = ~cen_a;
|
||||
assign ram_wen_a_n = ~ram_wen_a;
|
||||
assign cen_b_n = ~cen_b;
|
||||
assign ram_wen_b_n = ~ram_wen_b;
|
||||
|
||||
sram1024x18 #(
|
||||
.init(INIT_i)
|
||||
) uram(
|
||||
.clk_a(smux_clk_a),
|
||||
.cen_a(cen_a_n),
|
||||
.wen_a(ram_wen_a_n),
|
||||
.addr_a(ram_addr_a[13:4]),
|
||||
.wmsk_a(wmsk_a),
|
||||
.wdata_a(aligned_wdata_a),
|
||||
.rdata_a(ram_rdata_a),
|
||||
.clk_b(smux_clk_b),
|
||||
.cen_b(cen_b_n),
|
||||
.wen_b(ram_wen_b_n),
|
||||
.addr_b(ram_addr_b[13:4]),
|
||||
.wmsk_b(wmsk_b),
|
||||
.wdata_b(aligned_wdata_b),
|
||||
.rdata_b(ram_rdata_b)
|
||||
);
|
||||
fifo_ctl #(
|
||||
.ADDR_WIDTH(11),
|
||||
.FIFO_WIDTH(2),
|
||||
.DEPTH(6)
|
||||
) fifo_ctl(
|
||||
.rclk(smux_clk_b),
|
||||
.rst_R_n(FLUSH_ni),
|
||||
.wclk(smux_clk_a),
|
||||
.rst_W_n(FLUSH_ni),
|
||||
.ren(REN_B_i),
|
||||
.wen(ram_wen_a),
|
||||
.sync(SYNC_FIFO_i),
|
||||
.rmode(fifo_rmode),
|
||||
.wmode(fifo_wmode),
|
||||
.ren_o(ren_o),
|
||||
.fflags({FULL_o, FMO_o, FWM_o, OVERRUN_o, EMPTY_o, EPO_o, EWM_o, UNDERRUN_o}),
|
||||
.raddr(ff_raddr),
|
||||
.waddr(ff_waddr),
|
||||
.upaf(UPAF_i),
|
||||
.upae(UPAE_i)
|
||||
);
|
||||
localparam MODE_1 = 3'b101;
|
||||
localparam MODE_18 = 3'b010;
|
||||
localparam MODE_2 = 3'b110;
|
||||
localparam MODE_4 = 3'b100;
|
||||
always @(*) begin : WDATA_MODE_SEL
|
||||
if (ram_wen_a == 1) begin
|
||||
case (WMODE_A_i)
|
||||
MODE_18: begin
|
||||
aligned_wdata_a = WDATA_A_i;
|
||||
{wmsk_a[17], wmsk_a[15:8]} = (FMODE_i ? 9'h000 : (BE_A_i[1] ? 9'h000 : 9'h1ff));
|
||||
{wmsk_a[16], wmsk_a[7:0]} = (FMODE_i ? 9'h000 : (BE_A_i[0] ? 9'h000 : 9'h1ff));
|
||||
end
|
||||
MODE_9: begin
|
||||
aligned_wdata_a = {{2 {WDATA_A_i[16]}}, {2 {WDATA_A_i[7:0]}}};
|
||||
{wmsk_a[17], wmsk_a[15:8]} = (ram_waddr_a[3] ? 9'h000 : 9'h1ff);
|
||||
{wmsk_a[16], wmsk_a[7:0]} = (ram_waddr_a[3] ? 9'h1ff : 9'h000);
|
||||
end
|
||||
MODE_4: begin
|
||||
aligned_wdata_a = {2'b00, {4 {WDATA_A_i[3:0]}}};
|
||||
wmsk_a[17:16] = 2'b00;
|
||||
wmsk_a[15:12] = (ram_waddr_a[3:2] == 2'b11 ? 4'h0 : 4'hf);
|
||||
wmsk_a[11:8] = (ram_waddr_a[3:2] == 2'b10 ? 4'h0 : 4'hf);
|
||||
wmsk_a[7:4] = (ram_waddr_a[3:2] == 2'b01 ? 4'h0 : 4'hf);
|
||||
wmsk_a[3:0] = (ram_waddr_a[3:2] == 2'b00 ? 4'h0 : 4'hf);
|
||||
end
|
||||
MODE_2: begin
|
||||
aligned_wdata_a = {2'b00, {8 {WDATA_A_i[1:0]}}};
|
||||
wmsk_a[17:16] = 2'b00;
|
||||
wmsk_a[15:14] = (ram_waddr_a[3:1] == 3'b111 ? 2'h0 : 2'h3);
|
||||
wmsk_a[13:12] = (ram_waddr_a[3:1] == 3'b110 ? 2'h0 : 2'h3);
|
||||
wmsk_a[11:10] = (ram_waddr_a[3:1] == 3'b101 ? 2'h0 : 2'h3);
|
||||
wmsk_a[9:8] = (ram_waddr_a[3:1] == 3'b100 ? 2'h0 : 2'h3);
|
||||
wmsk_a[7:6] = (ram_waddr_a[3:1] == 3'b011 ? 2'h0 : 2'h3);
|
||||
wmsk_a[5:4] = (ram_waddr_a[3:1] == 3'b010 ? 2'h0 : 2'h3);
|
||||
wmsk_a[3:2] = (ram_waddr_a[3:1] == 3'b001 ? 2'h0 : 2'h3);
|
||||
wmsk_a[1:0] = (ram_waddr_a[3:1] == 3'b000 ? 2'h0 : 2'h3);
|
||||
end
|
||||
MODE_1: begin
|
||||
aligned_wdata_a = {2'b00, {16 {WDATA_A_i[0]}}};
|
||||
wmsk_a = 18'h0ffff;
|
||||
wmsk_a[{1'b0, ram_waddr_a[3:0]}] = 0;
|
||||
end
|
||||
default: wmsk_a = 18'h3ffff;
|
||||
endcase
|
||||
end
|
||||
else begin
|
||||
aligned_wdata_a = 18'h00000;
|
||||
wmsk_a = 18'h3ffff;
|
||||
end
|
||||
if (ram_wen_b == 1)
|
||||
case (WMODE_B_i)
|
||||
MODE_18: begin
|
||||
aligned_wdata_b = WDATA_B_i;
|
||||
{wmsk_b[17], wmsk_b[15:8]} = (BE_B_i[1] ? 9'h000 : 9'h1ff);
|
||||
{wmsk_b[16], wmsk_b[7:0]} = (BE_B_i[0] ? 9'h000 : 9'h1ff);
|
||||
end
|
||||
MODE_9: begin
|
||||
aligned_wdata_b = {{2 {WDATA_B_i[16]}}, {2 {WDATA_B_i[7:0]}}};
|
||||
{wmsk_b[17], wmsk_b[15:8]} = (ram_waddr_b[3] ? 9'h000 : 9'h1ff);
|
||||
{wmsk_b[16], wmsk_b[7:0]} = (ram_waddr_b[3] ? 9'h1ff : 9'h000);
|
||||
end
|
||||
MODE_4: begin
|
||||
aligned_wdata_b = {2'b00, {4 {WDATA_B_i[3:0]}}};
|
||||
wmsk_b[17:16] = 2'b00;
|
||||
wmsk_b[15:12] = (ram_waddr_b[3:2] == 2'b11 ? 4'h0 : 4'hf);
|
||||
wmsk_b[11:8] = (ram_waddr_b[3:2] == 2'b10 ? 4'h0 : 4'hf);
|
||||
wmsk_b[7:4] = (ram_waddr_b[3:2] == 2'b01 ? 4'h0 : 4'hf);
|
||||
wmsk_b[3:0] = (ram_waddr_b[3:2] == 2'b00 ? 4'h0 : 4'hf);
|
||||
end
|
||||
MODE_2: begin
|
||||
aligned_wdata_b = {2'b00, {8 {WDATA_B_i[1:0]}}};
|
||||
wmsk_b[17:16] = 2'b00;
|
||||
wmsk_b[15:14] = (ram_waddr_b[3:1] == 3'b111 ? 2'h0 : 2'h3);
|
||||
wmsk_b[13:12] = (ram_waddr_b[3:1] == 3'b110 ? 2'h0 : 2'h3);
|
||||
wmsk_b[11:10] = (ram_waddr_b[3:1] == 3'b101 ? 2'h0 : 2'h3);
|
||||
wmsk_b[9:8] = (ram_waddr_b[3:1] == 3'b100 ? 2'h0 : 2'h3);
|
||||
wmsk_b[7:6] = (ram_waddr_b[3:1] == 3'b011 ? 2'h0 : 2'h3);
|
||||
wmsk_b[5:4] = (ram_waddr_b[3:1] == 3'b010 ? 2'h0 : 2'h3);
|
||||
wmsk_b[3:2] = (ram_waddr_b[3:1] == 3'b001 ? 2'h0 : 2'h3);
|
||||
wmsk_b[1:0] = (ram_waddr_b[3:1] == 3'b000 ? 2'h0 : 2'h3);
|
||||
end
|
||||
MODE_1: begin
|
||||
aligned_wdata_b = {2'b00, {16 {WDATA_B_i[0]}}};
|
||||
wmsk_b = 18'h0ffff;
|
||||
wmsk_b[{1'b0, ram_waddr_b[3:0]}] = 0;
|
||||
end
|
||||
default: wmsk_b = 18'h3ffff;
|
||||
endcase
|
||||
else begin
|
||||
aligned_wdata_b = 18'b000000000000000000;
|
||||
wmsk_b = 18'h3ffff;
|
||||
end
|
||||
end
|
||||
always @(*) begin : RDATA_A_MODE_SEL
|
||||
case (RMODE_A_i)
|
||||
default: RDATA_A_o = 18'h00000;
|
||||
MODE_18: RDATA_A_o = ram_rdata_a;
|
||||
MODE_9: begin
|
||||
{RDATA_A_o[17], RDATA_A_o[15:8]} = 9'h000;
|
||||
{RDATA_A_o[16], RDATA_A_o[7:0]} = (ram_addr_a[3] ? {ram_rdata_a[17], ram_rdata_a[15:8]} : {ram_rdata_a[16], ram_rdata_a[7:0]});
|
||||
end
|
||||
MODE_4: begin
|
||||
RDATA_A_o[17:4] = 14'h0000;
|
||||
case (ram_addr_a[3:2])
|
||||
3: RDATA_A_o[3:0] = ram_rdata_a[15:12];
|
||||
2: RDATA_A_o[3:0] = ram_rdata_a[11:8];
|
||||
1: RDATA_A_o[3:0] = ram_rdata_a[7:4];
|
||||
0: RDATA_A_o[3:0] = ram_rdata_a[3:0];
|
||||
endcase
|
||||
end
|
||||
MODE_2: begin
|
||||
RDATA_A_o[17:2] = 16'h0000;
|
||||
case (ram_addr_a[3:1])
|
||||
7: RDATA_A_o[1:0] = ram_rdata_a[15:14];
|
||||
6: RDATA_A_o[1:0] = ram_rdata_a[13:12];
|
||||
5: RDATA_A_o[1:0] = ram_rdata_a[11:10];
|
||||
4: RDATA_A_o[1:0] = ram_rdata_a[9:8];
|
||||
3: RDATA_A_o[1:0] = ram_rdata_a[7:6];
|
||||
2: RDATA_A_o[1:0] = ram_rdata_a[5:4];
|
||||
1: RDATA_A_o[1:0] = ram_rdata_a[3:2];
|
||||
0: RDATA_A_o[1:0] = ram_rdata_a[1:0];
|
||||
endcase
|
||||
end
|
||||
MODE_1: begin
|
||||
RDATA_A_o[17:1] = 17'h00000;
|
||||
RDATA_A_o[0] = ram_rdata_a[ram_addr_a[3:0]];
|
||||
end
|
||||
endcase
|
||||
end
|
||||
always @(*)
|
||||
case (RMODE_B_i)
|
||||
default: RDATA_B_o = 18'h15566;
|
||||
MODE_18: RDATA_B_o = ram_rdata_b;
|
||||
MODE_9: begin
|
||||
{RDATA_B_o[17], RDATA_B_o[15:8]} = 9'b000000000;
|
||||
{RDATA_B_o[16], RDATA_B_o[7:0]} = (ram_addr_b[3] ? {ram_rdata_b[17], ram_rdata_b[15:8]} : {ram_rdata_b[16], ram_rdata_b[7:0]});
|
||||
end
|
||||
MODE_4:
|
||||
case (ram_addr_b[3:2])
|
||||
3: RDATA_B_o[3:0] = ram_rdata_b[15:12];
|
||||
2: RDATA_B_o[3:0] = ram_rdata_b[11:8];
|
||||
1: RDATA_B_o[3:0] = ram_rdata_b[7:4];
|
||||
0: RDATA_B_o[3:0] = ram_rdata_b[3:0];
|
||||
endcase
|
||||
MODE_2:
|
||||
case (ram_addr_b[3:1])
|
||||
7: RDATA_B_o[1:0] = ram_rdata_b[15:14];
|
||||
6: RDATA_B_o[1:0] = ram_rdata_b[13:12];
|
||||
5: RDATA_B_o[1:0] = ram_rdata_b[11:10];
|
||||
4: RDATA_B_o[1:0] = ram_rdata_b[9:8];
|
||||
3: RDATA_B_o[1:0] = ram_rdata_b[7:6];
|
||||
2: RDATA_B_o[1:0] = ram_rdata_b[5:4];
|
||||
1: RDATA_B_o[1:0] = ram_rdata_b[3:2];
|
||||
0: RDATA_B_o[1:0] = ram_rdata_b[1:0];
|
||||
endcase
|
||||
MODE_1: RDATA_B_o[0] = ram_rdata_b[{1'b0, ram_addr_b[3:0]}];
|
||||
endcase
|
||||
endmodule
|
||||
`default_nettype none
|
|
@ -0,0 +1,99 @@
|
|||
// Copyright 2020-2022 F4PGA Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
(* techmap_celltype = "$alu" *)
|
||||
module _80_quicklogic_alu (A, B, CI, BI, X, Y, CO);
|
||||
parameter A_SIGNED = 0;
|
||||
parameter B_SIGNED = 0;
|
||||
parameter A_WIDTH = 2;
|
||||
parameter B_WIDTH = 2;
|
||||
parameter Y_WIDTH = 2;
|
||||
parameter _TECHMAP_CONSTVAL_CI_ = 0;
|
||||
parameter _TECHMAP_CONSTMSK_CI_ = 0;
|
||||
|
||||
(* 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] A_buf, B_buf;
|
||||
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
|
||||
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
|
||||
|
||||
(* force_downto *)
|
||||
wire [Y_WIDTH-1:0] AA = A_buf;
|
||||
(* force_downto *)
|
||||
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
|
||||
|
||||
genvar i;
|
||||
wire co;
|
||||
|
||||
(* force_downto *)
|
||||
//wire [Y_WIDTH-1:0] C = {CO, CI};
|
||||
wire [Y_WIDTH:0] C;
|
||||
(* force_downto *)
|
||||
wire [Y_WIDTH-1:0] S = {AA ^ BB};
|
||||
assign CO[Y_WIDTH-1:0] = C[Y_WIDTH:1];
|
||||
//assign CO[Y_WIDTH-1] = co;
|
||||
|
||||
generate
|
||||
adder_carry intermediate_adder (
|
||||
.cin ( ),
|
||||
.cout (C[0]),
|
||||
.p (1'b0),
|
||||
.g (CI),
|
||||
.sumout ()
|
||||
);
|
||||
endgenerate
|
||||
genvar i;
|
||||
generate if (Y_WIDTH > 2) begin
|
||||
for (i = 0; i < Y_WIDTH-2; i = i + 1) begin:slice
|
||||
adder_carry my_adder (
|
||||
.cin (C[i]),
|
||||
.g (AA[i]),
|
||||
.p (S[i]),
|
||||
.cout (C[i+1]),
|
||||
.sumout (Y[i])
|
||||
);
|
||||
end
|
||||
end endgenerate
|
||||
generate
|
||||
adder_carry final_adder (
|
||||
.cin (C[Y_WIDTH-2]),
|
||||
.cout (),
|
||||
.p (1'b0),
|
||||
.g (1'b0),
|
||||
.sumout (co)
|
||||
);
|
||||
endgenerate
|
||||
|
||||
assign Y[Y_WIDTH-2] = S[Y_WIDTH-2] ^ co;
|
||||
assign C[Y_WIDTH-1] = S[Y_WIDTH-2] ? co : AA[Y_WIDTH-2];
|
||||
assign Y[Y_WIDTH-1] = S[Y_WIDTH-1] ^ C[Y_WIDTH-1];
|
||||
assign C[Y_WIDTH] = S[Y_WIDTH-1] ? C[Y_WIDTH-1] : AA[Y_WIDTH-1];
|
||||
|
||||
assign X = S;
|
||||
endmodule
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,375 @@
|
|||
// Copyright 2020-2022 F4PGA Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
`timescale 1ps/1ps
|
||||
|
||||
`default_nettype none
|
||||
(* abc9_lut=1 *)
|
||||
module LUT1(output wire O, input wire I0);
|
||||
parameter [1:0] INIT = 0;
|
||||
assign O = I0 ? INIT[1] : INIT[0];
|
||||
specify
|
||||
(I0 => O) = 74;
|
||||
endspecify
|
||||
endmodule
|
||||
|
||||
(* abc9_lut=2 *)
|
||||
module LUT2(output wire O, input wire I0, I1);
|
||||
parameter [3:0] INIT = 0;
|
||||
wire [ 1: 0] s1 = I1 ? INIT[ 3: 2] : INIT[ 1: 0];
|
||||
assign O = I0 ? s1[1] : s1[0];
|
||||
specify
|
||||
(I0 => O) = 116;
|
||||
(I1 => O) = 74;
|
||||
endspecify
|
||||
endmodule
|
||||
|
||||
(* abc9_lut=3 *)
|
||||
module LUT3(output wire O, input wire I0, I1, I2);
|
||||
parameter [7:0] INIT = 0;
|
||||
wire [ 3: 0] s2 = I2 ? INIT[ 7: 4] : INIT[ 3: 0];
|
||||
wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
|
||||
assign O = I0 ? s1[1] : s1[0];
|
||||
specify
|
||||
(I0 => O) = 162;
|
||||
(I1 => O) = 116;
|
||||
(I2 => O) = 174;
|
||||
endspecify
|
||||
endmodule
|
||||
|
||||
(* abc9_lut=3 *)
|
||||
module LUT4(output wire O, input wire I0, I1, I2, I3);
|
||||
parameter [15:0] INIT = 0;
|
||||
wire [ 7: 0] s3 = I3 ? INIT[15: 8] : INIT[ 7: 0];
|
||||
wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0];
|
||||
wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
|
||||
assign O = I0 ? s1[1] : s1[0];
|
||||
specify
|
||||
(I0 => O) = 201;
|
||||
(I1 => O) = 162;
|
||||
(I2 => O) = 116;
|
||||
(I3 => O) = 74;
|
||||
endspecify
|
||||
endmodule
|
||||
|
||||
(* abc9_lut=3 *)
|
||||
module LUT5(output wire O, input wire I0, I1, I2, I3, I4);
|
||||
parameter [31:0] INIT = 0;
|
||||
wire [15: 0] s4 = I4 ? INIT[31:16] : INIT[15: 0];
|
||||
wire [ 7: 0] s3 = I3 ? s4[15: 8] : s4[ 7: 0];
|
||||
wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0];
|
||||
wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
|
||||
assign O = I0 ? s1[1] : s1[0];
|
||||
specify
|
||||
(I0 => O) = 228;
|
||||
(I1 => O) = 189;
|
||||
(I2 => O) = 143;
|
||||
(I3 => O) = 100;
|
||||
(I4 => O) = 55;
|
||||
endspecify
|
||||
endmodule
|
||||
|
||||
(* abc9_lut=5 *)
|
||||
module LUT6(output wire O, input wire I0, I1, I2, I3, I4, I5);
|
||||
parameter [63:0] INIT = 0;
|
||||
wire [31: 0] s5 = I5 ? INIT[63:32] : INIT[31: 0];
|
||||
wire [15: 0] s4 = I4 ? s5[31:16] : s5[15: 0];
|
||||
wire [ 7: 0] s3 = I3 ? s4[15: 8] : s4[ 7: 0];
|
||||
wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0];
|
||||
wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
|
||||
assign O = I0 ? s1[1] : s1[0];
|
||||
specify
|
||||
(I0 => O) = 251;
|
||||
(I1 => O) = 212;
|
||||
(I2 => O) = 166;
|
||||
(I3 => O) = 123;
|
||||
(I4 => O) = 77;
|
||||
(I5 => O) = 43;
|
||||
endspecify
|
||||
endmodule
|
||||
|
||||
(* abc9_flop, lib_whitebox *)
|
||||
module sh_dff(
|
||||
output reg Q,
|
||||
input wire D,
|
||||
(* clkbuf_sink *)
|
||||
input wire C
|
||||
);
|
||||
|
||||
initial Q = 1'b0;
|
||||
always @(posedge C)
|
||||
Q <= D;
|
||||
|
||||
specify
|
||||
(posedge C => (Q +: D)) = 0;
|
||||
$setuphold(posedge C, D, 0, 0);
|
||||
endspecify
|
||||
|
||||
endmodule
|
||||
|
||||
(* abc9_box, lib_whitebox *)
|
||||
(* keep *)
|
||||
module adder_carry(
|
||||
output wire sumout,
|
||||
(* abc9_carry *)
|
||||
output wire cout,
|
||||
input wire p,
|
||||
input wire g,
|
||||
(* abc9_carry *)
|
||||
input wire cin
|
||||
);
|
||||
assign sumout = p ^ cin;
|
||||
assign cout = p ? cin : g;
|
||||
|
||||
specify
|
||||
(p => sumout) = 35;
|
||||
(g => sumout) = 35;
|
||||
(cin => sumout) = 40;
|
||||
(p => cout) = 67;
|
||||
(g => cout) = 65;
|
||||
(cin => cout) = 69;
|
||||
endspecify
|
||||
|
||||
endmodule
|
||||
|
||||
(* abc9_flop, lib_whitebox *)
|
||||
module dff(
|
||||
output reg Q,
|
||||
input wire D,
|
||||
(* clkbuf_sink *)
|
||||
input wire C
|
||||
);
|
||||
initial Q = 1'b0;
|
||||
|
||||
always @(posedge C)
|
||||
Q <= D;
|
||||
|
||||
specify
|
||||
(posedge C=>(Q+:D)) = 285;
|
||||
$setuphold(posedge C, D, 56, 0);
|
||||
endspecify
|
||||
|
||||
endmodule
|
||||
|
||||
(* abc9_flop, lib_whitebox *)
|
||||
module dffn(
|
||||
output reg Q,
|
||||
input wire D,
|
||||
(* clkbuf_sink *)
|
||||
input wire C
|
||||
);
|
||||
initial Q = 1'b0;
|
||||
|
||||
always @(negedge C)
|
||||
Q <= D;
|
||||
|
||||
specify
|
||||
(negedge C=>(Q+:D)) = 285;
|
||||
$setuphold(negedge C, D, 56, 0);
|
||||
endspecify
|
||||
|
||||
endmodule
|
||||
|
||||
(* abc9_flop, lib_whitebox *)
|
||||
module dffsre(
|
||||
output reg Q,
|
||||
input wire D,
|
||||
(* clkbuf_sink *)
|
||||
input wire C,
|
||||
input wire E,
|
||||
input wire R,
|
||||
input wire S
|
||||
);
|
||||
initial Q = 1'b0;
|
||||
|
||||
always @(posedge C or negedge S or negedge R)
|
||||
if (!R)
|
||||
Q <= 1'b0;
|
||||
else if (!S)
|
||||
Q <= 1'b1;
|
||||
else if (E)
|
||||
Q <= D;
|
||||
|
||||
specify
|
||||
(posedge C => (Q +: D)) = 280;
|
||||
(R => Q) = 0;
|
||||
(S => Q) = 0;
|
||||
$setuphold(posedge C, D, 56, 0);
|
||||
$setuphold(posedge C, E, 32, 0);
|
||||
$setuphold(posedge C, R, 0, 0);
|
||||
$setuphold(posedge C, S, 0, 0);
|
||||
$recrem(posedge R, posedge C, 0, 0);
|
||||
$recrem(posedge S, posedge C, 0, 0);
|
||||
endspecify
|
||||
|
||||
endmodule
|
||||
|
||||
(* abc9_flop, lib_whitebox *)
|
||||
module dffnsre(
|
||||
output reg Q,
|
||||
input wire D,
|
||||
(* clkbuf_sink *)
|
||||
input wire C,
|
||||
input wire E,
|
||||
input wire R,
|
||||
input wire S
|
||||
);
|
||||
initial Q = 1'b0;
|
||||
|
||||
always @(negedge C or negedge S or negedge R)
|
||||
if (!R)
|
||||
Q <= 1'b0;
|
||||
else if (!S)
|
||||
Q <= 1'b1;
|
||||
else if (E)
|
||||
Q <= D;
|
||||
|
||||
specify
|
||||
(negedge C => (Q +: D)) = 280;
|
||||
(R => Q) = 0;
|
||||
(S => Q) = 0;
|
||||
$setuphold(negedge C, D, 56, 0);
|
||||
$setuphold(negedge C, E, 32, 0);
|
||||
$setuphold(negedge C, R, 0, 0);
|
||||
$setuphold(negedge C, S, 0, 0);
|
||||
$recrem(posedge R, negedge C, 0, 0);
|
||||
$recrem(posedge S, negedge C, 0, 0);
|
||||
endspecify
|
||||
|
||||
endmodule
|
||||
|
||||
(* abc9_flop, lib_whitebox *)
|
||||
module sdffsre(
|
||||
output reg Q,
|
||||
input wire D,
|
||||
(* clkbuf_sink *)
|
||||
input wire C,
|
||||
input wire E,
|
||||
input wire R,
|
||||
input wire S
|
||||
);
|
||||
initial Q = 1'b0;
|
||||
|
||||
always @(posedge C)
|
||||
if (!R)
|
||||
Q <= 1'b0;
|
||||
else if (!S)
|
||||
Q <= 1'b1;
|
||||
else if (E)
|
||||
Q <= D;
|
||||
|
||||
specify
|
||||
(posedge C => (Q +: D)) = 280;
|
||||
$setuphold(posedge C, D, 56, 0);
|
||||
$setuphold(posedge C, R, 32, 0);
|
||||
$setuphold(posedge C, S, 0, 0);
|
||||
$setuphold(posedge C, E, 0, 0);
|
||||
endspecify
|
||||
|
||||
endmodule
|
||||
|
||||
(* abc9_flop, lib_whitebox *)
|
||||
module sdffnsre(
|
||||
output reg Q,
|
||||
input wire D,
|
||||
(* clkbuf_sink *)
|
||||
input wire C,
|
||||
input wire E,
|
||||
input wire R,
|
||||
input wire S
|
||||
);
|
||||
initial Q = 1'b0;
|
||||
|
||||
always @(negedge C)
|
||||
if (!R)
|
||||
Q <= 1'b0;
|
||||
else if (!S)
|
||||
Q <= 1'b1;
|
||||
else if (E)
|
||||
Q <= D;
|
||||
|
||||
specify
|
||||
(negedge C => (Q +: D)) = 280;
|
||||
$setuphold(negedge C, D, 56, 0);
|
||||
$setuphold(negedge C, R, 32, 0);
|
||||
$setuphold(negedge C, S, 0, 0);
|
||||
$setuphold(negedge C, E, 0, 0);
|
||||
endspecify
|
||||
|
||||
endmodule
|
||||
|
||||
(* abc9_flop, lib_whitebox *)
|
||||
module latchsre (
|
||||
output reg Q,
|
||||
input wire S,
|
||||
input wire R,
|
||||
input wire D,
|
||||
input wire G,
|
||||
input wire E
|
||||
);
|
||||
initial Q = 1'b0;
|
||||
|
||||
always @*
|
||||
begin
|
||||
if (!R)
|
||||
Q <= 1'b0;
|
||||
else if (!S)
|
||||
Q <= 1'b1;
|
||||
else if (E && G)
|
||||
Q <= D;
|
||||
end
|
||||
|
||||
specify
|
||||
(posedge G => (Q +: D)) = 0;
|
||||
$setuphold(posedge G, D, 0, 0);
|
||||
$setuphold(posedge G, E, 0, 0);
|
||||
$setuphold(posedge G, R, 0, 0);
|
||||
$setuphold(posedge G, S, 0, 0);
|
||||
endspecify
|
||||
|
||||
endmodule
|
||||
|
||||
(* abc9_flop, lib_whitebox *)
|
||||
module latchnsre (
|
||||
output reg Q,
|
||||
input wire S,
|
||||
input wire R,
|
||||
input wire D,
|
||||
input wire G,
|
||||
input wire E
|
||||
);
|
||||
initial Q = 1'b0;
|
||||
|
||||
always @*
|
||||
begin
|
||||
if (!R)
|
||||
Q <= 1'b0;
|
||||
else if (!S)
|
||||
Q <= 1'b1;
|
||||
else if (E && !G)
|
||||
Q <= D;
|
||||
end
|
||||
|
||||
specify
|
||||
(negedge G => (Q +: D)) = 0;
|
||||
$setuphold(negedge G, D, 0, 0);
|
||||
$setuphold(negedge G, E, 0, 0);
|
||||
$setuphold(negedge G, R, 0, 0);
|
||||
$setuphold(negedge G, S, 0, 0);
|
||||
endspecify
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
// Copyright 2020-2022 F4PGA Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
module dsp_t1_20x18x64_cfg_ports (
|
||||
input [19:0] a_i,
|
||||
input [17:0] b_i,
|
||||
input [ 5:0] acc_fir_i,
|
||||
output [37:0] z_o,
|
||||
output [17:0] dly_b_o,
|
||||
|
||||
input clock_i,
|
||||
input reset_i,
|
||||
|
||||
input [2:0] feedback_i,
|
||||
input load_acc_i,
|
||||
input unsigned_a_i,
|
||||
input unsigned_b_i,
|
||||
|
||||
input [2:0] output_select_i,
|
||||
input saturate_enable_i,
|
||||
input [5:0] shift_right_i,
|
||||
input round_i,
|
||||
input subtract_i,
|
||||
input register_inputs_i
|
||||
);
|
||||
|
||||
parameter [19:0] COEFF_0 = 20'd0;
|
||||
parameter [19:0] COEFF_1 = 20'd0;
|
||||
parameter [19:0] COEFF_2 = 20'd0;
|
||||
parameter [19:0] COEFF_3 = 20'd0;
|
||||
|
||||
QL_DSP2 # (
|
||||
.MODE_BITS ({COEFF_3, COEFF_2, COEFF_1, COEFF_0})
|
||||
) _TECHMAP_REPLACE_ (
|
||||
.a (a_i),
|
||||
.b (b_i),
|
||||
.acc_fir (acc_fir_i),
|
||||
.z (z_o),
|
||||
.dly_b (dly_b_o),
|
||||
|
||||
.clk (clock_i),
|
||||
.reset (reset_i),
|
||||
|
||||
.feedback (feedback_i),
|
||||
.load_acc (load_acc_i),
|
||||
.unsigned_a (unsigned_a_i),
|
||||
.unsigned_b (unsigned_b_i),
|
||||
|
||||
.f_mode (1'b0), // No fracturation
|
||||
.output_select (output_select_i),
|
||||
.saturate_enable (saturate_enable_i),
|
||||
.shift_right (shift_right_i),
|
||||
.round (round_i),
|
||||
.subtract (subtract_i),
|
||||
.register_inputs (register_inputs_i)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
module dsp_t1_10x9x32_cfg_ports (
|
||||
input [ 9:0] a_i,
|
||||
input [ 8:0] b_i,
|
||||
input [ 5:0] acc_fir_i,
|
||||
output [18:0] z_o,
|
||||
output [ 8:0] dly_b_o,
|
||||
|
||||
(* clkbuf_sink *)
|
||||
input clock_i,
|
||||
input reset_i,
|
||||
|
||||
input [2:0] feedback_i,
|
||||
input load_acc_i,
|
||||
input unsigned_a_i,
|
||||
input unsigned_b_i,
|
||||
|
||||
input [2:0] output_select_i,
|
||||
input saturate_enable_i,
|
||||
input [5:0] shift_right_i,
|
||||
input round_i,
|
||||
input subtract_i,
|
||||
input register_inputs_i
|
||||
);
|
||||
|
||||
parameter [9:0] COEFF_0 = 10'd0;
|
||||
parameter [9:0] COEFF_1 = 10'd0;
|
||||
parameter [9:0] COEFF_2 = 10'd0;
|
||||
parameter [9:0] COEFF_3 = 10'd0;
|
||||
|
||||
wire [37:0] z;
|
||||
wire [17:0] dly_b;
|
||||
|
||||
QL_DSP2 # (
|
||||
.MODE_BITS ({10'd0, COEFF_3,
|
||||
10'd0, COEFF_2,
|
||||
10'd0, COEFF_1,
|
||||
10'd0, COEFF_0})
|
||||
) _TECHMAP_REPLACE_ (
|
||||
.a ({10'd0, a_i}),
|
||||
.b ({ 9'd0, b_i}),
|
||||
.acc_fir (acc_fir_i),
|
||||
.z (z),
|
||||
.dly_b (dly_b),
|
||||
|
||||
.clk (clock_i),
|
||||
.reset (reset_i),
|
||||
|
||||
.feedback (feedback_i),
|
||||
.load_acc (load_acc_i),
|
||||
.unsigned_a (unsigned_a_i),
|
||||
.unsigned_b (unsigned_b_i),
|
||||
|
||||
.f_mode (1'b1), // Enable fractuation, Use the lower half
|
||||
.output_select (output_select_i),
|
||||
.saturate_enable (saturate_enable_i),
|
||||
.shift_right (shift_right_i),
|
||||
.round (round_i),
|
||||
.subtract (subtract_i),
|
||||
.register_inputs (register_inputs_i)
|
||||
);
|
||||
|
||||
assign z_o = z[18:0];
|
||||
assign dly_b_o = dly_b_o[8:0];
|
||||
|
||||
endmodule
|
||||
|
||||
module dsp_t1_20x18x64_cfg_params (
|
||||
input [19:0] a_i,
|
||||
input [17:0] b_i,
|
||||
input [ 5:0] acc_fir_i,
|
||||
output [37:0] z_o,
|
||||
output [17:0] dly_b_o,
|
||||
|
||||
input clock_i,
|
||||
input reset_i,
|
||||
|
||||
input [2:0] feedback_i,
|
||||
input load_acc_i,
|
||||
input unsigned_a_i,
|
||||
input unsigned_b_i,
|
||||
input subtract_i
|
||||
);
|
||||
|
||||
parameter [19:0] COEFF_0 = 20'd0;
|
||||
parameter [19:0] COEFF_1 = 20'd0;
|
||||
parameter [19:0] COEFF_2 = 20'd0;
|
||||
parameter [19:0] COEFF_3 = 20'd0;
|
||||
|
||||
parameter [2:0] OUTPUT_SELECT = 3'd0;
|
||||
parameter [0:0] SATURATE_ENABLE = 1'd0;
|
||||
parameter [5:0] SHIFT_RIGHT = 6'd0;
|
||||
parameter [0:0] ROUND = 1'd0;
|
||||
parameter [0:0] REGISTER_INPUTS = 1'd0;
|
||||
|
||||
QL_DSP3 # (
|
||||
.MODE_BITS ({
|
||||
REGISTER_INPUTS,
|
||||
ROUND,
|
||||
SHIFT_RIGHT,
|
||||
SATURATE_ENABLE,
|
||||
OUTPUT_SELECT,
|
||||
1'b0, // Not fractured
|
||||
COEFF_3,
|
||||
COEFF_2,
|
||||
COEFF_1,
|
||||
COEFF_0
|
||||
})
|
||||
) _TECHMAP_REPLACE_ (
|
||||
.a (a_i),
|
||||
.b (b_i),
|
||||
.acc_fir (acc_fir_i),
|
||||
.z (z_o),
|
||||
.dly_b (dly_b_o),
|
||||
|
||||
.clk (clock_i),
|
||||
.reset (reset_i),
|
||||
|
||||
.feedback (feedback_i),
|
||||
.load_acc (load_acc_i),
|
||||
.unsigned_a (unsigned_a_i),
|
||||
.unsigned_b (unsigned_b_i),
|
||||
.subtract (subtract_i)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
module dsp_t1_10x9x32_cfg_params (
|
||||
input [ 9:0] a_i,
|
||||
input [ 8:0] b_i,
|
||||
input [ 5:0] acc_fir_i,
|
||||
output [18:0] z_o,
|
||||
output [ 8:0] dly_b_o,
|
||||
|
||||
(* clkbuf_sink *)
|
||||
input clock_i,
|
||||
input reset_i,
|
||||
|
||||
input [2:0] feedback_i,
|
||||
input load_acc_i,
|
||||
input unsigned_a_i,
|
||||
input unsigned_b_i,
|
||||
input subtract_i
|
||||
);
|
||||
|
||||
parameter [9:0] COEFF_0 = 10'd0;
|
||||
parameter [9:0] COEFF_1 = 10'd0;
|
||||
parameter [9:0] COEFF_2 = 10'd0;
|
||||
parameter [9:0] COEFF_3 = 10'd0;
|
||||
|
||||
parameter [2:0] OUTPUT_SELECT = 3'd0;
|
||||
parameter [0:0] SATURATE_ENABLE = 1'd0;
|
||||
parameter [5:0] SHIFT_RIGHT = 6'd0;
|
||||
parameter [0:0] ROUND = 1'd0;
|
||||
parameter [0:0] REGISTER_INPUTS = 1'd0;
|
||||
|
||||
wire [37:0] z;
|
||||
wire [17:0] dly_b;
|
||||
|
||||
QL_DSP3 # (
|
||||
.MODE_BITS ({
|
||||
REGISTER_INPUTS,
|
||||
ROUND,
|
||||
SHIFT_RIGHT,
|
||||
SATURATE_ENABLE,
|
||||
OUTPUT_SELECT,
|
||||
1'b1, // Fractured
|
||||
10'd0, COEFF_3,
|
||||
10'd0, COEFF_2,
|
||||
10'd0, COEFF_1,
|
||||
10'd0, COEFF_0
|
||||
})
|
||||
) _TECHMAP_REPLACE_ (
|
||||
.a ({10'd0, a_i}),
|
||||
.b ({ 9'd0, b_i}),
|
||||
.acc_fir (acc_fir_i),
|
||||
.z (z),
|
||||
.dly_b (dly_b),
|
||||
|
||||
.clk (clock_i),
|
||||
.reset (reset_i),
|
||||
|
||||
.feedback (feedback_i),
|
||||
.load_acc (load_acc_i),
|
||||
.unsigned_a (unsigned_a_i),
|
||||
.unsigned_b (unsigned_b_i),
|
||||
.subtract (subtract_i)
|
||||
);
|
||||
|
||||
assign z_o = z[18:0];
|
||||
assign dly_b_o = dly_b_o[8:0];
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
// Copyright 2020-2022 F4PGA Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
module \$__QL_MUL20X18 (input [19:0] A, input [17:0] B, output [37:0] Y);
|
||||
parameter A_SIGNED = 0;
|
||||
parameter B_SIGNED = 0;
|
||||
parameter A_WIDTH = 0;
|
||||
parameter B_WIDTH = 0;
|
||||
parameter Y_WIDTH = 0;
|
||||
|
||||
wire [19:0] a;
|
||||
wire [17:0] b;
|
||||
wire [37:0] z;
|
||||
|
||||
assign a = (A_WIDTH == 20) ? A :
|
||||
(A_SIGNED) ? {{(20 - A_WIDTH){A[A_WIDTH-1]}}, A} :
|
||||
{{(20 - A_WIDTH){1'b0}}, A};
|
||||
|
||||
assign b = (B_WIDTH == 18) ? B :
|
||||
(B_SIGNED) ? {{(18 - B_WIDTH){B[B_WIDTH-1]}}, B} :
|
||||
{{(18 - B_WIDTH){1'b0}}, B};
|
||||
|
||||
(* is_inferred=1 *)
|
||||
dsp_t1_20x18x64_cfg_ports _TECHMAP_REPLACE_ (
|
||||
.a_i (a),
|
||||
.b_i (b),
|
||||
.acc_fir_i (6'd0),
|
||||
.z_o (z),
|
||||
|
||||
.feedback_i (3'd0),
|
||||
.load_acc_i (1'b0),
|
||||
.unsigned_a_i (!A_SIGNED),
|
||||
.unsigned_b_i (!B_SIGNED),
|
||||
|
||||
.output_select_i (3'd0),
|
||||
.saturate_enable_i (1'b0),
|
||||
.shift_right_i (6'd0),
|
||||
.round_i (1'b0),
|
||||
.subtract_i (1'b0),
|
||||
.register_inputs_i (1'b0)
|
||||
);
|
||||
|
||||
assign Y = z;
|
||||
|
||||
endmodule
|
||||
|
||||
module \$__QL_MUL10X9 (input [9:0] A, input [8:0] B, output [18:0] Y);
|
||||
parameter A_SIGNED = 0;
|
||||
parameter B_SIGNED = 0;
|
||||
parameter A_WIDTH = 0;
|
||||
parameter B_WIDTH = 0;
|
||||
parameter Y_WIDTH = 0;
|
||||
|
||||
wire [ 9:0] a;
|
||||
wire [ 8:0] b;
|
||||
wire [18:0] z;
|
||||
|
||||
assign a = (A_WIDTH == 10) ? A :
|
||||
(A_SIGNED) ? {{(10 - A_WIDTH){A[A_WIDTH-1]}}, A} :
|
||||
{{(10 - A_WIDTH){1'b0}}, A};
|
||||
|
||||
assign b = (B_WIDTH == 9) ? B :
|
||||
(B_SIGNED) ? {{( 9 - B_WIDTH){B[B_WIDTH-1]}}, B} :
|
||||
{{( 9 - B_WIDTH){1'b0}}, B};
|
||||
|
||||
(* is_inferred=1 *)
|
||||
dsp_t1_10x9x32_cfg_ports _TECHMAP_REPLACE_ (
|
||||
.a_i (a),
|
||||
.b_i (b),
|
||||
.acc_fir_i (6'd0),
|
||||
.z_o (z),
|
||||
|
||||
.feedback_i (3'd0),
|
||||
.load_acc_i (1'b0),
|
||||
.unsigned_a_i (!A_SIGNED),
|
||||
.unsigned_b_i (!B_SIGNED),
|
||||
|
||||
.output_select_i (3'd0),
|
||||
.saturate_enable_i (1'b0),
|
||||
.shift_right_i (6'd0),
|
||||
.round_i (1'b0),
|
||||
.subtract_i (1'b0),
|
||||
.register_inputs_i (1'b0)
|
||||
);
|
||||
|
||||
|
||||
assign Y = z;
|
||||
|
||||
endmodule
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,133 @@
|
|||
// Copyright 2020-2022 F4PGA Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// DFF, asynchronous set/reset, enable
|
||||
module \$_DFFSRE_PNNP_ (C, S, R, E, D, Q);
|
||||
input C;
|
||||
input S;
|
||||
input R;
|
||||
input E;
|
||||
input D;
|
||||
output Q;
|
||||
dffsre _TECHMAP_REPLACE_ (.Q(Q), .D(D), .C(C), .E(E), .R(R), .S(S));
|
||||
endmodule
|
||||
|
||||
module \$_DFFSRE_NNNP_ (C, S, R, E, D, Q);
|
||||
input C;
|
||||
input S;
|
||||
input R;
|
||||
input E;
|
||||
input D;
|
||||
output Q;
|
||||
dffnsre _TECHMAP_REPLACE_ (.Q(Q), .D(D), .C(C), .E(E), .R(R), .S(S));
|
||||
endmodule
|
||||
|
||||
// DFF, synchronous set or reset, enable
|
||||
module \$_SDFFE_PN0P_ (D, C, R, E, Q);
|
||||
input D;
|
||||
input C;
|
||||
input R;
|
||||
input E;
|
||||
output Q;
|
||||
sdffsre _TECHMAP_REPLACE_ (.Q(Q), .D(D), .C(C), .E(E), .R(R), .S(1'b1));
|
||||
endmodule
|
||||
|
||||
module \$_SDFFE_PN1P_ (D, C, R, E, Q);
|
||||
input D;
|
||||
input C;
|
||||
input R;
|
||||
input E;
|
||||
output Q;
|
||||
sdffsre _TECHMAP_REPLACE_ (.Q(Q), .D(D), .C(C), .E(E), .R(1'b1), .S(R));
|
||||
endmodule
|
||||
|
||||
module \$_SDFFE_NN0P_ (D, C, R, E, Q);
|
||||
input D;
|
||||
input C;
|
||||
input R;
|
||||
input E;
|
||||
output Q;
|
||||
sdffnsre _TECHMAP_REPLACE_ (.Q(Q), .D(D), .C(C), .E(E), .R(R), .S(1'b1));
|
||||
endmodule
|
||||
|
||||
module \$_SDFFE_NN1P_ (D, C, R, E, Q);
|
||||
input D;
|
||||
input C;
|
||||
input R;
|
||||
input E;
|
||||
output Q;
|
||||
sdffnsre _TECHMAP_REPLACE_ (.Q(Q), .D(D), .C(C), .E(E), .R(1'b1), .S(R));
|
||||
endmodule
|
||||
|
||||
// Latch, no set/reset, no enable
|
||||
module \$_DLATCH_P_ (input E, D, output Q);
|
||||
latchsre _TECHMAP_REPLACE_ (.D(D), .Q(Q), .E(1'b1), .G(E), .R(1'b1), .S(1'b1));
|
||||
endmodule
|
||||
|
||||
module \$_DLATCH_N_ (input E, D, output Q);
|
||||
latchnsre _TECHMAP_REPLACE_ (.D(D), .Q(Q), .E(1'b1), .G(E), .R(1'b1), .S(1'b1));
|
||||
endmodule
|
||||
|
||||
// Latch with async set and reset and enable
|
||||
module \$_DLATCHSR_PPP_ (input E, S, R, D, output Q);
|
||||
latchsre _TECHMAP_REPLACE_ (.D(D), .Q(Q), .E(1'b1), .G(E), .R(!R), .S(!S));
|
||||
endmodule
|
||||
|
||||
module \$_DLATCHSR_NPP_ (input E, S, R, D, output Q);
|
||||
latchnsre _TECHMAP_REPLACE_ (.D(D), .Q(Q), .E(1'b1), .G(E), .R(!R), .S(!S));
|
||||
endmodule
|
||||
|
||||
module \$__SHREG_DFF_P_ (D, Q, C);
|
||||
input D;
|
||||
input C;
|
||||
output Q;
|
||||
|
||||
parameter DEPTH = 2;
|
||||
|
||||
reg [DEPTH-2:0] q;
|
||||
|
||||
genvar i;
|
||||
generate for (i = 0; i < DEPTH; i = i + 1) begin: slice
|
||||
|
||||
// First in chain
|
||||
generate if (i == 0) begin
|
||||
sh_dff #() shreg_beg (
|
||||
.Q(q[i]),
|
||||
.D(D),
|
||||
.C(C)
|
||||
);
|
||||
end endgenerate
|
||||
// Middle in chain
|
||||
generate if (i > 0 && i != DEPTH-1) begin
|
||||
sh_dff #() shreg_mid (
|
||||
.Q(q[i]),
|
||||
.D(q[i-1]),
|
||||
.C(C)
|
||||
);
|
||||
end endgenerate
|
||||
// Last in chain
|
||||
generate if (i == DEPTH-1) begin
|
||||
sh_dff #() shreg_end (
|
||||
.Q(Q),
|
||||
.D(q[i-1]),
|
||||
.C(C)
|
||||
);
|
||||
end endgenerate
|
||||
end: slice
|
||||
endgenerate
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,248 @@
|
|||
import sys
|
||||
from datetime import datetime, timezone
|
||||
|
||||
def generate(filename):
|
||||
with open(filename, "w") as f:
|
||||
f.write("// **AUTOGENERATED FILE** **DO NOT EDIT**\n")
|
||||
f.write(f"// Generated by {sys.argv[0]} at {datetime.now(timezone.utc)}\n")
|
||||
|
||||
f.write("`timescale 1ns /10ps\n")
|
||||
for a_width in [1,2,4,9,18,36]:
|
||||
for b_width in [1,2,4,9,18,36]:
|
||||
f.write(f"""
|
||||
module TDP36K_BRAM_A_X{a_width}_B_X{b_width}_nonsplit (
|
||||
RESET_ni,
|
||||
WEN_A1_i, WEN_B1_i,
|
||||
REN_A1_i, REN_B1_i,
|
||||
CLK_A1_i, CLK_B1_i,
|
||||
BE_A1_i, BE_B1_i,
|
||||
ADDR_A1_i, ADDR_B1_i,
|
||||
WDATA_A1_i, WDATA_B1_i,
|
||||
RDATA_A1_o, RDATA_B1_o,
|
||||
FLUSH1_i,
|
||||
WEN_A2_i, WEN_B2_i,
|
||||
REN_A2_i, REN_B2_i,
|
||||
CLK_A2_i, CLK_B2_i,
|
||||
BE_A2_i, BE_B2_i,
|
||||
ADDR_A2_i, ADDR_B2_i,
|
||||
WDATA_A2_i, WDATA_B2_i,
|
||||
RDATA_A2_o, RDATA_B2_o,
|
||||
FLUSH2_i
|
||||
);
|
||||
|
||||
parameter [80:0] MODE_BITS = 81'd0;
|
||||
parameter [1024*36-1:0] RAM_INIT = 36864'bx;
|
||||
|
||||
input wire RESET_ni;
|
||||
input wire WEN_A1_i, WEN_B1_i;
|
||||
input wire REN_A1_i, REN_B1_i;
|
||||
input wire WEN_A2_i, WEN_B2_i;
|
||||
input wire REN_A2_i, REN_B2_i;
|
||||
|
||||
(* clkbuf_sink *)
|
||||
input wire CLK_A1_i;
|
||||
(* clkbuf_sink *)
|
||||
input wire CLK_B1_i;
|
||||
(* clkbuf_sink *)
|
||||
input wire CLK_A2_i;
|
||||
(* clkbuf_sink *)
|
||||
input wire CLK_B2_i;
|
||||
|
||||
input wire [ 1:0] BE_A1_i, BE_B1_i;
|
||||
input wire [14:0] ADDR_A1_i, ADDR_B1_i;
|
||||
input wire [17:0] WDATA_A1_i, WDATA_B1_i;
|
||||
output wire [17:0] RDATA_A1_o, RDATA_B1_o;
|
||||
|
||||
input wire FLUSH1_i;
|
||||
|
||||
input wire [ 1:0] BE_A2_i, BE_B2_i;
|
||||
input wire [13:0] ADDR_A2_i, ADDR_B2_i;
|
||||
input wire [17:0] WDATA_A2_i, WDATA_B2_i;
|
||||
output wire [17:0] RDATA_A2_o, RDATA_B2_o;
|
||||
|
||||
input wire FLUSH2_i;
|
||||
|
||||
TDP36K #(.MODE_BITS(MODE_BITS), .RAM_INIT(RAM_INIT)) bram (
|
||||
.RESET_ni (RESET_ni),
|
||||
.WEN_A1_i (WEN_A1_i), .WEN_B1_i (WEN_B1_i),
|
||||
.REN_A1_i (REN_A1_i), .REN_B1_i (REN_B1_i),
|
||||
.CLK_A1_i (CLK_A1_i), .CLK_B1_i (CLK_B1_i),
|
||||
.BE_A1_i (BE_A1_i), .BE_B1_i (BE_B1_i),
|
||||
.ADDR_A1_i (ADDR_A1_i), .ADDR_B1_i (ADDR_B1_i),
|
||||
.WDATA_A1_i (WDATA_A1_i), .WDATA_B1_i (WDATA_B1_i),
|
||||
.RDATA_A1_o (RDATA_A1_o), .RDATA_B1_o (RDATA_B1_o),
|
||||
.FLUSH1_i (FLUSH1_i),
|
||||
.WEN_A2_i (WEN_A2_i), .WEN_B2_i (WEN_B2_i),
|
||||
.REN_A2_i (REN_A2_i), .REN_B2_i (REN_B2_i),
|
||||
.CLK_A2_i (CLK_A2_i), .CLK_B2_i (CLK_B2_i),
|
||||
.BE_A2_i (BE_A2_i), .BE_B2_i (BE_B2_i),
|
||||
.ADDR_A2_i (ADDR_A2_i), .ADDR_B2_i (ADDR_B2_i),
|
||||
.WDATA_A2_i (WDATA_A2_i), .WDATA_B2_i (WDATA_B2_i),
|
||||
.RDATA_A2_o (RDATA_A2_o), .RDATA_B2_o (RDATA_B2_o),
|
||||
.FLUSH2_i (FLUSH2_i)
|
||||
);
|
||||
|
||||
`ifdef SDF_SIM
|
||||
specify
|
||||
(negedge RESET_ni => (RDATA_A1_o +: WDATA_A1_i)) = 0;
|
||||
(negedge RESET_ni => (RDATA_B1_o +: WDATA_B1_i)) = 0;
|
||||
(negedge RESET_ni => (RDATA_A2_o +: WDATA_A2_i)) = 0;
|
||||
(negedge RESET_ni => (RDATA_B2_o +: WDATA_B2_i)) = 0;
|
||||
(posedge CLK_A1_i => (RDATA_A1_o +: WDATA_A1_i)) = 0;
|
||||
(posedge CLK_B1_i => (RDATA_B1_o +: WDATA_B1_i)) = 0;
|
||||
(posedge CLK_A2_i => (RDATA_A2_o +: WDATA_A2_i)) = 0;
|
||||
(posedge CLK_B2_i => (RDATA_B2_o +: WDATA_B2_i)) = 0;
|
||||
$setuphold(posedge CLK_A1_i, RESET_ni, 0, 0);
|
||||
$setuphold(posedge CLK_A1_i, FLUSH1_i, 0, 0);
|
||||
$setuphold(posedge CLK_A1_i, WEN_A1_i, 0, 0);
|
||||
$setuphold(posedge CLK_A1_i, REN_A1_i, 0, 0);
|
||||
$setuphold(posedge CLK_A1_i, BE_A1_i, 0, 0);
|
||||
$setuphold(posedge CLK_A1_i, ADDR_A1_i, 0, 0);
|
||||
$setuphold(posedge CLK_A1_i, WDATA_A1_i, 0, 0);
|
||||
$setuphold(posedge CLK_B1_i, RESET_ni, 0, 0);
|
||||
$setuphold(posedge CLK_B1_i, WEN_B1_i, 0, 0);
|
||||
$setuphold(posedge CLK_B1_i, REN_B1_i, 0, 0);
|
||||
$setuphold(posedge CLK_B1_i, BE_B1_i, 0, 0);
|
||||
$setuphold(posedge CLK_B1_i, ADDR_B1_i, 0, 0);
|
||||
$setuphold(posedge CLK_B1_i, WDATA_B1_i, 0, 0);
|
||||
$setuphold(posedge CLK_A2_i, RESET_ni, 0, 0);
|
||||
$setuphold(posedge CLK_A2_i, FLUSH2_i, 0, 0);
|
||||
$setuphold(posedge CLK_A2_i, WEN_A2_i, 0, 0);
|
||||
$setuphold(posedge CLK_A2_i, REN_A2_i, 0, 0);
|
||||
$setuphold(posedge CLK_A2_i, BE_A2_i, 0, 0);
|
||||
$setuphold(posedge CLK_A2_i, ADDR_A2_i, 0, 0);
|
||||
$setuphold(posedge CLK_A2_i, WDATA_A2_i, 0, 0);
|
||||
$setuphold(posedge CLK_B2_i, RESET_ni, 0, 0);
|
||||
$setuphold(posedge CLK_B2_i, WEN_B2_i, 0, 0);
|
||||
$setuphold(posedge CLK_B2_i, REN_B2_i, 0, 0);
|
||||
$setuphold(posedge CLK_B2_i, BE_B2_i, 0, 0);
|
||||
$setuphold(posedge CLK_B2_i, ADDR_B2_i, 0, 0);
|
||||
$setuphold(posedge CLK_B2_i, WDATA_B2_i, 0, 0);
|
||||
endspecify
|
||||
`endif
|
||||
endmodule
|
||||
""")
|
||||
|
||||
for a1_width in [1,2,4,9,18]:
|
||||
for b1_width in [1,2,4,9,18]:
|
||||
for a2_width in [1,2,4,9,18]:
|
||||
for b2_width in [1,2,4,9,18]:
|
||||
f.write(f"""
|
||||
module TDP36K_BRAM_A1_X{a1_width}_B1_X{b1_width}_A2_X{a2_width}_B2_X{b2_width}_split (
|
||||
RESET_ni,
|
||||
WEN_A1_i, WEN_B1_i,
|
||||
REN_A1_i, REN_B1_i,
|
||||
CLK_A1_i, CLK_B1_i,
|
||||
BE_A1_i, BE_B1_i,
|
||||
ADDR_A1_i, ADDR_B1_i,
|
||||
WDATA_A1_i, WDATA_B1_i,
|
||||
RDATA_A1_o, RDATA_B1_o,
|
||||
FLUSH1_i,
|
||||
WEN_A2_i, WEN_B2_i,
|
||||
REN_A2_i, REN_B2_i,
|
||||
CLK_A2_i, CLK_B2_i,
|
||||
BE_A2_i, BE_B2_i,
|
||||
ADDR_A2_i, ADDR_B2_i,
|
||||
WDATA_A2_i, WDATA_B2_i,
|
||||
RDATA_A2_o, RDATA_B2_o,
|
||||
FLUSH2_i
|
||||
);
|
||||
|
||||
parameter [80:0] MODE_BITS = 81'd0;
|
||||
parameter [1024*36-1:0] RAM_INIT = 36864'bx;
|
||||
|
||||
input wire RESET_ni;
|
||||
input wire WEN_A1_i, WEN_B1_i;
|
||||
input wire REN_A1_i, REN_B1_i;
|
||||
input wire WEN_A2_i, WEN_B2_i;
|
||||
input wire REN_A2_i, REN_B2_i;
|
||||
|
||||
(* clkbuf_sink *)
|
||||
input wire CLK_A1_i;
|
||||
(* clkbuf_sink *)
|
||||
input wire CLK_B1_i;
|
||||
(* clkbuf_sink *)
|
||||
input wire CLK_A2_i;
|
||||
(* clkbuf_sink *)
|
||||
input wire CLK_B2_i;
|
||||
|
||||
input wire [ 1:0] BE_A1_i, BE_B1_i;
|
||||
input wire [14:0] ADDR_A1_i, ADDR_B1_i;
|
||||
input wire [17:0] WDATA_A1_i, WDATA_B1_i;
|
||||
output wire [17:0] RDATA_A1_o, RDATA_B1_o;
|
||||
|
||||
input wire FLUSH1_i;
|
||||
|
||||
input wire [ 1:0] BE_A2_i, BE_B2_i;
|
||||
input wire [13:0] ADDR_A2_i, ADDR_B2_i;
|
||||
input wire [17:0] WDATA_A2_i, WDATA_B2_i;
|
||||
output wire [17:0] RDATA_A2_o, RDATA_B2_o;
|
||||
|
||||
input wire FLUSH2_i;
|
||||
|
||||
TDP36K #(.MODE_BITS(MODE_BITS), .RAM_INIT(RAM_INIT)) bram (
|
||||
.RESET_ni (RESET_ni),
|
||||
.WEN_A1_i (WEN_A1_i), .WEN_B1_i (WEN_B1_i),
|
||||
.REN_A1_i (REN_A1_i), .REN_B1_i (REN_B1_i),
|
||||
.CLK_A1_i (CLK_A1_i), .CLK_B1_i (CLK_B1_i),
|
||||
.BE_A1_i (BE_A1_i), .BE_B1_i (BE_B1_i),
|
||||
.ADDR_A1_i (ADDR_A1_i), .ADDR_B1_i (ADDR_B1_i),
|
||||
.WDATA_A1_i (WDATA_A1_i), .WDATA_B1_i (WDATA_B1_i),
|
||||
.RDATA_A1_o (RDATA_A1_o), .RDATA_B1_o (RDATA_B1_o),
|
||||
.FLUSH1_i (FLUSH1_i),
|
||||
.WEN_A2_i (WEN_A2_i), .WEN_B2_i (WEN_B2_i),
|
||||
.REN_A2_i (REN_A2_i), .REN_B2_i (REN_B2_i),
|
||||
.CLK_A2_i (CLK_A2_i), .CLK_B2_i (CLK_B2_i),
|
||||
.BE_A2_i (BE_A2_i), .BE_B2_i (BE_B2_i),
|
||||
.ADDR_A2_i (ADDR_A2_i), .ADDR_B2_i (ADDR_B2_i),
|
||||
.WDATA_A2_i (WDATA_A2_i), .WDATA_B2_i (WDATA_B2_i),
|
||||
.RDATA_A2_o (RDATA_A2_o), .RDATA_B2_o (RDATA_B2_o),
|
||||
.FLUSH2_i (FLUSH2_i)
|
||||
);
|
||||
|
||||
`ifdef SDF_SIM
|
||||
specify
|
||||
(negedge RESET_ni => (RDATA_A1_o +: WDATA_A1_i)) = 0;
|
||||
(negedge RESET_ni => (RDATA_B1_o +: WDATA_B1_i)) = 0;
|
||||
(negedge RESET_ni => (RDATA_A2_o +: WDATA_A2_i)) = 0;
|
||||
(negedge RESET_ni => (RDATA_B2_o +: WDATA_B2_i)) = 0;
|
||||
(posedge CLK_A1_i => (RDATA_A1_o +: WDATA_A1_i)) = 0;
|
||||
(posedge CLK_B1_i => (RDATA_B1_o +: WDATA_B1_i)) = 0;
|
||||
(posedge CLK_A2_i => (RDATA_A2_o +: WDATA_A2_i)) = 0;
|
||||
(posedge CLK_B2_i => (RDATA_B2_o +: WDATA_B2_i)) = 0;
|
||||
$setuphold(posedge CLK_A1_i, RESET_ni, 0, 0);
|
||||
$setuphold(posedge CLK_A1_i, FLUSH1_i, 0, 0);
|
||||
$setuphold(posedge CLK_A1_i, WEN_A1_i, 0, 0);
|
||||
$setuphold(posedge CLK_A1_i, REN_A1_i, 0, 0);
|
||||
$setuphold(posedge CLK_A1_i, BE_A1_i, 0, 0);
|
||||
$setuphold(posedge CLK_A1_i, ADDR_A1_i, 0, 0);
|
||||
$setuphold(posedge CLK_A1_i, WDATA_A1_i, 0, 0);
|
||||
$setuphold(posedge CLK_B1_i, RESET_ni, 0, 0);
|
||||
$setuphold(posedge CLK_B1_i, WEN_B1_i, 0, 0);
|
||||
$setuphold(posedge CLK_B1_i, REN_B1_i, 0, 0);
|
||||
$setuphold(posedge CLK_B1_i, BE_B1_i, 0, 0);
|
||||
$setuphold(posedge CLK_B1_i, ADDR_B1_i, 0, 0);
|
||||
$setuphold(posedge CLK_B1_i, WDATA_B1_i, 0, 0);
|
||||
$setuphold(posedge CLK_A2_i, RESET_ni, 0, 0);
|
||||
$setuphold(posedge CLK_A2_i, FLUSH2_i, 0, 0);
|
||||
$setuphold(posedge CLK_A2_i, WEN_A2_i, 0, 0);
|
||||
$setuphold(posedge CLK_A2_i, REN_A2_i, 0, 0);
|
||||
$setuphold(posedge CLK_A2_i, BE_A2_i, 0, 0);
|
||||
$setuphold(posedge CLK_A2_i, ADDR_A2_i, 0, 0);
|
||||
$setuphold(posedge CLK_A2_i, WDATA_A2_i, 0, 0);
|
||||
$setuphold(posedge CLK_B2_i, RESET_ni, 0, 0);
|
||||
$setuphold(posedge CLK_B2_i, WEN_B2_i, 0, 0);
|
||||
$setuphold(posedge CLK_B2_i, REN_B2_i, 0, 0);
|
||||
$setuphold(posedge CLK_B2_i, BE_B2_i, 0, 0);
|
||||
$setuphold(posedge CLK_B2_i, ADDR_B2_i, 0, 0);
|
||||
$setuphold(posedge CLK_B2_i, WDATA_B2_i, 0, 0);
|
||||
endspecify
|
||||
`endif
|
||||
endmodule
|
||||
""")
|
||||
|
||||
if __name__ == "__main__":
|
||||
filename = "bram_types_sim.v"
|
||||
if len(sys.argv) > 1:
|
||||
filename = sys.argv[1]
|
||||
generate(filename)
|
|
@ -0,0 +1,22 @@
|
|||
ram block $__QLF_TDP36K {
|
||||
init any;
|
||||
byte 9;
|
||||
option "SPLIT" 0 {
|
||||
abits 15;
|
||||
widths 1 2 4 9 18 36 per_port;
|
||||
}
|
||||
option "SPLIT" 1 {
|
||||
abits 14;
|
||||
widths 1 2 4 9 18 per_port;
|
||||
}
|
||||
cost 65;
|
||||
port srsw "A" "B" {
|
||||
width tied;
|
||||
clock posedge;
|
||||
# wen causes read even when ren is low
|
||||
# map clken = wen || ren
|
||||
clken;
|
||||
wrbe_separate;
|
||||
rdwr old;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,483 @@
|
|||
// Copyright 2020-2022 F4PGA Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
module \$__QLF_TDP36K (PORT_A_CLK, PORT_A_ADDR, PORT_A_WR_DATA, PORT_A_WR_EN, PORT_A_WR_BE, PORT_A_CLK_EN, PORT_A_RD_DATA,
|
||||
PORT_B_CLK, PORT_B_ADDR, PORT_B_WR_DATA, PORT_B_WR_EN, PORT_B_WR_BE, PORT_B_CLK_EN, PORT_B_RD_DATA);
|
||||
|
||||
parameter INIT = 0;
|
||||
|
||||
parameter OPTION_SPLIT = 0;
|
||||
|
||||
parameter PORT_A_WIDTH = 1;
|
||||
parameter PORT_A_WR_BE_WIDTH = 1;
|
||||
|
||||
parameter PORT_B_WIDTH = 1;
|
||||
parameter PORT_B_WR_BE_WIDTH = 1;
|
||||
|
||||
input PORT_A_CLK;
|
||||
input [14:0] PORT_A_ADDR;
|
||||
input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA;
|
||||
input PORT_A_WR_EN;
|
||||
input [PORT_A_WR_BE_WIDTH-1:0] PORT_A_WR_BE;
|
||||
input PORT_A_CLK_EN;
|
||||
output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA;
|
||||
|
||||
input PORT_B_CLK;
|
||||
input [14:0] PORT_B_ADDR;
|
||||
input [PORT_B_WIDTH-1:0] PORT_B_WR_DATA;
|
||||
input PORT_B_WR_EN;
|
||||
input [PORT_B_WR_BE_WIDTH-1:0] PORT_B_WR_BE;
|
||||
input PORT_B_CLK_EN;
|
||||
output [PORT_B_WIDTH-1:0] PORT_B_RD_DATA;
|
||||
|
||||
|
||||
// Fixed mode settings
|
||||
localparam [ 0:0] SYNC_FIFO1_i = 1'd0;
|
||||
localparam [ 0:0] FMODE1_i = 1'd0;
|
||||
localparam [ 0:0] POWERDN1_i = 1'd0;
|
||||
localparam [ 0:0] SLEEP1_i = 1'd0;
|
||||
localparam [ 0:0] PROTECT1_i = 1'd0;
|
||||
localparam [11:0] UPAE1_i = 12'd10;
|
||||
localparam [11:0] UPAF1_i = 12'd10;
|
||||
|
||||
localparam [ 0:0] SYNC_FIFO2_i = 1'd0;
|
||||
localparam [ 0:0] FMODE2_i = 1'd0;
|
||||
localparam [ 0:0] POWERDN2_i = 1'd0;
|
||||
localparam [ 0:0] SLEEP2_i = 1'd0;
|
||||
localparam [ 0:0] PROTECT2_i = 1'd0;
|
||||
localparam [10:0] UPAE2_i = 11'd10;
|
||||
localparam [10:0] UPAF2_i = 11'd10;
|
||||
|
||||
// Width mode function
|
||||
function [2:0] mode;
|
||||
input integer width;
|
||||
case (width)
|
||||
1: mode = 3'b101;
|
||||
2: mode = 3'b110;
|
||||
4: mode = 3'b100;
|
||||
8,9: mode = 3'b001;
|
||||
16, 18: mode = 3'b010;
|
||||
32, 36: mode = 3'b011;
|
||||
default: mode = 3'b000;
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
function [36863:0] pack_init;
|
||||
integer i;
|
||||
reg [35:0] ri;
|
||||
for (i = 0; i < (OPTION_SPLIT ? 512 : 1024); i = i + 1) begin
|
||||
ri = INIT[i*36 +: 36];
|
||||
pack_init[i*36 +: 36] = {ri[35], ri[26], ri[34:27], ri[25:18],
|
||||
ri[17], ri[8], ri[16:9], ri[7:0]};
|
||||
end
|
||||
if (OPTION_SPLIT)
|
||||
pack_init[36863:18432] = 18432'bx;
|
||||
endfunction
|
||||
|
||||
wire REN_A1_i;
|
||||
wire REN_A2_i;
|
||||
|
||||
wire REN_B1_i;
|
||||
wire REN_B2_i;
|
||||
|
||||
wire WEN_A1_i;
|
||||
wire WEN_A2_i;
|
||||
|
||||
wire WEN_B1_i;
|
||||
wire WEN_B2_i;
|
||||
|
||||
wire [1:0] BE_A1_i;
|
||||
wire [1:0] BE_A2_i;
|
||||
|
||||
wire [1:0] BE_B1_i;
|
||||
wire [1:0] BE_B2_i;
|
||||
|
||||
wire [14:0] ADDR_A1_i;
|
||||
wire [13:0] ADDR_A2_i;
|
||||
|
||||
wire [14:0] ADDR_B1_i;
|
||||
wire [13:0] ADDR_B2_i;
|
||||
|
||||
wire [17:0] WDATA_A1_i;
|
||||
wire [17:0] WDATA_A2_i;
|
||||
|
||||
wire [17:0] WDATA_B1_i;
|
||||
wire [17:0] WDATA_B2_i;
|
||||
|
||||
wire [17:0] RDATA_A1_o;
|
||||
wire [17:0] RDATA_A2_o;
|
||||
|
||||
wire [17:0] RDATA_B1_o;
|
||||
wire [17:0] RDATA_B2_o;
|
||||
|
||||
|
||||
// Set port width mode (In non-split mode A2/B2 is not active. Set same values anyway to match previous behavior.)
|
||||
localparam [ 2:0] RMODE_A1_i = mode(PORT_A_WIDTH);
|
||||
localparam [ 2:0] WMODE_A1_i = mode(PORT_A_WIDTH);
|
||||
localparam [ 2:0] RMODE_A2_i = mode(PORT_A_WIDTH);
|
||||
localparam [ 2:0] WMODE_A2_i = mode(PORT_A_WIDTH);
|
||||
|
||||
localparam [ 2:0] RMODE_B1_i = mode(PORT_B_WIDTH);
|
||||
localparam [ 2:0] WMODE_B1_i = mode(PORT_B_WIDTH);
|
||||
localparam [ 2:0] RMODE_B2_i = mode(PORT_B_WIDTH);
|
||||
localparam [ 2:0] WMODE_B2_i = mode(PORT_B_WIDTH);
|
||||
|
||||
assign REN_A1_i = PORT_A_CLK_EN;
|
||||
assign WEN_A1_i = PORT_A_CLK_EN & PORT_A_WR_EN;
|
||||
assign {BE_A2_i, BE_A1_i} = PORT_A_WR_BE;
|
||||
|
||||
assign REN_B1_i = PORT_B_CLK_EN;
|
||||
assign WEN_B1_i = PORT_B_CLK_EN & PORT_B_WR_EN;
|
||||
assign {BE_B2_i, BE_B1_i} = PORT_B_WR_BE;
|
||||
|
||||
case (PORT_A_WIDTH)
|
||||
9: assign { WDATA_A1_i[16], WDATA_A1_i[7:0] } = PORT_A_WR_DATA;
|
||||
18: assign { WDATA_A1_i[17], WDATA_A1_i[15:8], WDATA_A1_i[16], WDATA_A1_i[7:0] } = PORT_A_WR_DATA;
|
||||
36: assign { WDATA_A2_i[17], WDATA_A2_i[15:8], WDATA_A2_i[16], WDATA_A2_i[7:0], WDATA_A1_i[17], WDATA_A1_i[15:8], WDATA_A1_i[16], WDATA_A1_i[7:0]} = PORT_A_WR_DATA;
|
||||
default: assign WDATA_A1_i = PORT_A_WR_DATA; // 1,2,4
|
||||
endcase
|
||||
|
||||
case (PORT_B_WIDTH)
|
||||
9: assign { WDATA_B1_i[16], WDATA_B1_i[7:0] } = PORT_B_WR_DATA;
|
||||
18: assign { WDATA_B1_i[17], WDATA_B1_i[15:8], WDATA_B1_i[16], WDATA_B1_i[7:0] } = PORT_B_WR_DATA;
|
||||
36: assign { WDATA_B2_i[17], WDATA_B2_i[15:8], WDATA_B2_i[16], WDATA_B2_i[7:0], WDATA_B1_i[17], WDATA_B1_i[15:8], WDATA_B1_i[16], WDATA_B1_i[7:0]} = PORT_B_WR_DATA;
|
||||
default: assign WDATA_B1_i = PORT_B_WR_DATA; // 1,2,4
|
||||
endcase
|
||||
|
||||
case (PORT_A_WIDTH)
|
||||
9: assign PORT_A_RD_DATA = { RDATA_A1_o[16], RDATA_A1_o[7:0] };
|
||||
18: assign PORT_A_RD_DATA = { RDATA_A1_o[17], RDATA_A1_o[15:8], RDATA_A1_o[16], RDATA_A1_o[7:0] };
|
||||
36: assign PORT_A_RD_DATA = { RDATA_A2_o[17], RDATA_A2_o[15:8], RDATA_A2_o[16], RDATA_A2_o[7:0], RDATA_A1_o[17], RDATA_A1_o[15:8], RDATA_A1_o[16], RDATA_A1_o[7:0]};
|
||||
default: assign PORT_A_RD_DATA = RDATA_A1_o; // 1,2,4
|
||||
endcase
|
||||
|
||||
case (PORT_B_WIDTH)
|
||||
9: assign PORT_B_RD_DATA = { RDATA_B1_o[16], RDATA_B1_o[7:0] };
|
||||
18: assign PORT_B_RD_DATA = { RDATA_B1_o[17], RDATA_B1_o[15:8], RDATA_B1_o[16], RDATA_B1_o[7:0] };
|
||||
36: assign PORT_B_RD_DATA = { RDATA_B2_o[17], RDATA_B2_o[15:8], RDATA_B2_o[16], RDATA_B2_o[7:0], RDATA_B1_o[17], RDATA_B1_o[15:8], RDATA_B1_o[16], RDATA_B1_o[7:0]};
|
||||
default: assign PORT_B_RD_DATA = RDATA_B1_o; // 1,2,4
|
||||
endcase
|
||||
|
||||
defparam _TECHMAP_REPLACE_.MODE_BITS = { 1'b0,
|
||||
UPAF2_i, UPAE2_i, PROTECT2_i, SLEEP2_i, POWERDN2_i, FMODE2_i, WMODE_B2_i, WMODE_A2_i, RMODE_B2_i, RMODE_A2_i, SYNC_FIFO2_i,
|
||||
UPAF1_i, UPAE1_i, PROTECT1_i, SLEEP1_i, POWERDN1_i, FMODE1_i, WMODE_B1_i, WMODE_A1_i, RMODE_B1_i, RMODE_A1_i, SYNC_FIFO1_i
|
||||
};
|
||||
|
||||
(* is_inferred = 1 *)
|
||||
(* is_split = 0 *)
|
||||
(* was_split_candidate = OPTION_SPLIT *)
|
||||
(* port_a_width = PORT_A_WIDTH *)
|
||||
(* port_b_width = PORT_B_WIDTH *)
|
||||
TDP36K #(
|
||||
.RAM_INIT(pack_init()),
|
||||
) _TECHMAP_REPLACE_ (
|
||||
.RESET_ni(1'b1),
|
||||
|
||||
.CLK_A1_i(PORT_A_CLK),
|
||||
.ADDR_A1_i(PORT_A_ADDR),
|
||||
.WEN_A1_i(WEN_A1_i),
|
||||
.BE_A1_i(BE_A1_i),
|
||||
.WDATA_A1_i(WDATA_A1_i),
|
||||
.REN_A1_i(REN_A1_i),
|
||||
.RDATA_A1_o(RDATA_A1_o),
|
||||
|
||||
.CLK_A2_i(PORT_A_CLK),
|
||||
.ADDR_A2_i(PORT_A_ADDR[13:0]),
|
||||
.WEN_A2_i(WEN_A1_i),
|
||||
.BE_A2_i(BE_A2_i),
|
||||
.WDATA_A2_i(WDATA_A2_i),
|
||||
.REN_A2_i(REN_A1_i),
|
||||
.RDATA_A2_o(RDATA_A2_o),
|
||||
|
||||
.CLK_B1_i(PORT_B_CLK),
|
||||
.ADDR_B1_i(PORT_B_ADDR),
|
||||
.WEN_B1_i(WEN_B1_i),
|
||||
.BE_B1_i(BE_B1_i),
|
||||
.WDATA_B1_i(WDATA_B1_i),
|
||||
.REN_B1_i(REN_B1_i),
|
||||
.RDATA_B1_o(RDATA_B1_o),
|
||||
|
||||
.CLK_B2_i(PORT_B_CLK),
|
||||
.ADDR_B2_i(PORT_B_ADDR[13:0]),
|
||||
.WEN_B2_i(WEN_B1_i),
|
||||
.BE_B2_i(BE_B2_i),
|
||||
.WDATA_B2_i(WDATA_B2_i),
|
||||
.REN_B2_i(REN_B1_i),
|
||||
.RDATA_B2_o(RDATA_B2_o),
|
||||
|
||||
.FLUSH1_i(1'b0),
|
||||
.FLUSH2_i(1'b0)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
module \$__QLF_TDP36K_MERGED (...);
|
||||
|
||||
parameter INIT1 = 0;
|
||||
|
||||
parameter PORT_A1_WIDTH = 1;
|
||||
parameter PORT_B1_WIDTH = 1;
|
||||
|
||||
parameter PORT_A1_WR_BE_WIDTH = 1;
|
||||
parameter PORT_B1_WR_BE_WIDTH = 1;
|
||||
|
||||
input PORT_A1_CLK;
|
||||
input [14:0] PORT_A1_ADDR;
|
||||
input [PORT_A1_WIDTH-1:0] PORT_A1_WR_DATA;
|
||||
input PORT_A1_WR_EN;
|
||||
input [PORT_A1_WR_BE_WIDTH-1:0] PORT_A1_WR_BE;
|
||||
input PORT_A1_CLK_EN;
|
||||
output [PORT_A1_WIDTH-1:0] PORT_A1_RD_DATA;
|
||||
|
||||
input PORT_B1_CLK;
|
||||
input [14:0] PORT_B1_ADDR;
|
||||
input [PORT_B1_WIDTH-1:0] PORT_B1_WR_DATA;
|
||||
input PORT_B1_WR_EN;
|
||||
input [PORT_B1_WR_BE_WIDTH-1:0] PORT_B1_WR_BE;
|
||||
input PORT_B1_CLK_EN;
|
||||
output [PORT_B1_WIDTH-1:0] PORT_B1_RD_DATA;
|
||||
|
||||
parameter INIT2 = 0;
|
||||
|
||||
parameter PORT_A2_WIDTH = 1;
|
||||
parameter PORT_B2_WIDTH = 1;
|
||||
parameter PORT_A2_WR_BE_WIDTH = 1;
|
||||
parameter PORT_B2_WR_BE_WIDTH = 1;
|
||||
|
||||
input PORT_A2_CLK;
|
||||
input [14:0] PORT_A2_ADDR;
|
||||
input [PORT_A2_WIDTH-1:0] PORT_A2_WR_DATA;
|
||||
input PORT_A2_WR_EN;
|
||||
input [PORT_A2_WR_BE_WIDTH-1:0] PORT_A2_WR_BE;
|
||||
input PORT_A2_CLK_EN;
|
||||
output [PORT_A2_WIDTH-1:0] PORT_A2_RD_DATA;
|
||||
|
||||
input PORT_B2_CLK;
|
||||
input [14:0] PORT_B2_ADDR;
|
||||
input [PORT_B2_WIDTH-1:0] PORT_B2_WR_DATA;
|
||||
input PORT_B2_WR_EN;
|
||||
input [PORT_B2_WR_BE_WIDTH-1:0] PORT_B2_WR_BE;
|
||||
input PORT_B2_CLK_EN;
|
||||
output [PORT_B2_WIDTH-1:0] PORT_B2_RD_DATA;
|
||||
|
||||
|
||||
// Fixed mode settings
|
||||
localparam [ 0:0] SYNC_FIFO1_i = 1'd0;
|
||||
localparam [ 0:0] FMODE1_i = 1'd0;
|
||||
localparam [ 0:0] POWERDN1_i = 1'd0;
|
||||
localparam [ 0:0] SLEEP1_i = 1'd0;
|
||||
localparam [ 0:0] PROTECT1_i = 1'd0;
|
||||
localparam [11:0] UPAE1_i = 12'd10;
|
||||
localparam [11:0] UPAF1_i = 12'd10;
|
||||
|
||||
localparam [ 0:0] SYNC_FIFO2_i = 1'd0;
|
||||
localparam [ 0:0] FMODE2_i = 1'd0;
|
||||
localparam [ 0:0] POWERDN2_i = 1'd0;
|
||||
localparam [ 0:0] SLEEP2_i = 1'd0;
|
||||
localparam [ 0:0] PROTECT2_i = 1'd0;
|
||||
localparam [10:0] UPAE2_i = 11'd10;
|
||||
localparam [10:0] UPAF2_i = 11'd10;
|
||||
|
||||
// Width mode function
|
||||
function [2:0] mode;
|
||||
input integer width;
|
||||
case (width)
|
||||
1: mode = 3'b101;
|
||||
2: mode = 3'b110;
|
||||
4: mode = 3'b100;
|
||||
8,9: mode = 3'b001;
|
||||
16, 18: mode = 3'b010;
|
||||
default: mode = 3'b000;
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
function [36863:0] pack_init;
|
||||
integer i;
|
||||
reg [35:0] ri;
|
||||
for (i = 0; i < 1024; i = i + 1) begin
|
||||
ri = {INIT2[i*18 +: 18], INIT1[i*18 +: 18]};
|
||||
pack_init[i*36 +: 36] = {ri[35], ri[26], ri[34:27], ri[25:18], ri[17], ri[8], ri[16:9], ri[7:0]};
|
||||
end
|
||||
endfunction
|
||||
|
||||
wire REN_A1_i;
|
||||
wire REN_A2_i;
|
||||
|
||||
wire REN_B1_i;
|
||||
wire REN_B2_i;
|
||||
|
||||
wire WEN_A1_i;
|
||||
wire WEN_A2_i;
|
||||
|
||||
wire WEN_B1_i;
|
||||
wire WEN_B2_i;
|
||||
|
||||
wire [1:0] BE_A1_i;
|
||||
wire [1:0] BE_A2_i;
|
||||
|
||||
wire [1:0] BE_B1_i;
|
||||
wire [1:0] BE_B2_i;
|
||||
|
||||
wire [14:0] ADDR_A1_i;
|
||||
wire [13:0] ADDR_A2_i;
|
||||
|
||||
wire [14:0] ADDR_B1_i;
|
||||
wire [13:0] ADDR_B2_i;
|
||||
|
||||
wire [17:0] WDATA_A1_i;
|
||||
wire [17:0] WDATA_A2_i;
|
||||
|
||||
wire [17:0] WDATA_B1_i;
|
||||
wire [17:0] WDATA_B2_i;
|
||||
|
||||
wire [17:0] RDATA_A1_o;
|
||||
wire [17:0] RDATA_A2_o;
|
||||
|
||||
wire [17:0] RDATA_B1_o;
|
||||
wire [17:0] RDATA_B2_o;
|
||||
|
||||
|
||||
// Set port width mode (In non-split mode A2/B2 is not active. Set same values anyway to match previous behavior.)
|
||||
localparam [ 2:0] RMODE_A1_i = mode(PORT_A1_WIDTH);
|
||||
localparam [ 2:0] WMODE_A1_i = mode(PORT_A1_WIDTH);
|
||||
localparam [ 2:0] RMODE_B1_i = mode(PORT_B1_WIDTH);
|
||||
localparam [ 2:0] WMODE_B1_i = mode(PORT_B1_WIDTH);
|
||||
|
||||
localparam [ 2:0] RMODE_A2_i = mode(PORT_A2_WIDTH);
|
||||
localparam [ 2:0] WMODE_A2_i = mode(PORT_A2_WIDTH);
|
||||
localparam [ 2:0] RMODE_B2_i = mode(PORT_B2_WIDTH);
|
||||
localparam [ 2:0] WMODE_B2_i = mode(PORT_B2_WIDTH);
|
||||
|
||||
assign REN_A1_i = PORT_A1_CLK_EN;
|
||||
assign WEN_A1_i = PORT_A1_CLK_EN & PORT_A1_WR_EN;
|
||||
assign BE_A1_i = PORT_A1_WR_BE;
|
||||
|
||||
assign REN_B1_i = PORT_B1_CLK_EN;
|
||||
assign WEN_B1_i = PORT_B1_CLK_EN & PORT_B1_WR_EN;
|
||||
assign BE_B1_i = PORT_B1_WR_BE;
|
||||
|
||||
assign REN_A2_i = PORT_A2_CLK_EN;
|
||||
assign WEN_A2_i = PORT_A2_CLK_EN & PORT_A2_WR_EN;
|
||||
assign BE_A2_i = PORT_A2_WR_BE;
|
||||
|
||||
assign REN_B2_i = PORT_B2_CLK_EN;
|
||||
assign WEN_B2_i = PORT_B2_CLK_EN & PORT_B2_WR_EN;
|
||||
assign BE_B2_i = PORT_B2_WR_BE;
|
||||
|
||||
assign ADDR_A1_i = PORT_A1_ADDR;
|
||||
assign ADDR_B1_i = PORT_B1_ADDR;
|
||||
assign ADDR_A2_i = PORT_A2_ADDR;
|
||||
assign ADDR_B2_i = PORT_B2_ADDR;
|
||||
|
||||
case (PORT_A1_WIDTH)
|
||||
9: assign { WDATA_A1_i[16], WDATA_A1_i[7:0] } = PORT_A1_WR_DATA;
|
||||
18: assign { WDATA_A1_i[17], WDATA_A1_i[15:8], WDATA_A1_i[16], WDATA_A1_i[7:0] } = PORT_A1_WR_DATA;
|
||||
default: assign WDATA_A1_i = PORT_A1_WR_DATA; // 1,2,4,8,16
|
||||
endcase
|
||||
|
||||
case (PORT_B1_WIDTH)
|
||||
9: assign { WDATA_B1_i[16], WDATA_B1_i[7:0] } = PORT_B1_WR_DATA;
|
||||
18: assign { WDATA_B1_i[17], WDATA_B1_i[15:8], WDATA_B1_i[16], WDATA_B1_i[7:0] } = PORT_B1_WR_DATA;
|
||||
default: assign WDATA_B1_i = PORT_B1_WR_DATA; // 1,2,4,8,16
|
||||
endcase
|
||||
|
||||
case (PORT_A1_WIDTH)
|
||||
9: assign PORT_A1_RD_DATA = { RDATA_A1_o[16], RDATA_A1_o[7:0] };
|
||||
18: assign PORT_A1_RD_DATA = { RDATA_A1_o[17], RDATA_A1_o[15:8], RDATA_A1_o[16], RDATA_A1_o[7:0] };
|
||||
default: assign PORT_A1_RD_DATA = RDATA_A1_o; // 1,2,4,8,16
|
||||
endcase
|
||||
|
||||
case (PORT_B1_WIDTH)
|
||||
9: assign PORT_B1_RD_DATA = { RDATA_B1_o[16], RDATA_B1_o[7:0] };
|
||||
18: assign PORT_B1_RD_DATA = { RDATA_B1_o[17], RDATA_B1_o[15:8], RDATA_B1_o[16], RDATA_B1_o[7:0] };
|
||||
default: assign PORT_B1_RD_DATA = RDATA_B1_o; // 1,2,4,8,16
|
||||
endcase
|
||||
|
||||
case (PORT_A2_WIDTH)
|
||||
9: assign { WDATA_A2_i[16], WDATA_A2_i[7:0] } = PORT_A2_WR_DATA;
|
||||
18: assign { WDATA_A2_i[17], WDATA_A2_i[15:8], WDATA_A2_i[16], WDATA_A2_i[7:0] } = PORT_A2_WR_DATA;
|
||||
default: assign WDATA_A2_i = PORT_A2_WR_DATA; // 1,2,4,8,16
|
||||
endcase
|
||||
|
||||
case (PORT_B2_WIDTH)
|
||||
9: assign { WDATA_B2_i[16], WDATA_B2_i[7:0] } = PORT_B2_WR_DATA;
|
||||
18: assign { WDATA_B2_i[17], WDATA_B2_i[15:8], WDATA_B2_i[16], WDATA_B2_i[7:0] } = PORT_B2_WR_DATA;
|
||||
default: assign WDATA_B2_i = PORT_B2_WR_DATA; // 1,2,4,8,16
|
||||
endcase
|
||||
|
||||
case (PORT_A2_WIDTH)
|
||||
9: assign PORT_A2_RD_DATA = { RDATA_A2_o[16], RDATA_A2_o[7:0] };
|
||||
18: assign PORT_A2_RD_DATA = { RDATA_A2_o[17], RDATA_A2_o[15:8], RDATA_A2_o[16], RDATA_A2_o[7:0] };
|
||||
default: assign PORT_A2_RD_DATA = RDATA_A2_o; // 1,2,4,8,16
|
||||
endcase
|
||||
|
||||
case (PORT_B2_WIDTH)
|
||||
9: assign PORT_B2_RD_DATA = { RDATA_B2_o[16], RDATA_B2_o[7:0] };
|
||||
18: assign PORT_B2_RD_DATA = { RDATA_B2_o[17], RDATA_B2_o[15:8], RDATA_B2_o[16], RDATA_B2_o[7:0] };
|
||||
default: assign PORT_B2_RD_DATA = RDATA_B2_o; // 1,2,4,8,16
|
||||
endcase
|
||||
|
||||
defparam _TECHMAP_REPLACE_.MODE_BITS = {1'b1,
|
||||
UPAF2_i, UPAE2_i, PROTECT2_i, SLEEP2_i, POWERDN2_i, FMODE2_i, WMODE_B2_i, WMODE_A2_i, RMODE_B2_i, RMODE_A2_i, SYNC_FIFO2_i,
|
||||
UPAF1_i, UPAE1_i, PROTECT1_i, SLEEP1_i, POWERDN1_i, FMODE1_i, WMODE_B1_i, WMODE_A1_i, RMODE_B1_i, RMODE_A1_i, SYNC_FIFO1_i
|
||||
};
|
||||
|
||||
(* is_inferred = 1 *)
|
||||
(* is_split = 1 *)
|
||||
(* port_a1_width = PORT_A1_WIDTH *)
|
||||
(* port_a2_width = PORT_A2_WIDTH *)
|
||||
(* port_b1_width = PORT_B1_WIDTH *)
|
||||
(* port_b2_width = PORT_B2_WIDTH *)
|
||||
TDP36K #(
|
||||
.RAM_INIT(pack_init()),
|
||||
) _TECHMAP_REPLACE_ (
|
||||
.RESET_ni(1'b1),
|
||||
.WDATA_A1_i(WDATA_A1_i),
|
||||
.WDATA_A2_i(WDATA_A2_i),
|
||||
.RDATA_A1_o(RDATA_A1_o),
|
||||
.RDATA_A2_o(RDATA_A2_o),
|
||||
.ADDR_A1_i(ADDR_A1_i),
|
||||
.ADDR_A2_i(ADDR_A2_i),
|
||||
.CLK_A1_i(PORT_A1_CLK),
|
||||
.CLK_A2_i(PORT_A2_CLK),
|
||||
.REN_A1_i(REN_A1_i),
|
||||
.REN_A2_i(REN_A2_i),
|
||||
.WEN_A1_i(WEN_A1_i),
|
||||
.WEN_A2_i(WEN_A2_i),
|
||||
.BE_A1_i(BE_A1_i),
|
||||
.BE_A2_i(BE_A2_i),
|
||||
|
||||
.WDATA_B1_i(WDATA_B1_i),
|
||||
.WDATA_B2_i(WDATA_B2_i),
|
||||
.RDATA_B1_o(RDATA_B1_o),
|
||||
.RDATA_B2_o(RDATA_B2_o),
|
||||
.ADDR_B1_i(ADDR_B1_i),
|
||||
.ADDR_B2_i(ADDR_B2_i),
|
||||
.CLK_B1_i(PORT_B1_CLK),
|
||||
.CLK_B2_i(PORT_B2_CLK),
|
||||
.REN_B1_i(REN_B1_i),
|
||||
.REN_B2_i(REN_B2_i),
|
||||
.WEN_B1_i(WEN_B1_i),
|
||||
.WEN_B2_i(WEN_B2_i),
|
||||
.BE_B1_i(BE_B1_i),
|
||||
.BE_B2_i(BE_B2_i),
|
||||
|
||||
.FLUSH1_i(1'b0),
|
||||
.FLUSH2_i(1'b0)
|
||||
);
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,64 @@
|
|||
`default_nettype none
|
||||
module sram1024x18 (
|
||||
clk_a,
|
||||
cen_a,
|
||||
wen_a,
|
||||
addr_a,
|
||||
wmsk_a,
|
||||
wdata_a,
|
||||
rdata_a,
|
||||
clk_b,
|
||||
cen_b,
|
||||
wen_b,
|
||||
addr_b,
|
||||
wmsk_b,
|
||||
wdata_b,
|
||||
rdata_b
|
||||
);
|
||||
parameter [1024*18-1:0] init = 18431'bx;
|
||||
(* clkbuf_sink *)
|
||||
input wire clk_a;
|
||||
input wire cen_a;
|
||||
input wire wen_a;
|
||||
input wire [9:0] addr_a;
|
||||
input wire [17:0] wmsk_a;
|
||||
input wire [17:0] wdata_a;
|
||||
output reg [17:0] rdata_a;
|
||||
(* clkbuf_sink *)
|
||||
input wire clk_b;
|
||||
input wire cen_b;
|
||||
input wire wen_b;
|
||||
input wire [9:0] addr_b;
|
||||
input wire [17:0] wmsk_b;
|
||||
input wire [17:0] wdata_b;
|
||||
output reg [17:0] rdata_b;
|
||||
reg [17:0] ram [1023:0];
|
||||
integer i;
|
||||
initial begin
|
||||
for (i = 0; i < 1024; i = i + 1) begin
|
||||
ram[i] = init[18*i +: 18];
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk_a) begin
|
||||
if (!cen_a) begin
|
||||
if (!wen_a)
|
||||
for (i = 0; i < 18; i++) begin
|
||||
if (!wmsk_a[i]) ram[addr_a][i] <= wdata_a[i];
|
||||
end
|
||||
rdata_a <= ram[addr_a];
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk_b) begin
|
||||
if (!cen_b) begin
|
||||
if (!wen_b)
|
||||
for (i = 0; i < 18; i++) begin
|
||||
if (!wmsk_b[i]) ram[addr_b][i] <= wdata_b[i];
|
||||
end
|
||||
rdata_b <= ram[addr_b];
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,620 @@
|
|||
// Copyright 2020-2022 F4PGA Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
`default_nettype wire
|
||||
module fifo_ctl (
|
||||
raddr,
|
||||
waddr,
|
||||
fflags,
|
||||
ren_o,
|
||||
sync,
|
||||
rmode,
|
||||
wmode,
|
||||
rclk,
|
||||
rst_R_n,
|
||||
wclk,
|
||||
rst_W_n,
|
||||
ren,
|
||||
wen,
|
||||
upaf,
|
||||
upae
|
||||
);
|
||||
parameter ADDR_WIDTH = 11;
|
||||
parameter FIFO_WIDTH = 3'd2;
|
||||
parameter DEPTH = 6;
|
||||
output wire [ADDR_WIDTH - 1:0] raddr;
|
||||
output wire [ADDR_WIDTH - 1:0] waddr;
|
||||
output wire [7:0] fflags;
|
||||
output wire ren_o;
|
||||
input wire sync;
|
||||
input wire [1:0] rmode;
|
||||
input wire [1:0] wmode;
|
||||
(* clkbuf_sink *)
|
||||
input wire rclk;
|
||||
input wire rst_R_n;
|
||||
(* clkbuf_sink *)
|
||||
input wire wclk;
|
||||
input wire rst_W_n;
|
||||
input wire ren;
|
||||
input wire wen;
|
||||
input wire [ADDR_WIDTH - 1:0] upaf;
|
||||
input wire [ADDR_WIDTH - 1:0] upae;
|
||||
localparam ADDR_PLUS_ONE = ADDR_WIDTH + 1;
|
||||
reg [ADDR_WIDTH:0] pushtopop1;
|
||||
reg [ADDR_WIDTH:0] pushtopop2;
|
||||
reg [ADDR_WIDTH:0] poptopush1;
|
||||
reg [ADDR_WIDTH:0] poptopush2;
|
||||
wire [ADDR_WIDTH:0] pushtopop0;
|
||||
wire [ADDR_WIDTH:0] poptopush0;
|
||||
wire [ADDR_WIDTH:0] smux_poptopush;
|
||||
wire [ADDR_WIDTH:0] smux_pushtopop;
|
||||
assign smux_poptopush = (sync ? poptopush0 : poptopush2);
|
||||
assign smux_pushtopop = (sync ? pushtopop0 : pushtopop2);
|
||||
always @(posedge rclk or negedge rst_R_n)
|
||||
if (~rst_R_n) begin
|
||||
pushtopop1 <= 'h0;
|
||||
pushtopop2 <= 'h0;
|
||||
end
|
||||
else begin
|
||||
pushtopop1 = pushtopop0;
|
||||
pushtopop2 = pushtopop1;
|
||||
end
|
||||
always @(posedge wclk or negedge rst_W_n)
|
||||
if (~rst_W_n) begin
|
||||
poptopush1 <= 'h0;
|
||||
poptopush2 <= 'h0;
|
||||
end
|
||||
else begin
|
||||
poptopush1 <= poptopush0;
|
||||
poptopush2 <= poptopush1;
|
||||
end
|
||||
fifo_push #(
|
||||
.ADDR_WIDTH(ADDR_WIDTH),
|
||||
.DEPTH(DEPTH)
|
||||
) u_fifo_push(
|
||||
.wclk(wclk),
|
||||
.wen(wen),
|
||||
.rst_n(rst_W_n),
|
||||
.rmode(rmode),
|
||||
.wmode(wmode),
|
||||
.gcout(pushtopop0),
|
||||
.gcin(smux_poptopush),
|
||||
.ff_waddr(waddr),
|
||||
.pushflags(fflags[7:4]),
|
||||
.upaf(upaf)
|
||||
);
|
||||
fifo_pop #(
|
||||
.ADDR_WIDTH(ADDR_WIDTH),
|
||||
.FIFO_WIDTH(FIFO_WIDTH),
|
||||
.DEPTH(DEPTH)
|
||||
) u_fifo_pop(
|
||||
.rclk(rclk),
|
||||
.ren_in(ren),
|
||||
.rst_n(rst_R_n),
|
||||
.rmode(rmode),
|
||||
.wmode(wmode),
|
||||
.ren_o(ren_o),
|
||||
.gcout(poptopush0),
|
||||
.gcin(smux_pushtopop),
|
||||
.out_raddr(raddr),
|
||||
.popflags(fflags[3:0]),
|
||||
.upae(upae)
|
||||
);
|
||||
endmodule
|
||||
module fifo_push (
|
||||
pushflags,
|
||||
gcout,
|
||||
ff_waddr,
|
||||
rst_n,
|
||||
wclk,
|
||||
wen,
|
||||
rmode,
|
||||
wmode,
|
||||
gcin,
|
||||
upaf
|
||||
);
|
||||
parameter ADDR_WIDTH = 11;
|
||||
parameter DEPTH = 6;
|
||||
output wire [3:0] pushflags;
|
||||
output wire [ADDR_WIDTH:0] gcout;
|
||||
output wire [ADDR_WIDTH - 1:0] ff_waddr;
|
||||
input rst_n;
|
||||
(* clkbuf_sink *)
|
||||
input wclk;
|
||||
input wen;
|
||||
input [1:0] rmode;
|
||||
input [1:0] wmode;
|
||||
input [ADDR_WIDTH:0] gcin;
|
||||
input [ADDR_WIDTH - 1:0] upaf;
|
||||
localparam ADDR_PLUS_ONE = ADDR_WIDTH + 1;
|
||||
reg full_next;
|
||||
reg full;
|
||||
reg paf_next;
|
||||
reg paf;
|
||||
reg fmo;
|
||||
reg fmo_next;
|
||||
reg overflow;
|
||||
reg p1;
|
||||
reg p2;
|
||||
reg f1;
|
||||
reg f2;
|
||||
reg q1;
|
||||
reg q2;
|
||||
reg [1:0] gmode;
|
||||
reg [ADDR_WIDTH:0] waddr;
|
||||
reg [ADDR_WIDTH:0] raddr;
|
||||
reg [ADDR_WIDTH:0] gcout_reg;
|
||||
reg [ADDR_WIDTH:0] gcout_next;
|
||||
reg [ADDR_WIDTH:0] raddr_next;
|
||||
reg [ADDR_WIDTH - 1:0] paf_thresh;
|
||||
wire overflow_next;
|
||||
wire [ADDR_WIDTH:0] waddr_next;
|
||||
wire [ADDR_WIDTH:0] gc8out_next;
|
||||
wire [ADDR_WIDTH - 1:0] gc16out_next;
|
||||
wire [ADDR_WIDTH - 2:0] gc32out_next;
|
||||
wire [ADDR_WIDTH:0] tmp;
|
||||
wire [ADDR_WIDTH:0] next_count;
|
||||
wire [ADDR_WIDTH:0] count;
|
||||
wire [ADDR_WIDTH:0] fbytes;
|
||||
genvar i;
|
||||
assign next_count = fbytes - (waddr_next >= raddr_next ? waddr_next - raddr_next : (~raddr_next + waddr_next) + 1);
|
||||
assign count = fbytes - (waddr >= raddr ? waddr - raddr : (~raddr + waddr) + 1);
|
||||
assign fbytes = 1 << (DEPTH + 5);
|
||||
always @(*) begin
|
||||
paf_thresh = wmode[1] ? upaf : (wmode[0] ? upaf << 1 : upaf << 2);
|
||||
end
|
||||
always @(*)
|
||||
case (wmode)
|
||||
2'h0, 2'h1, 2'h2: begin
|
||||
full_next = (wen ? f1 : f2);
|
||||
fmo_next = (wen ? p1 : p2);
|
||||
paf_next = (wen ? q1 : q2);
|
||||
end
|
||||
default: begin
|
||||
full_next = 1'b0;
|
||||
fmo_next = 1'b0;
|
||||
paf_next = 1'b0;
|
||||
end
|
||||
endcase
|
||||
always @(*) begin : PUSH_FULL_FLAGS
|
||||
f1 = 1'b0;
|
||||
f2 = 1'b0;
|
||||
p1 = 1'b0;
|
||||
p2 = 1'b0;
|
||||
q1 = next_count < {1'b0, paf_thresh};
|
||||
q2 = count < {1'b0, paf_thresh};
|
||||
case (wmode)
|
||||
2'h0:
|
||||
case (DEPTH)
|
||||
3'h6: begin
|
||||
f1 = {~waddr_next[11], waddr_next[10:2]} == raddr_next[11:2];
|
||||
f2 = {~waddr[11], waddr[10:2]} == raddr_next[11:2];
|
||||
p1 = ((waddr_next[10:2] + 1) & 9'h1ff) == raddr_next[10:2];
|
||||
p2 = ((waddr[10:2] + 1) & 9'h1ff) == raddr_next[10:2];
|
||||
end
|
||||
3'h5: begin
|
||||
f1 = {~waddr_next[10], waddr_next[9:2]} == raddr_next[10:2];
|
||||
f2 = {~waddr[10], waddr[9:2]} == raddr_next[10:2];
|
||||
p1 = ((waddr_next[9:2] + 1) & 8'hff) == raddr_next[9:2];
|
||||
p2 = ((waddr[9:2] + 1) & 8'hff) == raddr_next[9:2];
|
||||
end
|
||||
3'h4: begin
|
||||
f1 = {~waddr_next[9], waddr_next[8:2]} == raddr_next[9:2];
|
||||
f2 = {~waddr[9], waddr[8:2]} == raddr_next[9:2];
|
||||
p1 = ((waddr_next[8:2] + 1) & 7'h7f) == raddr_next[8:2];
|
||||
p2 = ((waddr[8:2] + 1) & 7'h7f) == raddr_next[8:2];
|
||||
end
|
||||
3'h3: begin
|
||||
f1 = {~waddr_next[8], waddr_next[7:2]} == raddr_next[8:2];
|
||||
f2 = {~waddr[8], waddr[7:2]} == raddr_next[8:2];
|
||||
p1 = ((waddr_next[7:2] + 1) & 6'h3f) == raddr_next[7:2];
|
||||
p2 = ((waddr[7:2] + 1) & 6'h3f) == raddr_next[7:2];
|
||||
end
|
||||
3'h2: begin
|
||||
f1 = {~waddr_next[7], waddr_next[6:2]} == raddr_next[7:2];
|
||||
f2 = {~waddr[7], waddr[6:2]} == raddr_next[7:2];
|
||||
p1 = ((waddr_next[6:2] + 1) & 5'h1f) == raddr_next[6:2];
|
||||
p2 = ((waddr[6:2] + 1) & 5'h1f) == raddr_next[6:2];
|
||||
end
|
||||
3'h1: begin
|
||||
f1 = {~waddr_next[6], waddr_next[5:2]} == raddr_next[6:2];
|
||||
f2 = {~waddr[6], waddr[5:2]} == raddr_next[6:2];
|
||||
p1 = ((waddr_next[5:2] + 1) & 4'hf) == raddr_next[5:2];
|
||||
p2 = ((waddr[5:2] + 1) & 4'hf) == raddr_next[5:2];
|
||||
end
|
||||
3'h0: begin
|
||||
f1 = {~waddr_next[5], waddr_next[4:2]} == raddr_next[5:2];
|
||||
f2 = {~waddr[5], waddr[4:2]} == raddr_next[5:2];
|
||||
p1 = ((waddr_next[4:2] + 1) & 3'h7) == raddr_next[4:2];
|
||||
p2 = ((waddr[4:2] + 1) & 3'h7) == raddr_next[4:2];
|
||||
end
|
||||
3'h7: begin
|
||||
f1 = {~waddr_next[ADDR_WIDTH], waddr_next[ADDR_WIDTH - 1:2]} == raddr_next[ADDR_WIDTH:2];
|
||||
f2 = {~waddr[ADDR_WIDTH], waddr[ADDR_WIDTH - 1:2]} == raddr_next[ADDR_WIDTH:2];
|
||||
p1 = ((waddr_next[ADDR_WIDTH - 1:2] + 1) & {ADDR_WIDTH - 2 {1'b1}}) == raddr_next[ADDR_WIDTH - 1:2];
|
||||
p2 = ((waddr[ADDR_WIDTH - 1:2] + 1) & {ADDR_WIDTH - 2 {1'b1}}) == raddr_next[ADDR_WIDTH - 1:2];
|
||||
end
|
||||
endcase
|
||||
2'h1:
|
||||
case (DEPTH)
|
||||
3'h6: begin
|
||||
f1 = {~waddr_next[11], waddr_next[10:1]} == raddr_next[11:1];
|
||||
f2 = {~waddr[11], waddr[10:1]} == raddr_next[11:1];
|
||||
p1 = ((waddr_next[10:1] + 1) & 10'h3ff) == raddr_next[10:1];
|
||||
p2 = ((waddr[10:1] + 1) & 10'h3ff) == raddr_next[10:1];
|
||||
end
|
||||
3'h5: begin
|
||||
f1 = {~waddr_next[10], waddr_next[9:1]} == raddr_next[10:1];
|
||||
f2 = {~waddr[10], waddr[9:1]} == raddr_next[10:1];
|
||||
p1 = ((waddr_next[9:1] + 1) & 9'h1ff) == raddr_next[9:1];
|
||||
p2 = ((waddr[9:1] + 1) & 9'h1ff) == raddr_next[9:1];
|
||||
end
|
||||
3'h4: begin
|
||||
f1 = {~waddr_next[9], waddr_next[8:1]} == raddr_next[9:1];
|
||||
f2 = {~waddr[9], waddr[8:1]} == raddr_next[9:1];
|
||||
p1 = ((waddr_next[8:1] + 1) & 8'hff) == raddr_next[8:1];
|
||||
p2 = ((waddr[8:1] + 1) & 8'hff) == raddr_next[8:1];
|
||||
end
|
||||
3'h3: begin
|
||||
f1 = {~waddr_next[8], waddr_next[7:1]} == raddr_next[8:1];
|
||||
f2 = {~waddr[8], waddr[7:1]} == raddr_next[8:1];
|
||||
p1 = ((waddr_next[7:1] + 1) & 7'h7f) == raddr_next[7:1];
|
||||
p2 = ((waddr[7:1] + 1) & 7'h7f) == raddr_next[7:1];
|
||||
end
|
||||
3'h2: begin
|
||||
f1 = {~waddr_next[7], waddr_next[6:1]} == raddr_next[7:1];
|
||||
f2 = {~waddr[7], waddr[6:1]} == raddr_next[7:1];
|
||||
p1 = ((waddr_next[6:1] + 1) & 6'h3f) == raddr_next[6:1];
|
||||
p2 = ((waddr[6:1] + 1) & 6'h3f) == raddr_next[6:1];
|
||||
end
|
||||
3'h1: begin
|
||||
f1 = {~waddr_next[6], waddr_next[5:1]} == raddr_next[6:1];
|
||||
f2 = {~waddr[6], waddr[5:1]} == raddr_next[6:1];
|
||||
p1 = ((waddr_next[5:1] + 1) & 5'h1f) == raddr_next[5:1];
|
||||
p2 = ((waddr[5:1] + 1) & 5'h1f) == raddr_next[5:1];
|
||||
end
|
||||
3'h0: begin
|
||||
f1 = {~waddr_next[5], waddr_next[4:1]} == raddr_next[5:1];
|
||||
f2 = {~waddr[5], waddr[4:1]} == raddr_next[5:1];
|
||||
p1 = ((waddr_next[4:1] + 1) & 4'hf) == raddr_next[4:1];
|
||||
p2 = ((waddr[4:1] + 1) & 4'hf) == raddr_next[4:1];
|
||||
end
|
||||
3'h7: begin
|
||||
f1 = {~waddr_next[ADDR_WIDTH], waddr_next[ADDR_WIDTH - 1:1]} == raddr_next[ADDR_WIDTH:1];
|
||||
f2 = {~waddr[ADDR_WIDTH], waddr[ADDR_WIDTH - 1:1]} == raddr_next[ADDR_WIDTH:1];
|
||||
p1 = ((waddr_next[ADDR_WIDTH - 1:1] + 1) & {ADDR_WIDTH - 1 {1'b1}}) == raddr_next[ADDR_WIDTH - 1:1];
|
||||
p2 = ((waddr[ADDR_WIDTH - 1:1] + 1) & {ADDR_WIDTH - 1 {1'b1}}) == raddr_next[ADDR_WIDTH - 1:1];
|
||||
end
|
||||
endcase
|
||||
2'h2:
|
||||
case (DEPTH)
|
||||
3'h6: begin
|
||||
f1 = {~waddr_next[11], waddr_next[10:0]} == raddr_next[11:0];
|
||||
f2 = {~waddr[11], waddr[10:0]} == raddr_next[11:0];
|
||||
p1 = ((waddr_next[10:0] + 1) & 11'h7ff) == raddr_next[10:0];
|
||||
p2 = ((waddr[10:0] + 1) & 11'h7ff) == raddr_next[10:0];
|
||||
end
|
||||
3'h5: begin
|
||||
f1 = {~waddr_next[10], waddr_next[9:0]} == raddr_next[10:0];
|
||||
f2 = {~waddr[10], waddr[9:0]} == raddr_next[10:0];
|
||||
p1 = ((waddr_next[9:0] + 1) & 10'h3ff) == raddr_next[9:0];
|
||||
p2 = ((waddr[9:0] + 1) & 10'h3ff) == raddr_next[9:0];
|
||||
end
|
||||
3'h4: begin
|
||||
f1 = {~waddr_next[9], waddr_next[8:0]} == raddr_next[9:0];
|
||||
f2 = {~waddr[9], waddr[8:0]} == raddr_next[9:0];
|
||||
p1 = ((waddr_next[8:0] + 1) & 9'h1ff) == raddr_next[8:0];
|
||||
p2 = ((waddr[8:0] + 1) & 9'h1ff) == raddr_next[8:0];
|
||||
end
|
||||
3'h3: begin
|
||||
f1 = {~waddr_next[8], waddr_next[7:0]} == raddr_next[8:0];
|
||||
f2 = {~waddr[8], waddr[7:0]} == raddr_next[8:0];
|
||||
p1 = ((waddr_next[7:0] + 1) & 8'hff) == raddr_next[7:0];
|
||||
p2 = ((waddr[7:0] + 1) & 8'hff) == raddr_next[7:0];
|
||||
end
|
||||
3'h2: begin
|
||||
f1 = {~waddr_next[7], waddr_next[6:0]} == raddr_next[7:0];
|
||||
f2 = {~waddr[7], waddr[6:0]} == raddr_next[7:0];
|
||||
p1 = ((waddr_next[6:0] + 1) & 7'h7f) == raddr_next[6:0];
|
||||
p2 = ((waddr[6:0] + 1) & 7'h7f) == raddr_next[6:0];
|
||||
end
|
||||
3'h1: begin
|
||||
f1 = {~waddr_next[6], waddr_next[5:0]} == raddr_next[6:0];
|
||||
f2 = {~waddr[6], waddr[5:0]} == raddr_next[6:0];
|
||||
p1 = ((waddr_next[5:0] + 1) & 6'h3f) == raddr_next[5:0];
|
||||
p2 = ((waddr[5:0] + 1) & 6'h3f) == raddr_next[5:0];
|
||||
end
|
||||
3'h0: begin
|
||||
f1 = {~waddr_next[5], waddr_next[4:0]} == raddr_next[5:0];
|
||||
f2 = {~waddr[5], waddr[4:0]} == raddr_next[5:0];
|
||||
p1 = ((waddr_next[4:0] + 1) & 5'h1f) == raddr_next[4:0];
|
||||
p2 = ((waddr[4:0] + 1) & 5'h1f) == raddr_next[4:0];
|
||||
end
|
||||
3'h7: begin
|
||||
f1 = {~waddr_next[ADDR_WIDTH], waddr_next[ADDR_WIDTH - 1:0]} == raddr_next[ADDR_WIDTH:0];
|
||||
f2 = {~waddr[ADDR_WIDTH], waddr[ADDR_WIDTH - 1:0]} == raddr_next[ADDR_WIDTH:0];
|
||||
p1 = ((waddr_next[ADDR_WIDTH - 1:0] + 1) & {ADDR_WIDTH {1'b1}}) == raddr_next[ADDR_WIDTH - 1:0];
|
||||
p2 = ((waddr[ADDR_WIDTH - 1:0] + 1) & {ADDR_WIDTH {1'b1}}) == raddr_next[ADDR_WIDTH - 1:0];
|
||||
end
|
||||
endcase
|
||||
2'h3: begin
|
||||
f1 = 1'b0;
|
||||
f2 = 1'b0;
|
||||
p1 = 1'b0;
|
||||
p2 = 1'b0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
always @(*)
|
||||
case (wmode)
|
||||
2'h0: gmode = 2'h0;
|
||||
2'h1: gmode = (rmode == 2'h0 ? 2'h0 : 2'h1);
|
||||
2'h2: gmode = (rmode == 2'h2 ? 2'h2 : rmode);
|
||||
2'h3: gmode = 2'h3;
|
||||
endcase
|
||||
assign gc8out_next = (waddr_next >> 1) ^ waddr_next;
|
||||
assign gc16out_next = (waddr_next >> 2) ^ (waddr_next >> 1);
|
||||
assign gc32out_next = (waddr_next >> 3) ^ (waddr_next >> 2);
|
||||
always @(*)
|
||||
if (wen)
|
||||
case (gmode)
|
||||
2'h2: gcout_next = gc8out_next;
|
||||
2'h1: gcout_next = {1'b0, gc16out_next};
|
||||
2'h0: gcout_next = {2'b00, gc32out_next};
|
||||
default: gcout_next = {ADDR_PLUS_ONE {1'b0}};
|
||||
endcase
|
||||
else
|
||||
gcout_next = {ADDR_PLUS_ONE {1'b0}};
|
||||
always @(posedge wclk or negedge rst_n)
|
||||
if (~rst_n) begin
|
||||
full <= 1'b0;
|
||||
fmo <= 1'b0;
|
||||
paf <= 1'b0;
|
||||
raddr <= {ADDR_PLUS_ONE {1'b0}};
|
||||
end
|
||||
else begin
|
||||
full <= full_next;
|
||||
fmo <= fmo_next;
|
||||
paf <= paf_next;
|
||||
case (gmode)
|
||||
0: raddr <= raddr_next & {{ADDR_WIDTH - 1 {1'b1}}, 2'b00};
|
||||
1: raddr <= raddr_next & {{ADDR_WIDTH {1'b1}}, 1'b0};
|
||||
2: raddr <= raddr_next & {ADDR_WIDTH + 1 {1'b1}};
|
||||
3: raddr <= 12'h000;
|
||||
endcase
|
||||
end
|
||||
assign overflow_next = full & wen;
|
||||
always @(posedge wclk or negedge rst_n)
|
||||
if (~rst_n)
|
||||
overflow <= 1'b0;
|
||||
else if (wen == 1'b1)
|
||||
overflow <= overflow_next;
|
||||
always @(posedge wclk or negedge rst_n)
|
||||
if (~rst_n) begin
|
||||
waddr <= {ADDR_WIDTH + 1 {1'b0}};
|
||||
gcout_reg <= {ADDR_WIDTH + 1 {1'b0}};
|
||||
end
|
||||
else if (wen == 1'b1) begin
|
||||
waddr <= waddr_next;
|
||||
gcout_reg <= gcout_next;
|
||||
end
|
||||
assign gcout = gcout_reg;
|
||||
generate
|
||||
for (i = 0; i < (ADDR_WIDTH + 1); i = i + 1) begin : genblk1
|
||||
assign tmp[i] = ^(gcin >> i);
|
||||
end
|
||||
endgenerate
|
||||
always @(*)
|
||||
case (gmode)
|
||||
2'h0: raddr_next = {tmp[ADDR_WIDTH - 2:0], 2'b00} & {{ADDR_WIDTH - 1 {1'b1}}, 2'b00};
|
||||
2'h1: raddr_next = {tmp[ADDR_WIDTH - 1:0], 1'b0} & {{ADDR_WIDTH {1'b1}}, 1'b0};
|
||||
2'h2: raddr_next = {tmp[ADDR_WIDTH:0]} & {ADDR_WIDTH + 1 {1'b1}};
|
||||
default: raddr_next = {ADDR_WIDTH + 1 {1'b0}};
|
||||
endcase
|
||||
assign ff_waddr = waddr[ADDR_WIDTH - 1:0];
|
||||
assign pushflags = {full, fmo, paf, overflow};
|
||||
assign waddr_next = waddr + (wmode == 2'h0 ? 'h4 : (wmode == 2'h1 ? 'h2 : 'h1));
|
||||
endmodule
|
||||
module fifo_pop (
|
||||
ren_o,
|
||||
popflags,
|
||||
out_raddr,
|
||||
gcout,
|
||||
rst_n,
|
||||
rclk,
|
||||
ren_in,
|
||||
rmode,
|
||||
wmode,
|
||||
gcin,
|
||||
upae
|
||||
);
|
||||
parameter ADDR_WIDTH = 11;
|
||||
parameter FIFO_WIDTH = 3'd2;
|
||||
parameter DEPTH = 6;
|
||||
output wire ren_o;
|
||||
output wire [3:0] popflags;
|
||||
output reg [ADDR_WIDTH - 1:0] out_raddr;
|
||||
output wire [ADDR_WIDTH:0] gcout;
|
||||
input rst_n;
|
||||
(* clkbuf_sink *)
|
||||
input rclk;
|
||||
input ren_in;
|
||||
input [1:0] rmode;
|
||||
input [1:0] wmode;
|
||||
input [ADDR_WIDTH:0] gcin;
|
||||
input [ADDR_WIDTH - 1:0] upae;
|
||||
localparam ADDR_PLUS_ONE = ADDR_WIDTH + 1;
|
||||
reg empty;
|
||||
reg epo;
|
||||
reg pae;
|
||||
reg underflow;
|
||||
reg e1;
|
||||
reg e2;
|
||||
reg o1;
|
||||
reg o2;
|
||||
reg q1;
|
||||
reg q2;
|
||||
reg [1:0] bwl_sel;
|
||||
reg [1:0] gmode;
|
||||
reg [ADDR_WIDTH - 1:0] ff_raddr;
|
||||
reg [ADDR_WIDTH:0] waddr;
|
||||
reg [ADDR_WIDTH:0] raddr;
|
||||
reg [ADDR_WIDTH:0] gcout_reg;
|
||||
reg [ADDR_WIDTH:0] gcout_next;
|
||||
reg [ADDR_WIDTH:0] waddr_next;
|
||||
reg [ADDR_WIDTH - 1:0] pae_thresh;
|
||||
wire ren_out;
|
||||
wire empty_next;
|
||||
wire pae_next;
|
||||
wire epo_next;
|
||||
wire [ADDR_WIDTH - 2:0] gc32out_next;
|
||||
wire [ADDR_WIDTH - 1:0] gc16out_next;
|
||||
wire [ADDR_WIDTH:0] gc8out_next;
|
||||
wire [ADDR_WIDTH:0] raddr_next;
|
||||
wire [ADDR_WIDTH - 1:0] ff_raddr_next;
|
||||
wire [ADDR_WIDTH:0] tmp;
|
||||
wire [ADDR_PLUS_ONE:0] next_count;
|
||||
wire [ADDR_PLUS_ONE:0] count;
|
||||
wire [ADDR_PLUS_ONE:0] fbytes;
|
||||
genvar i;
|
||||
assign next_count = waddr - raddr_next;
|
||||
assign count = waddr - raddr;
|
||||
assign fbytes = 1 << (DEPTH + 5);
|
||||
always @(*) pae_thresh = rmode[1] ? upae : (rmode[0] ? upae << 1 : upae << 2);
|
||||
assign ren_out = (empty ? 1'b1 : ren_in);
|
||||
always @(*)
|
||||
case (rmode)
|
||||
2'h0: gmode = 2'h0;
|
||||
2'h1: gmode = (wmode == 2'h0 ? 2'h0 : 2'h1);
|
||||
2'h2: gmode = (wmode == 2'h2 ? 2'h2 : wmode);
|
||||
2'h3: gmode = 2'h3;
|
||||
endcase
|
||||
always @(*) begin
|
||||
e1 = 1'b0;
|
||||
e2 = 1'b0;
|
||||
o1 = 1'b0;
|
||||
o2 = 1'b0;
|
||||
q1 = next_count < {1'b0, pae_thresh};
|
||||
q2 = count < {1'b0, pae_thresh};
|
||||
case (rmode)
|
||||
2'h0: begin
|
||||
e1 = raddr_next[ADDR_WIDTH:2] == waddr_next[ADDR_WIDTH:2];
|
||||
e2 = raddr[ADDR_WIDTH:2] == waddr_next[ADDR_WIDTH:2];
|
||||
o1 = (raddr_next[ADDR_WIDTH:2] + 1) == waddr_next[ADDR_WIDTH:2];
|
||||
o2 = (raddr[ADDR_WIDTH:2] + 1) == waddr_next[ADDR_WIDTH:2];
|
||||
end
|
||||
2'h1: begin
|
||||
e1 = raddr_next[ADDR_WIDTH:1] == waddr_next[ADDR_WIDTH:1];
|
||||
e2 = raddr[ADDR_WIDTH:1] == waddr_next[ADDR_WIDTH:1];
|
||||
o1 = (raddr_next[ADDR_WIDTH:1] + 1) == waddr_next[ADDR_WIDTH:1];
|
||||
o2 = (raddr[ADDR_WIDTH:1] + 1) == waddr_next[ADDR_WIDTH:1];
|
||||
end
|
||||
2'h2: begin
|
||||
e1 = raddr_next[ADDR_WIDTH:0] == waddr_next[ADDR_WIDTH:0];
|
||||
e2 = raddr[ADDR_WIDTH:0] == waddr_next[ADDR_WIDTH:0];
|
||||
o1 = (raddr_next[ADDR_WIDTH:0] + 1) == waddr_next[ADDR_WIDTH:0];
|
||||
o2 = (raddr[ADDR_WIDTH:0] + 1) == waddr_next[11:0];
|
||||
end
|
||||
2'h3: begin
|
||||
e1 = 1'b0;
|
||||
e2 = 1'b0;
|
||||
o1 = 1'b0;
|
||||
o2 = 1'b0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
assign empty_next = (ren_in & !empty ? e1 : e2);
|
||||
assign epo_next = (ren_in & !empty ? o1 : o2);
|
||||
assign pae_next = (ren_in & !empty ? q1 : q2);
|
||||
always @(posedge rclk or negedge rst_n)
|
||||
if (~rst_n) begin
|
||||
empty <= 1'b1;
|
||||
pae <= 1'b1;
|
||||
epo <= 1'b0;
|
||||
end
|
||||
else begin
|
||||
empty <= empty_next;
|
||||
pae <= pae_next;
|
||||
epo <= epo_next;
|
||||
end
|
||||
assign gc8out_next = (raddr_next >> 1) ^ raddr_next;
|
||||
assign gc16out_next = (raddr_next >> 2) ^ (raddr_next >> 1);
|
||||
assign gc32out_next = (raddr_next >> 3) ^ (raddr_next >> 2);
|
||||
always @(*)
|
||||
if (ren_in)
|
||||
case (gmode)
|
||||
2'h2: gcout_next = gc8out_next;
|
||||
2'h1: gcout_next = {1'b0, gc16out_next};
|
||||
2'h0: gcout_next = {2'b00, gc32out_next};
|
||||
default: gcout_next = 'h0;
|
||||
endcase
|
||||
else
|
||||
gcout_next = 'h0;
|
||||
always @(posedge rclk or negedge rst_n)
|
||||
if (~rst_n)
|
||||
waddr <= 12'h000;
|
||||
else
|
||||
waddr <= waddr_next;
|
||||
always @(posedge rclk or negedge rst_n)
|
||||
if (~rst_n) begin
|
||||
underflow <= 1'b0;
|
||||
bwl_sel <= 2'h0;
|
||||
gcout_reg <= 12'h000;
|
||||
end
|
||||
else if (ren_in) begin
|
||||
underflow <= empty;
|
||||
if (!empty) begin
|
||||
bwl_sel <= raddr_next[1:0];
|
||||
gcout_reg <= gcout_next;
|
||||
end
|
||||
end
|
||||
generate
|
||||
for (i = 0; i < (ADDR_WIDTH + 1); i = i + 1) begin : genblk1
|
||||
assign tmp[i] = ^(gcin >> i);
|
||||
end
|
||||
endgenerate
|
||||
always @(*)
|
||||
case (gmode)
|
||||
2'h0: waddr_next = {tmp[ADDR_WIDTH - 2:0], 2'b00} & {{ADDR_WIDTH - 1 {1'b1}}, 2'b00};
|
||||
2'h1: waddr_next = {tmp[ADDR_WIDTH - 1:0], 1'b0} & {{ADDR_WIDTH {1'b1}}, 1'b0};
|
||||
2'h2: waddr_next = {tmp[ADDR_WIDTH:0]} & {ADDR_PLUS_ONE {1'b1}};
|
||||
default: waddr_next = {ADDR_PLUS_ONE {1'b0}};
|
||||
endcase
|
||||
assign ff_raddr_next = ff_raddr + (rmode == 2'h0 ? 'h4 : (rmode == 2'h1 ? 'h2 : 'h1));
|
||||
assign raddr_next = raddr + (rmode == 2'h0 ? 'h4 : (rmode == 2'h1 ? 'h2 : 'h1));
|
||||
always @(posedge rclk or negedge rst_n)
|
||||
if (~rst_n)
|
||||
ff_raddr <= 1'sb0;
|
||||
else if (empty & ~empty_next)
|
||||
ff_raddr <= raddr_next[ADDR_WIDTH - 1:0];
|
||||
else if ((ren_in & !empty) & ~empty_next)
|
||||
ff_raddr <= ff_raddr_next;
|
||||
always @(posedge rclk or negedge rst_n)
|
||||
if (~rst_n)
|
||||
raddr <= 12'h000;
|
||||
else if (ren_in & !empty)
|
||||
raddr <= raddr_next;
|
||||
always @(*)
|
||||
case (FIFO_WIDTH)
|
||||
3'h2: out_raddr = {ff_raddr[ADDR_WIDTH - 1:1], bwl_sel[0]};
|
||||
3'h4: out_raddr = {ff_raddr[ADDR_WIDTH - 1:2], bwl_sel};
|
||||
default: out_raddr = ff_raddr[ADDR_WIDTH - 1:0];
|
||||
endcase
|
||||
assign ren_o = ren_out;
|
||||
assign gcout = gcout_reg;
|
||||
assign popflags = {empty, epo, pae, underflow};
|
||||
endmodule
|
||||
`default_nettype none
|
|
@ -2,6 +2,7 @@
|
|||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2021 QuickLogic Corp.
|
||||
* Copyright 2020-2022 F4PGA Authors
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -30,6 +31,7 @@ struct SynthQuickLogicPass : public ScriptPass {
|
|||
|
||||
void help() override
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" synth_quicklogic [options]\n");
|
||||
log("This command runs synthesis for QuickLogic FPGAs\n");
|
||||
|
@ -42,6 +44,21 @@ struct SynthQuickLogicPass : public ScriptPass {
|
|||
log(" generate the synthesis netlist for the specified family.\n");
|
||||
log(" supported values:\n");
|
||||
log(" - pp3: PolarPro 3 \n");
|
||||
log(" - qlf_k6n10f: K6N10f\n");
|
||||
log("\n");
|
||||
log(" -nodsp\n");
|
||||
log(" do not use dsp_t1_* to implement multipliers and associated logic\n");
|
||||
log(" (qlf_k6n10f only).\n");
|
||||
log("\n");
|
||||
log(" -nocarry\n");
|
||||
log(" do not use adder_carry cells in output netlist.\n");
|
||||
log("\n");
|
||||
log(" -nobram\n");
|
||||
log(" do not use block RAM cells in output netlist.\n");
|
||||
log("\n");
|
||||
log(" -bramtypes\n");
|
||||
log(" Emit specialized BRAM cells for particular address and data width\n");
|
||||
log(" configurations.\n");
|
||||
log("\n");
|
||||
log(" -blif <file>\n");
|
||||
log(" write the design to the specified BLIF file. writing of an output file\n");
|
||||
|
@ -60,27 +77,51 @@ struct SynthQuickLogicPass : public ScriptPass {
|
|||
log("\n");
|
||||
}
|
||||
|
||||
string top_opt, blif_file, family, currmodule, verilog_file;
|
||||
bool abc9;
|
||||
string top_opt, blif_file, edif_file, family, currmodule, verilog_file, lib_path;
|
||||
bool abc9, inferAdder, nobram, bramTypes, dsp;
|
||||
|
||||
void clear_flags() override
|
||||
{
|
||||
top_opt = "-auto-top";
|
||||
blif_file = "";
|
||||
edif_file = "";
|
||||
verilog_file = "";
|
||||
currmodule = "";
|
||||
family = "pp3";
|
||||
abc9 = true;
|
||||
inferAdder = true;
|
||||
nobram = false;
|
||||
bramTypes = false;
|
||||
lib_path = "+/quicklogic/";
|
||||
dsp = true;
|
||||
}
|
||||
|
||||
void set_scratchpad_defaults(RTLIL::Design *design) {
|
||||
lib_path = design->scratchpad_get_string("ql.lib_path", lib_path);
|
||||
if (lib_path.back() != '/')
|
||||
lib_path += "/";
|
||||
inferAdder = !design->scratchpad_get_bool("ql.nocarry", false);
|
||||
nobram = design->scratchpad_get_bool("ql.nobram", false);
|
||||
bramTypes = design->scratchpad_get_bool("ql.bramtypes", false);
|
||||
}
|
||||
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
string run_from, run_to;
|
||||
clear_flags();
|
||||
set_scratchpad_defaults(design);
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
{
|
||||
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] == "-top" && argidx+1 < args.size()) {
|
||||
top_opt = "-top " + args[++argidx];
|
||||
continue;
|
||||
|
@ -101,6 +142,22 @@ struct SynthQuickLogicPass : public ScriptPass {
|
|||
abc9 = false;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nocarry" || args[argidx] == "-no_adder") {
|
||||
inferAdder = false;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nobram" || args[argidx] == "-no_bram") {
|
||||
nobram = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-bramtypes" || args[argidx] == "-bram_types") {
|
||||
bramTypes = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nodsp" || args[argidx] == "-no_dsp") {
|
||||
dsp = false;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
@ -108,7 +165,7 @@ struct SynthQuickLogicPass : public ScriptPass {
|
|||
if (!design->full_selection())
|
||||
log_cmd_error("This command only operates on fully selected designs!\n");
|
||||
|
||||
if (family != "pp3")
|
||||
if (family != "pp3" && family != "qlf_k6n10f")
|
||||
log_cmd_error("Invalid family specified: '%s'\n", family.c_str());
|
||||
|
||||
if (abc9 && design->scratchpad_get_int("abc9.D", 0) == 0) {
|
||||
|
@ -126,16 +183,29 @@ struct SynthQuickLogicPass : public ScriptPass {
|
|||
|
||||
void script() override
|
||||
{
|
||||
if (help_mode) {
|
||||
family = "<family>";
|
||||
}
|
||||
|
||||
if (check_label("begin")) {
|
||||
run(stringf("read_verilog -lib -specify +/quicklogic/cells_sim.v +/quicklogic/%s_cells_sim.v", family.c_str()));
|
||||
run("read_verilog -lib -specify +/quicklogic/lut_sim.v");
|
||||
std::string read_simlibs = stringf("read_verilog -lib -specify %scommon/cells_sim.v %s%s/cells_sim.v", lib_path.c_str(), lib_path.c_str(), family.c_str());
|
||||
if (family == "qlf_k6n10f") {
|
||||
read_simlibs += stringf(" %sqlf_k6n10f/brams_sim.v", lib_path.c_str());
|
||||
if (bramTypes)
|
||||
read_simlibs += stringf(" %sqlf_k6n10f/bram_types_sim.v", lib_path.c_str());
|
||||
if (dsp)
|
||||
read_simlibs += stringf(" %sqlf_k6n10f/dsp_sim.v", lib_path.c_str());
|
||||
}
|
||||
run(read_simlibs);
|
||||
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
|
||||
}
|
||||
|
||||
if (check_label("coarse")) {
|
||||
if (check_label("prepare")) {
|
||||
run("proc");
|
||||
run("flatten");
|
||||
run("tribuf -logic");
|
||||
if (help_mode || family == "pp3") {
|
||||
run("tribuf -logic", " (for pp3)");
|
||||
}
|
||||
run("deminout");
|
||||
run("opt_expr");
|
||||
run("opt_clean");
|
||||
|
@ -147,6 +217,24 @@ struct SynthQuickLogicPass : public ScriptPass {
|
|||
run("peepopt");
|
||||
run("opt_clean");
|
||||
run("share");
|
||||
}
|
||||
|
||||
if (check_label("map_dsp", "(for qlf_k6n10f, skip if -nodsp)")
|
||||
&& ((dsp && family == "qlf_k6n10f") || help_mode)) {
|
||||
run("wreduce t:$mul");
|
||||
run("ql_dsp_macc");
|
||||
|
||||
run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=20 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=11 -D DSP_B_MINWIDTH=10 -D DSP_NAME=$__QL_MUL20X18");
|
||||
run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=10 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=$__QL_MUL10X9");
|
||||
run("chtype -set $mul t:$__soft_mul");
|
||||
|
||||
run("techmap -map " + lib_path + family + "/dsp_map.v -D USE_DSP_CFG_PARAMS=0");
|
||||
run("ql_dsp_simd");
|
||||
run("techmap -map " + lib_path + family + "/dsp_final_map.v");
|
||||
run("ql_dsp_io_regs");
|
||||
}
|
||||
|
||||
if (check_label("coarse")) {
|
||||
run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4");
|
||||
run("opt_expr");
|
||||
run("opt_clean");
|
||||
|
@ -157,6 +245,17 @@ struct SynthQuickLogicPass : public ScriptPass {
|
|||
run("opt_clean");
|
||||
}
|
||||
|
||||
if (check_label("map_bram", "(for qlf_k6n10f, skip if -no_bram)")
|
||||
&& (family == "qlf_k6n10f" || help_mode)) {
|
||||
run("memory_libmap -lib " + lib_path + family + "/libmap_brams.txt");
|
||||
run("ql_bram_merge");
|
||||
run("techmap -map " + lib_path + family + "/libmap_brams_map.v");
|
||||
run("techmap -autoproc -map " + lib_path + family + "/brams_map.v");
|
||||
|
||||
if (bramTypes || help_mode)
|
||||
run("ql_bram_types", "(if -bramtypes)");
|
||||
}
|
||||
|
||||
if (check_label("map_ffram")) {
|
||||
run("opt -fast -mux_undef -undriven -fine");
|
||||
run("memory_map -iattr -attr !ram_block -attr !rom_block -attr logic_block "
|
||||
|
@ -166,36 +265,67 @@ struct SynthQuickLogicPass : public ScriptPass {
|
|||
}
|
||||
|
||||
if (check_label("map_gates")) {
|
||||
run("techmap");
|
||||
if (inferAdder && family == "qlf_k6n10f") {
|
||||
run("techmap -map +/techmap.v -map " + lib_path + family + "/arith_map.v", "(unless -no_adder)");
|
||||
} else {
|
||||
run("techmap");
|
||||
}
|
||||
run("opt -fast");
|
||||
run("muxcover -mux8 -mux4");
|
||||
if (help_mode || family == "pp3") {
|
||||
run("muxcover -mux8 -mux4", "(for pp3)");
|
||||
}
|
||||
}
|
||||
|
||||
if (check_label("map_ffs")) {
|
||||
run("opt_expr");
|
||||
run("dfflegalize -cell $_DFFSRE_PPPP_ 0 -cell $_DLATCH_?_ x");
|
||||
|
||||
run(stringf("techmap -map +/quicklogic/%s_cells_map.v -map +/quicklogic/%s_ffs_map.v", family.c_str(), family.c_str()));
|
||||
|
||||
run("opt_expr -mux_undef");
|
||||
if (help_mode) {
|
||||
run("shregmap -minlen <min> -maxlen <max>", "(for qlf_k6n10f)");
|
||||
run("dfflegalize -cell <supported FF types>");
|
||||
run("techmap -map " + lib_path + family + "/cells_map.v", "(for pp3)");
|
||||
run("techmap -map " + lib_path + family + "/ffs_map.v", "(for ql_k6n10f)");
|
||||
}
|
||||
if (family == "pp3") {
|
||||
run("dfflegalize -cell $_DFFSRE_PPPP_ 0 -cell $_DLATCH_?_ x");
|
||||
run("techmap -map " + lib_path + family + "/cells_map.v -map " + lib_path + family + "/ffs_map.v");
|
||||
run("opt_expr -mux_undef");
|
||||
} else if (family == "qlf_k6n10f") {
|
||||
run("shregmap -minlen 8 -maxlen 20");
|
||||
// FIXME: Apparently dfflegalize leaves around $_DLATCH_[NP]_ even if
|
||||
// not in the allowed set. As a workaround we put them in the allowed
|
||||
// set explicitly and map them later to $_DLATCHSR_[NP]NN_.
|
||||
run("dfflegalize -cell $_DFFSRE_?NNP_ 0 -cell $_DLATCHSR_?NN_ 0 -cell $_DLATCH_?_ 0" " -cell $_SDFFE_?N?P_ 0");
|
||||
run("techmap -map " + lib_path + family + "/ffs_map.v");
|
||||
}
|
||||
run("opt");
|
||||
}
|
||||
|
||||
if (check_label("map_luts")) {
|
||||
run(stringf("techmap -map +/quicklogic/%s_latches_map.v", family.c_str()));
|
||||
if (check_label("map_luts", "(for pp3)") && (help_mode || family == "pp3")) {
|
||||
run("techmap -map " + lib_path + family + "/latches_map.v");
|
||||
if (abc9) {
|
||||
run("read_verilog -lib -specify -icells +/quicklogic/abc9_model.v");
|
||||
run("techmap -map +/quicklogic/abc9_map.v");
|
||||
run("read_verilog -lib -specify -icells " + lib_path + family + "/abc9_model.v");
|
||||
run("techmap -map " + lib_path + family + "/abc9_map.v");
|
||||
run("abc9 -maxlut 4 -dff");
|
||||
run("techmap -map +/quicklogic/abc9_unmap.v");
|
||||
run("techmap -map " + lib_path + family + "/abc9_unmap.v");
|
||||
} else {
|
||||
run("abc -luts 1,2,2,4 -dress");
|
||||
}
|
||||
run("clean");
|
||||
}
|
||||
|
||||
if (check_label("map_cells")) {
|
||||
run(stringf("techmap -map +/quicklogic/%s_lut_map.v", family.c_str()));
|
||||
if (check_label("map_luts", "(for qlf_k6n10f)") && (help_mode || family == "qlf_k6n10f")) {
|
||||
if (abc9) {
|
||||
run("abc9 -maxlut 6");
|
||||
} else {
|
||||
run("abc -lut 6 -dress");
|
||||
}
|
||||
run("clean");
|
||||
run("opt_lut");
|
||||
}
|
||||
|
||||
if (check_label("map_cells", "(for pp3)") && (help_mode || family == "pp3")) {
|
||||
run("techmap -map " + lib_path + family + "/lut_map.v");
|
||||
run("clean");
|
||||
run("opt_lut");
|
||||
}
|
||||
|
||||
if (check_label("check")) {
|
||||
|
@ -205,26 +335,30 @@ struct SynthQuickLogicPass : public ScriptPass {
|
|||
run("check -noinit");
|
||||
}
|
||||
|
||||
if (check_label("iomap")) {
|
||||
if (check_label("iomap", "(for pp3)") && (family == "pp3" || help_mode)) {
|
||||
run("clkbufmap -inpad ckpad Q:P");
|
||||
run("iopadmap -bits -outpad outpad A:P -inpad inpad Q:P -tinoutpad bipad EN:Q:A:P A:top");
|
||||
}
|
||||
|
||||
if (check_label("finalize")) {
|
||||
run("setundef -zero -params -undriven");
|
||||
run("hilomap -hicell logic_1 A -locell logic_0 A -singleton A:top");
|
||||
if (help_mode || family == "pp3") {
|
||||
run("setundef -zero -params -undriven", "(for pp3)");
|
||||
}
|
||||
if (family == "pp3" || !edif_file.empty()) {
|
||||
run("hilomap -hicell logic_1 A -locell logic_0 A -singleton A:top", "(for pp3 or if -edif)");
|
||||
}
|
||||
run("opt_clean -purge");
|
||||
run("check");
|
||||
run("blackbox =A:whitebox");
|
||||
}
|
||||
|
||||
if (check_label("blif")) {
|
||||
if (check_label("blif", "(if -blif)")) {
|
||||
if (!blif_file.empty() || help_mode) {
|
||||
run(stringf("write_blif -attr -param %s %s", top_opt.c_str(), blif_file.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
if (check_label("verilog")) {
|
||||
if (check_label("verilog", "(if -verilog)")) {
|
||||
if (!verilog_file.empty() || help_mode) {
|
||||
run(stringf("write_verilog -noattr -nohex %s", help_mode ? "<file-name>" : verilog_file.c_str()));
|
||||
}
|
||||
|
|
|
@ -45,6 +45,113 @@ module sync_ram_sdp #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10)
|
|||
endmodule // sync_ram_sdp
|
||||
|
||||
|
||||
module sync_ram_sdp_wwr #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10, SHIFT_VAL=1) // wd=16, wa=9
|
||||
(
|
||||
input wire clk_w, clk_r, write_enable,
|
||||
input wire [WORD-1:0] data_in,
|
||||
input wire [ADDRESS_WIDTH_W-1:0] address_in_w,
|
||||
input wire [ADDRESS_WIDTH-1:0] address_in_r,
|
||||
output wire [DATA_WIDTH-1:0] data_out
|
||||
);
|
||||
|
||||
localparam ADDRESS_WIDTH_W = ADDRESS_WIDTH-SHIFT_VAL;
|
||||
localparam BYTE = DATA_WIDTH;
|
||||
localparam WORD = DATA_WIDTH<<SHIFT_VAL;
|
||||
localparam DEPTH = 2**ADDRESS_WIDTH_W;
|
||||
localparam SUB_DEPTH = 2**SHIFT_VAL;
|
||||
|
||||
reg [BYTE-1:0] data_out_r;
|
||||
reg [BYTE-1:0] memory [0:DEPTH-1];
|
||||
|
||||
integer i;
|
||||
always @(posedge clk_w) begin
|
||||
for (i=0; i<SUB_DEPTH; i=i+1)
|
||||
if (write_enable)
|
||||
memory[{address_in_w, i}] <= data_in[i*BYTE+:BYTE];
|
||||
end
|
||||
|
||||
always @(posedge clk_r) begin
|
||||
data_out_r <= memory[address_in_r];
|
||||
end
|
||||
|
||||
assign data_out = data_out_r;
|
||||
|
||||
endmodule // sync_ram_sdp_wwr
|
||||
|
||||
|
||||
module sync_ram_sdp_wrr #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10, SHIFT_VAL=1) // rd=16, ra=9
|
||||
(
|
||||
input wire clk_w, clk_r, write_enable,
|
||||
input wire [DATA_WIDTH-1:0] data_in,
|
||||
input wire [ADDRESS_WIDTH-1:0] address_in_w,
|
||||
input wire [ADDRESS_WIDTH_R-1:0] address_in_r,
|
||||
output wire [WORD-1:0] data_out
|
||||
);
|
||||
localparam ADDRESS_WIDTH_R = ADDRESS_WIDTH-SHIFT_VAL;
|
||||
localparam BYTE = DATA_WIDTH;
|
||||
localparam WORD = BYTE<<SHIFT_VAL;
|
||||
localparam DEPTH = 2**ADDRESS_WIDTH;
|
||||
localparam SUB_DEPTH = 2**SHIFT_VAL;
|
||||
|
||||
reg [WORD-1:0] data_out_r;
|
||||
reg [BYTE-1:0] memory [0:DEPTH-1];
|
||||
|
||||
always @(posedge clk_w) begin
|
||||
if (write_enable)
|
||||
memory[address_in_w] <= data_in;
|
||||
end
|
||||
|
||||
integer i;
|
||||
always @(posedge clk_r) begin
|
||||
for (i=0; i<SUB_DEPTH; i=i+1)
|
||||
data_out_r[i*BYTE+:BYTE] <= memory[{address_in_r, i}];
|
||||
end
|
||||
|
||||
assign data_out = data_out_r;
|
||||
|
||||
endmodule // sync_ram_sdp_wrr
|
||||
|
||||
|
||||
module double_sync_ram_sdp #(parameter DATA_WIDTH_A=8, ADDRESS_WIDTH_A=10, DATA_WIDTH_B=8, ADDRESS_WIDTH_B=10)
|
||||
(
|
||||
input wire write_enable_a, clk_a,
|
||||
input wire [DATA_WIDTH_A-1:0] data_in_a,
|
||||
input wire [ADDRESS_WIDTH_A-1:0] address_in_r_a, address_in_w_a,
|
||||
output wire [DATA_WIDTH_A-1:0] data_out_a,
|
||||
|
||||
input wire write_enable_b, clk_b,
|
||||
input wire [DATA_WIDTH_B-1:0] data_in_b,
|
||||
input wire [ADDRESS_WIDTH_B-1:0] address_in_r_b, address_in_w_b,
|
||||
output wire [DATA_WIDTH_B-1:0] data_out_b
|
||||
);
|
||||
|
||||
sync_ram_sdp #(
|
||||
.DATA_WIDTH(DATA_WIDTH_A),
|
||||
.ADDRESS_WIDTH(ADDRESS_WIDTH_A)
|
||||
) a_ram (
|
||||
.write_enable(write_enable_a),
|
||||
.clk(clk_a),
|
||||
.data_in(data_in_a),
|
||||
.address_in_r(address_in_r_a),
|
||||
.address_in_w(address_in_w_a),
|
||||
.data_out(data_out_a)
|
||||
);
|
||||
|
||||
sync_ram_sdp #(
|
||||
.DATA_WIDTH(DATA_WIDTH_B),
|
||||
.ADDRESS_WIDTH(ADDRESS_WIDTH_B)
|
||||
) b_ram (
|
||||
.write_enable(write_enable_b),
|
||||
.clk(clk_b),
|
||||
.data_in(data_in_b),
|
||||
.address_in_r(address_in_r_b),
|
||||
.address_in_w(address_in_w_b),
|
||||
.data_out(data_out_b)
|
||||
);
|
||||
|
||||
endmodule // double_sync_ram_sdp
|
||||
|
||||
|
||||
module sync_ram_tdp #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10)
|
||||
(input wire clk_a, clk_b,
|
||||
input wire write_enable_a, write_enable_b,
|
||||
|
@ -74,3 +181,68 @@ module sync_ram_tdp #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10)
|
|||
|
||||
endmodule // sync_ram_tdp
|
||||
|
||||
module double_sync_ram_tdp #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10)
|
||||
(
|
||||
input wire clk_a_0,
|
||||
input wire write_enable_a_0, read_enable_a_0,
|
||||
input wire [DATA_WIDTH-1:0] write_data_a_0,
|
||||
input wire [ADDRESS_WIDTH-1:0] addr_a_0,
|
||||
output wire [DATA_WIDTH-1:0] read_data_a_0,
|
||||
|
||||
input wire clk_a_1,
|
||||
input wire write_enable_a_1, read_enable_a_1,
|
||||
input wire [DATA_WIDTH-1:0] write_data_a_1,
|
||||
input wire [ADDRESS_WIDTH-1:0] addr_a_1,
|
||||
output wire [DATA_WIDTH-1:0] read_data_a_1,
|
||||
|
||||
input wire clk_b_0,
|
||||
input wire write_enable_b_0, read_enable_b_0,
|
||||
input wire [DATA_WIDTH-1:0] write_data_b_0,
|
||||
input wire [ADDRESS_WIDTH-1:0] addr_b_0,
|
||||
output wire [DATA_WIDTH-1:0] read_data_b_0,
|
||||
|
||||
input wire clk_b_1,
|
||||
input wire write_enable_b_1, read_enable_b_1,
|
||||
input wire [DATA_WIDTH-1:0] write_data_b_1,
|
||||
input wire [ADDRESS_WIDTH-1:0] addr_b_1,
|
||||
output wire [DATA_WIDTH-1:0] read_data_b_1
|
||||
);
|
||||
|
||||
sync_ram_tdp #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.ADDRESS_WIDTH(ADDRESS_WIDTH)
|
||||
) ram_0 (
|
||||
.clk_a(clk_a_0),
|
||||
.clk_b(clk_b_0),
|
||||
.write_enable_a(write_enable_a_0),
|
||||
.write_enable_b(write_enable_b_0),
|
||||
.read_enable_a(read_enable_a_0),
|
||||
.read_enable_b(read_enable_b_0),
|
||||
.write_data_a(write_data_a_0),
|
||||
.write_data_b(write_data_b_0),
|
||||
.addr_a(addr_a_0),
|
||||
.addr_b(addr_b_0),
|
||||
.read_data_a(read_data_a_0),
|
||||
.read_data_b(read_data_b_0)
|
||||
);
|
||||
|
||||
sync_ram_tdp #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.ADDRESS_WIDTH(ADDRESS_WIDTH)
|
||||
) ram_1 (
|
||||
.clk_a(clk_a_1),
|
||||
.clk_b(clk_b_1),
|
||||
.write_enable_a(write_enable_a_1),
|
||||
.write_enable_b(write_enable_b_1),
|
||||
.read_enable_a(read_enable_a_1),
|
||||
.read_enable_b(read_enable_b_1),
|
||||
.write_data_a(write_data_a_1),
|
||||
.write_data_b(write_data_b_1),
|
||||
.addr_a(addr_a_1),
|
||||
.addr_b(addr_b_1),
|
||||
.read_data_a(read_data_a_1),
|
||||
.read_data_b(read_data_b_1)
|
||||
);
|
||||
|
||||
endmodule // double_sync_ram_tdp
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
read_verilog ../common/add_sub.v
|
||||
read_verilog ../../common/add_sub.v
|
||||
hierarchy -top top
|
||||
equiv_opt -assert -map +/quicklogic/lut_sim.v -map +/quicklogic/pp3_cells_sim.v synth_quicklogic -family pp3 # equivalency check
|
||||
equiv_opt -assert -map +/quicklogic/pp3/cells_sim.v synth_quicklogic -family pp3 # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd top # Constrain all select calls below inside the top module
|
||||
select -assert-count 2 t:LUT2
|
|
@ -1,9 +1,9 @@
|
|||
read_verilog ../common/adffs.v
|
||||
read_verilog ../../common/adffs.v
|
||||
design -save read
|
||||
|
||||
hierarchy -top adff
|
||||
proc
|
||||
equiv_opt -async2sync -assert -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v synth_quicklogic # equivalency check
|
||||
equiv_opt -async2sync -assert -map +/quicklogic/pp3/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd adff # Constrain all select calls below inside the top module
|
||||
select -assert-count 1 t:dffepc
|
||||
|
@ -19,7 +19,7 @@ select -assert-none t:dffepc t:logic_0 t:logic_1 t:inpad t:outpad t:ckpad %% t:*
|
|||
design -load read
|
||||
hierarchy -top adffn
|
||||
proc
|
||||
equiv_opt -async2sync -assert -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v -map +/quicklogic/lut_sim.v synth_quicklogic # equivalency check
|
||||
equiv_opt -async2sync -assert -map +/quicklogic/pp3/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd adffn # Constrain all select calls below inside the top module
|
||||
select -assert-count 1 t:LUT1
|
||||
|
@ -36,7 +36,7 @@ select -assert-none t:LUT1 t:dffepc t:logic_0 t:logic_1 t:inpad t:outpad t:ckpad
|
|||
design -load read
|
||||
hierarchy -top dffs
|
||||
proc
|
||||
equiv_opt -async2sync -assert -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v -map +/quicklogic/lut_sim.v synth_quicklogic # equivalency check
|
||||
equiv_opt -async2sync -assert -map +/quicklogic/pp3/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd dffs # Constrain all select calls below inside the top module
|
||||
select -assert-count 1 t:LUT2
|
||||
|
@ -53,7 +53,7 @@ select -assert-none t:LUT2 t:dffepc t:logic_0 t:logic_1 t:inpad t:outpad t:ckpad
|
|||
design -load read
|
||||
hierarchy -top ndffnr
|
||||
proc
|
||||
equiv_opt -async2sync -assert -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v -map +/quicklogic/lut_sim.v synth_quicklogic # equivalency check
|
||||
equiv_opt -async2sync -assert -map +/quicklogic/pp3/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd ndffnr # Constrain all select calls below inside the top module
|
||||
select -assert-count 1 t:LUT1
|
|
@ -1,8 +1,8 @@
|
|||
read_verilog ../common/counter.v
|
||||
read_verilog ../../common/counter.v
|
||||
hierarchy -top top
|
||||
proc
|
||||
flatten
|
||||
equiv_opt -assert -multiclock -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v -map +/quicklogic/lut_sim.v synth_quicklogic # equivalency check
|
||||
equiv_opt -assert -multiclock -map +/quicklogic/pp3/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd top # Constrain all select calls below inside the top module
|
||||
select -assert-count 1 t:LUT1
|
|
@ -1,11 +1,11 @@
|
|||
read_verilog ../common/dffs.v
|
||||
read_verilog ../../common/dffs.v
|
||||
rename dff my_dff # Work around conflicting module names between test and vendor cells
|
||||
rename dffe my_dffe
|
||||
design -save read
|
||||
|
||||
hierarchy -top my_dff
|
||||
proc
|
||||
equiv_opt -async2sync -assert -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v synth_quicklogic # equivalency check
|
||||
equiv_opt -async2sync -assert -map +/quicklogic/pp3/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd my_dff # Constrain all select calls below inside the top module
|
||||
select -assert-count 1 t:ckpad
|
||||
|
@ -20,7 +20,7 @@ select -assert-none t:ckpad t:dffepc t:inpad t:logic_0 t:logic_1 t:outpad %% t:*
|
|||
design -load read
|
||||
hierarchy -top my_dffe
|
||||
proc
|
||||
equiv_opt -async2sync -assert -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v synth_quicklogic # equivalency check
|
||||
equiv_opt -async2sync -assert -map +/quicklogic/pp3/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd my_dffe # Constrain all select calls below inside the top module
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
read_verilog ../common/fsm.v
|
||||
read_verilog ../../common/fsm.v
|
||||
hierarchy -top fsm
|
||||
proc
|
||||
flatten
|
||||
|
||||
equiv_opt -run :prove -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v -map +/quicklogic/lut_sim.v synth_quicklogic
|
||||
equiv_opt -run :prove -map +/quicklogic/pp3/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic
|
||||
async2sync
|
||||
miter -equiv -make_assert -flatten gold gate miter
|
||||
sat -verify -prove-asserts -show-public -set-at 1 in_reset 1 -seq 20 -prove-skip 1 miter
|
|
@ -1,4 +1,4 @@
|
|||
read_verilog ../common/latches.v
|
||||
read_verilog ../../common/latches.v
|
||||
design -save read
|
||||
|
||||
hierarchy -top latchp
|
|
@ -1,7 +1,7 @@
|
|||
read_verilog ../common/logic.v
|
||||
read_verilog ../../common/logic.v
|
||||
hierarchy -top top
|
||||
proc
|
||||
equiv_opt -assert -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v -map +/quicklogic/lut_sim.v synth_quicklogic # equivalency check
|
||||
equiv_opt -assert -map +/quicklogic/pp3/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd top # Constrain all select calls below inside the top module
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
read_verilog ../common/mux.v
|
||||
read_verilog ../../common/mux.v
|
||||
design -save read
|
||||
|
||||
hierarchy -top mux2
|
||||
proc
|
||||
equiv_opt -assert -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v -map +/quicklogic/lut_sim.v synth_quicklogic # equivalency check
|
||||
equiv_opt -assert -map +/quicklogic/pp3/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd mux2 # Constrain all select calls below inside the top module
|
||||
select -assert-count 1 t:LUT3
|
||||
|
@ -15,7 +15,7 @@ select -assert-none t:LUT3 t:inpad t:outpad %% t:* %D
|
|||
design -load read
|
||||
hierarchy -top mux4
|
||||
proc
|
||||
equiv_opt -assert -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v -map +/quicklogic/lut_sim.v synth_quicklogic # equivalency check
|
||||
equiv_opt -assert -map +/quicklogic/pp3/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic # equivalency check
|
||||
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:LUT3
|
||||
|
@ -27,7 +27,7 @@ select -assert-none t:LUT3 t:inpad t:outpad %% t:* %D
|
|||
design -load read
|
||||
hierarchy -top mux8
|
||||
proc
|
||||
equiv_opt -assert -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v -map +/quicklogic/lut_sim.v synth_quicklogic # equivalency check
|
||||
equiv_opt -assert -map +/quicklogic/pp3/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd mux8 # Constrain all select calls below inside the top module
|
||||
select -assert-count 1 t:LUT1
|
||||
|
@ -41,7 +41,7 @@ select -assert-none t:LUT1 t:LUT3 t:mux4x0 t:inpad t:outpad %% t:* %D
|
|||
design -load read
|
||||
hierarchy -top mux16
|
||||
proc
|
||||
equiv_opt -assert -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v -map +/quicklogic/lut_sim.v synth_quicklogic # equivalency check
|
||||
equiv_opt -assert -map +/quicklogic/pp3/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd mux16 # Constrain all select calls below inside the top module
|
||||
select -assert-count 1 t:LUT3
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../../gen-tests-makefile.sh
|
||||
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.'"
|
|
@ -1,10 +1,10 @@
|
|||
read_verilog ../common/tribuf.v
|
||||
read_verilog ../../common/tribuf.v
|
||||
hierarchy -top tristate
|
||||
proc
|
||||
tribuf
|
||||
flatten
|
||||
synth
|
||||
equiv_opt -assert -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v -map +/simcells.v synth_quicklogic # equivalency check
|
||||
equiv_opt -assert -map +/quicklogic/pp3/cells_sim.v -map +/quicklogic/common/cells_sim.v -map +/simcells.v synth_quicklogic # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd tristate # Constrain all select calls below inside the top module
|
||||
select -assert-count 2 t:inpad
|
|
@ -0,0 +1 @@
|
|||
t_*.ys
|
|
@ -0,0 +1,8 @@
|
|||
read_verilog ../../common/add_sub.v
|
||||
hierarchy -top top
|
||||
equiv_opt -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v synth_quicklogic -family qlf_k6n10f # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd top # Constrain all select calls below inside the top module
|
||||
select -assert-count 9 t:$lut # OOT flow has 8
|
||||
select -assert-count 8 t:adder_carry
|
||||
select -assert-none t:$lut t:adder_carry %% t:* %D
|
|
@ -0,0 +1,48 @@
|
|||
read_verilog ../../common/adffs.v
|
||||
design -save read
|
||||
|
||||
hierarchy -top adff
|
||||
proc
|
||||
equiv_opt -async2sync -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd adff # Constrain all select calls below inside the top module
|
||||
select -assert-count 1 t:$lut r:WIDTH=1 %i
|
||||
select -assert-none r:WIDTH>1
|
||||
select -assert-count 1 t:dffsre
|
||||
|
||||
select -assert-none t:$lut t:dffsre %% t:* %D
|
||||
|
||||
|
||||
design -load read
|
||||
hierarchy -top adffn
|
||||
proc
|
||||
equiv_opt -async2sync -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd adffn # Constrain all select calls below inside the top module
|
||||
select -assert-count 1 t:dffsre
|
||||
|
||||
select -assert-none t:dffsre %% t:* %D
|
||||
|
||||
|
||||
design -load read
|
||||
hierarchy -top dffs
|
||||
proc
|
||||
equiv_opt -async2sync -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd dffs # Constrain all select calls below inside the top module
|
||||
select -assert-count 1 t:$lut r:WIDTH=1 %i
|
||||
select -assert-none r:WIDTH>1
|
||||
select -assert-count 1 t:sdffsre
|
||||
|
||||
select -assert-none t:$lut t:sdffsre %% t:* %D
|
||||
|
||||
|
||||
design -load read
|
||||
hierarchy -top ndffnr
|
||||
proc
|
||||
equiv_opt -async2sync -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd ndffnr # Constrain all select calls below inside the top module
|
||||
select -assert-count 1 t:sdffnsre
|
||||
|
||||
select -assert-none t:sdffnsre %% t:* %D
|
|
@ -0,0 +1,12 @@
|
|||
read_verilog ../../common/counter.v
|
||||
hierarchy -top top
|
||||
proc
|
||||
flatten
|
||||
equiv_opt -assert -multiclock -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd top # Constrain all select calls below inside the top module
|
||||
select -assert-count 4 t:$lut
|
||||
select -assert-count 8 t:adder_carry
|
||||
select -assert-count 8 t:dffsre
|
||||
|
||||
select -assert-none t:$lut t:adder_carry t:dffsre %% t:* %D
|
|
@ -0,0 +1,21 @@
|
|||
read_verilog ../../common/dffs.v
|
||||
rename dff my_dff # Work around conflicting module names between test and vendor cells
|
||||
rename dffe my_dffe
|
||||
design -save read
|
||||
|
||||
hierarchy -top my_dff
|
||||
proc
|
||||
equiv_opt -async2sync -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd my_dff # Constrain all select calls below inside the top module
|
||||
select -assert-count 1 t:sdffsre
|
||||
select -assert-none t:sdffsre %% t:* %D
|
||||
|
||||
design -load read
|
||||
hierarchy -top my_dffe
|
||||
proc
|
||||
equiv_opt -async2sync -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd my_dffe # Constrain all select calls below inside the top module
|
||||
select -assert-count 1 t:sdffsre
|
||||
select -assert-none t:sdffsre %% t:* %D
|
|
@ -0,0 +1,120 @@
|
|||
read_verilog <<EOF
|
||||
module top(a, b, y, batch, clk);
|
||||
parameter [31:0] OPER_WIDTH=8;
|
||||
parameter [31:0] ACC_WIDTH=8;
|
||||
input wire batch;
|
||||
input wire clk;
|
||||
input wire [OPER_WIDTH-1:0] a;
|
||||
input wire [OPER_WIDTH-1:0] b;
|
||||
output reg [ACC_WIDTH-1:0] y;
|
||||
wire [ACC_WIDTH-1:0] ab = a * b;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (batch)
|
||||
y <= ab;
|
||||
else
|
||||
y <= ab + y;
|
||||
end
|
||||
endmodule
|
||||
EOF
|
||||
|
||||
design -save ast
|
||||
proc
|
||||
wreduce
|
||||
#equiv_opt -async2sync -map +/quicklogic/qlf_k6n10f/dsp_sim.v synth_quicklogic -family qlf_k6n10f
|
||||
#design -load postopt
|
||||
synth_quicklogic -family qlf_k6n10f
|
||||
cd top
|
||||
select -assert-count 1 t:QL_DSP2_MULTACC
|
||||
select -assert-none t:QL_DSP2_MULTACC %n t:* %i
|
||||
|
||||
design -load ast
|
||||
chparam -set OPER_WIDTH 18
|
||||
chparam -set ACC_WIDTH 16
|
||||
proc
|
||||
wreduce
|
||||
synth_quicklogic -family qlf_k6n10f
|
||||
cd top
|
||||
select -assert-count 1 t:QL_DSP2_MULTACC
|
||||
select -assert-none t:QL_DSP2_MULTACC %n t:* %i
|
||||
|
||||
design -load ast
|
||||
chparam -set OPER_WIDTH 19 # <-- too wide, shouldn't map to multacc
|
||||
chparam -set ACC_WIDTH 16
|
||||
proc
|
||||
wreduce
|
||||
synth_quicklogic -family qlf_k6n10f
|
||||
cd top
|
||||
select -assert-none t:QL_DSP2_MULTACC
|
||||
select -assert-count 1 t:QL_DSP2_MULT
|
||||
|
||||
|
||||
design -load ast
|
||||
chparam -set OPER_WIDTH 16
|
||||
chparam -set ACC_WIDTH 32
|
||||
proc
|
||||
|
||||
synth_quicklogic -family qlf_k6n10f
|
||||
|
||||
read_verilog -sv <<EOF
|
||||
module testbench(clk);
|
||||
localparam OPER_WIDTH=16;
|
||||
localparam ACC_WIDTH=32;
|
||||
localparam VECTORLEN=16;
|
||||
parameter PRIME1 = 237481091;
|
||||
parameter PRIME2 = 1752239;
|
||||
reg [OPER_WIDTH-1:0] a_vector [VECTORLEN-1:0];
|
||||
reg [OPER_WIDTH-1:0] b_vector [VECTORLEN-1:0];
|
||||
reg [ACC_WIDTH-1:0] y_vector [VECTORLEN-1:0];
|
||||
reg [0:0] batch_vector [VECTORLEN-1:0];
|
||||
|
||||
integer j;
|
||||
integer a_, b_, y_, batch_;
|
||||
initial begin
|
||||
y_ = 0;
|
||||
a_ = 0;
|
||||
b_ = 0;
|
||||
y_vector[0] = 0;
|
||||
for (j = 0; j < VECTORLEN; j = j + 1) begin
|
||||
batch_ = (j % 4) == 0;
|
||||
a_ = (a_ ^ (PRIME1 * j)) & ((1 << OPER_WIDTH) - 1);
|
||||
b_ = (b_ ^ (PRIME2 * j)) & ((1 << OPER_WIDTH) - 1);
|
||||
if (batch_)
|
||||
y_ = a_ * b_;
|
||||
else
|
||||
y_ = a_ * b_ + y_;
|
||||
a_vector[j] = a_;
|
||||
b_vector[j] = b_;
|
||||
y_vector[j + 1] = y_;
|
||||
batch_vector[j] = batch_;
|
||||
end
|
||||
end
|
||||
|
||||
input wire clk;
|
||||
wire batch = batch_vector[i];
|
||||
wire [OPER_WIDTH-1:0] a = a_vector[i];
|
||||
wire [OPER_WIDTH-1:0] b = b_vector[i];
|
||||
wire [ACC_WIDTH-1:0] y_expected = y_vector[i];
|
||||
wire [ACC_WIDTH-1:0] y;
|
||||
top uut_top(
|
||||
.batch(batch),
|
||||
.clk(clk),
|
||||
.a(a),
|
||||
.b(b),
|
||||
.y(y)
|
||||
);
|
||||
reg [7:0] i = 0;
|
||||
always @(posedge clk) begin
|
||||
if (i < VECTORLEN) begin
|
||||
// FIXME: for some reason the first assert fails (despite comparing zero to zero)
|
||||
if (i > 0)
|
||||
assert(y == y_expected);
|
||||
i <= i + 1;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
EOF
|
||||
read_verilog +/quicklogic/qlf_k6n10f/dsp_sim.v
|
||||
hierarchy -top testbench
|
||||
proc
|
||||
sim -assert -q -clock clk -n 20
|
|
@ -0,0 +1,17 @@
|
|||
read_verilog ../../common/fsm.v
|
||||
hierarchy -top fsm
|
||||
proc
|
||||
flatten
|
||||
|
||||
equiv_opt -run :prove -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f
|
||||
async2sync
|
||||
miter -equiv -make_assert -flatten gold gate miter
|
||||
sat -verify -prove-asserts -show-public -set-at 1 in_reset 1 -seq 20 -prove-skip 1 miter
|
||||
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd fsm # Constrain all select calls below inside the top module
|
||||
|
||||
select -assert-count 9 t:$lut
|
||||
select -assert-count 6 t:sdffsre
|
||||
|
||||
select -assert-none t:$lut t:sdffsre %% t:* %D
|
|
@ -0,0 +1,29 @@
|
|||
read_verilog ../../common/latches.v
|
||||
design -save read
|
||||
|
||||
hierarchy -top latchp
|
||||
proc
|
||||
equiv_opt -assert -async2sync -map +/quicklogic/qlf_k6n10f/cells_sim.v synth_quicklogic -family qlf_k6n10f
|
||||
design -load postopt
|
||||
cd latchp
|
||||
select -assert-count 1 t:latchsre
|
||||
select -assert-none t:latchsre %% t:* %D
|
||||
|
||||
design -load read
|
||||
hierarchy -top latchn
|
||||
proc
|
||||
equiv_opt -assert -async2sync -map +/quicklogic/qlf_k6n10f/cells_sim.v synth_quicklogic -family qlf_k6n10f
|
||||
design -load postopt
|
||||
cd latchn
|
||||
select -assert-count 1 t:latchnsre
|
||||
select -assert-none t:latchnsre %% t:* %D
|
||||
|
||||
design -load read
|
||||
hierarchy -top latchsr
|
||||
proc
|
||||
equiv_opt -assert -async2sync -map +/quicklogic/qlf_k6n10f/cells_sim.v synth_quicklogic -family qlf_k6n10f
|
||||
design -load postopt
|
||||
cd latchsr
|
||||
select -assert-count 2 t:$lut
|
||||
select -assert-count 1 t:latchnsre
|
||||
select -assert-none t:$lut t:latchnsre %% t:* %D
|
|
@ -0,0 +1,10 @@
|
|||
read_verilog ../../common/logic.v
|
||||
hierarchy -top top
|
||||
proc
|
||||
equiv_opt -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd top # Constrain all select calls below inside the top module
|
||||
|
||||
select -assert-count 9 t:$lut
|
||||
|
||||
select -assert-none t:$lut %% t:* %D
|
|
@ -0,0 +1,462 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
blockram_template = """# ======================================
|
||||
log ** GENERATING TEST {top} WITH PARAMS{param_str}
|
||||
design -reset; read_verilog -defer ../../common/blockram.v
|
||||
chparam{param_str} {top}
|
||||
hierarchy -top {top}
|
||||
synth_quicklogic -family qlf_k6n10f -top {top}
|
||||
"""
|
||||
blockram_tests: "list[tuple[list[tuple[str, int]], str, list[str]]]" = [
|
||||
# TDP36K = 1024x36bit RAM, 2048x18bit or 4096x9bit also work
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 36)], "sync_ram_*dp", ["-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 11), ("DATA_WIDTH", 18)], "sync_ram_*dp", ["-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 12), ("DATA_WIDTH", 9)], "sync_ram_*dp", ["-assert-count 1 t:TDP36K"]),
|
||||
# larger sizes need an extra ram
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 48)], "sync_ram_*dp", ["-assert-count 2 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 11), ("DATA_WIDTH", 36)], "sync_ram_*dp", ["-assert-count 2 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 12), ("DATA_WIDTH", 18)], "sync_ram_*dp", ["-assert-count 2 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 12), ("DATA_WIDTH", 10)], "sync_ram_*dp", ["-assert-count 2 t:TDP36K"]),
|
||||
# 4096x20bit *can* fit in 3, albeit somewhat awkwardly
|
||||
([("ADDRESS_WIDTH", 12), ("DATA_WIDTH", 20)], "sync_ram_*dp", ["-assert-min 3 t:TDP36K",
|
||||
"-assert-max 4 t:TDP36K"]),
|
||||
|
||||
# smaller sizes can still fit in one, and assign the correct width (1, 2, 4, 8, 18 or 36)
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 32)], "sync_ram_*dp", ["-assert-count 1 t:TDP36K", "-assert-count 1 t:TDP36K a:port_a_width=36 %i"]),
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 24)], "sync_ram_*dp", ["-assert-count 1 t:TDP36K", "-assert-count 1 t:TDP36K a:port_a_width=36 %i"]),
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 18)], "sync_ram_*dp", ["-assert-count 1 t:TDP36K", "-assert-count 1 t:TDP36K a:port_a_width=18 %i"]),
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 9)], "sync_ram_*dp", ["-assert-count 1 t:TDP36K", "-assert-count 1 t:TDP36K a:port_a_width=9 %i"]),
|
||||
([("ADDRESS_WIDTH", 11), ("DATA_WIDTH", 16)], "sync_ram_*dp", ["-assert-count 1 t:TDP36K", "-assert-count 1 t:TDP36K a:port_a_width=18 %i"]),
|
||||
([("ADDRESS_WIDTH", 11), ("DATA_WIDTH", 9)], "sync_ram_*dp", ["-assert-count 1 t:TDP36K", "-assert-count 1 t:TDP36K a:port_a_width=9 %i"]),
|
||||
([("ADDRESS_WIDTH", 12), ("DATA_WIDTH", 8)], "sync_ram_*dp", ["-assert-count 1 t:TDP36K", "-assert-count 1 t:TDP36K a:port_a_width=9 %i"]),
|
||||
([("ADDRESS_WIDTH", 13), ("DATA_WIDTH", 4)], "sync_ram_*dp", ["-assert-count 1 t:TDP36K", "-assert-count 1 t:TDP36K a:port_a_width=4 %i"]),
|
||||
([("ADDRESS_WIDTH", 14), ("DATA_WIDTH", 2)], "sync_ram_*dp", ["-assert-count 1 t:TDP36K", "-assert-count 1 t:TDP36K a:port_a_width=2 %i"]),
|
||||
([("ADDRESS_WIDTH", 15), ("DATA_WIDTH", 1)], "sync_ram_*dp", ["-assert-count 1 t:TDP36K", "-assert-count 1 t:TDP36K a:port_a_width=1 %i"]),
|
||||
|
||||
# 2x asymmetric (1024x36bit write / 2048x18bit read or vice versa = 1TDP36K)
|
||||
([("ADDRESS_WIDTH", 11), ("DATA_WIDTH", 18), ("SHIFT_VAL", 1)], "sync_ram_sdp_w*r", ["-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 11), ("DATA_WIDTH", 16), ("SHIFT_VAL", 1)], "sync_ram_sdp_w*r", ["-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 12), ("DATA_WIDTH", 9), ("SHIFT_VAL", 1)], "sync_ram_sdp_w*r", ["-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 12), ("DATA_WIDTH", 8), ("SHIFT_VAL", 1)], "sync_ram_sdp_w*r", ["-assert-count 1 t:TDP36K"]),
|
||||
|
||||
# 4x asymmetric (1024x36bit write / 4096x9bit read or vice versa = 1TDP36K)
|
||||
([("ADDRESS_WIDTH", 11), ("DATA_WIDTH", 4), ("SHIFT_VAL", 2)], "sync_ram_sdp_w*r", ["-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 12), ("DATA_WIDTH", 9), ("SHIFT_VAL", 2)], "sync_ram_sdp_w*r", ["-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 12), ("DATA_WIDTH", 8), ("SHIFT_VAL", 2)], "sync_ram_sdp_w*r", ["-assert-count 1 t:TDP36K"]),
|
||||
|
||||
# can also use an extra TDP36K for higher width
|
||||
([("ADDRESS_WIDTH", 11), ("DATA_WIDTH", 16), ("SHIFT_VAL", 1)], "sync_ram_sdp_w*r", ["-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 12), ("DATA_WIDTH", 8), ("SHIFT_VAL", 2)], "sync_ram_sdp_w*r", ["-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 36), ("SHIFT_VAL", 1)], "sync_ram_sdp_w*r", ["-assert-count 2 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 36), ("SHIFT_VAL", 2)], "sync_ram_sdp_w*r", ["-assert-count 4 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 9), ("DATA_WIDTH", 36), ("SHIFT_VAL", 2)], "sync_ram_sdp_w*r", ["-assert-count 4 t:TDP36K"]),
|
||||
|
||||
# # SHIFT=0 should be identical to sync_ram_sdp
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 36), ("SHIFT_VAL", 0)], "sync_ram_sdp_w*r", ["-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 11), ("DATA_WIDTH", 18), ("SHIFT_VAL", 0)], "sync_ram_sdp_w*r", ["-assert-count 1 t:TDP36K"]),
|
||||
|
||||
# asymmetric memories assign different port widths on a and b ports
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 18), ("SHIFT_VAL", 1)], "sync_ram_sdp_wwr", ["-assert-count 1 t:TDP36K", "-assert-count 1 t:TDP36K a:port_a_width=36 %i a:port_b_width=18 %i"]),
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 9), ("SHIFT_VAL", 1)], "sync_ram_sdp_wwr", ["-assert-count 1 t:TDP36K", "-assert-count 1 t:TDP36K a:port_a_width=18 %i a:port_b_width=9 %i"]),
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 9), ("SHIFT_VAL", 2)], "sync_ram_sdp_wwr", ["-assert-count 1 t:TDP36K", "-assert-count 1 t:TDP36K a:port_a_width=36 %i a:port_b_width=9 %i"]),
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 18), ("SHIFT_VAL", 1)], "sync_ram_sdp_wrr", ["-assert-count 1 t:TDP36K", "-assert-count 1 t:TDP36K a:port_a_width=18 %i a:port_b_width=36 %i"]),
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 9), ("SHIFT_VAL", 1)], "sync_ram_sdp_wrr", ["-assert-count 1 t:TDP36K", "-assert-count 1 t:TDP36K a:port_a_width=9 %i a:port_b_width=18 %i"]),
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 9), ("SHIFT_VAL", 2)], "sync_ram_sdp_wrr", ["-assert-count 1 t:TDP36K", "-assert-count 1 t:TDP36K a:port_a_width=9 %i a:port_b_width=36 %i"]),
|
||||
|
||||
# two disjoint 18K memories can share a single TDP36K
|
||||
([("ADDRESS_WIDTH_A", 10), ("DATA_WIDTH_A", 18),
|
||||
("ADDRESS_WIDTH_B", 10), ("DATA_WIDTH_B", 18)], "double_sync_ram_sdp", ["-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH_A", 10), ("DATA_WIDTH_A", 16),
|
||||
("ADDRESS_WIDTH_B", 11), ("DATA_WIDTH_B", 8)], "double_sync_ram_sdp", ["-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH_A", 14), ("DATA_WIDTH_A", 1),
|
||||
("ADDRESS_WIDTH_B", 11), ("DATA_WIDTH_B", 8)], "double_sync_ram_sdp", ["-assert-count 1 t:TDP36K"]),
|
||||
# but only if data width is <= 18
|
||||
([("ADDRESS_WIDTH_A", 9), ("DATA_WIDTH_A", 36),
|
||||
("ADDRESS_WIDTH_B", 11), ("DATA_WIDTH_B", 9)], "double_sync_ram_sdp", ["-assert-count 2 t:TDP36K"]),
|
||||
|
||||
# also for tdp
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 18)], "double_sync_ram_tdp", ["-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 16)], "double_sync_ram_tdp", ["-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 11), ("DATA_WIDTH", 8)], "double_sync_ram_tdp", ["-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 12), ("DATA_WIDTH", 4)], "double_sync_ram_tdp", ["-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 13), ("DATA_WIDTH", 2)], "double_sync_ram_tdp", ["-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 14), ("DATA_WIDTH", 1)], "double_sync_ram_tdp", ["-assert-count 1 t:TDP36K"]),
|
||||
# still only if data width is <= 18
|
||||
([("ADDRESS_WIDTH", 9), ("DATA_WIDTH", 36)], "double_sync_ram_tdp", ["-assert-count 2 t:TDP36K"]),
|
||||
|
||||
# sharing a TDP36K sets is_split=1
|
||||
([("ADDRESS_WIDTH_A", 10), ("DATA_WIDTH_A", 18),
|
||||
("ADDRESS_WIDTH_B", 10), ("DATA_WIDTH_B", 18)], "double_sync_ram_sdp", ["-assert-count 1 t:TDP36K a:is_split=1 %i"]),
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 18)], "double_sync_ram_tdp", ["-assert-count 1 t:TDP36K a:is_split=1 %i"]),
|
||||
# an unshared TDP36K sets is_split=0
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 36)], "sync_ram_*dp", ["-assert-count 1 t:TDP36K a:is_split=0 %i"]),
|
||||
([("ADDRESS_WIDTH", 11), ("DATA_WIDTH", 18)], "sync_ram_sdp_w*r", ["-assert-count 1 t:TDP36K a:is_split=0 %i"]),
|
||||
|
||||
# sharing a TDP36K sets correct port widths
|
||||
([("ADDRESS_WIDTH_A", 10), ("DATA_WIDTH_A", 18), ("DATA_WIDTH_B", 18), ("ADDRESS_WIDTH_B", 10)], "double_sync_ram_sdp",
|
||||
["-assert-count 1 t:TDP36K a:port_a1_width=18 %i a:port_a2_width=18 %i",
|
||||
"-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH", 10), ("DATA_WIDTH", 18)], "double_sync_ram_tdp",
|
||||
["-assert-count 1 t:TDP36K a:port_a1_width=18 %i a:port_a2_width=18 %i",
|
||||
"-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH_A", 10), ("DATA_WIDTH_A", 16), ("DATA_WIDTH_B", 8), ("ADDRESS_WIDTH_B", 11)], "double_sync_ram_sdp",
|
||||
["-assert-count 1 t:TDP36K a:port_a1_width=18 %i a:port_a2_width=9 %i "
|
||||
+ "t:TDP36K a:port_a2_width=18 %i a:port_a1_width=9 %i %u",
|
||||
"-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH_A", 12), ("DATA_WIDTH_A", 4), ("DATA_WIDTH_B", 12), ("ADDRESS_WIDTH_B", 10)], "double_sync_ram_sdp",
|
||||
["-assert-count 1 t:TDP36K a:port_a1_width=4 %i a:port_a2_width=18 %i "
|
||||
+ "t:TDP36K a:port_a2_width=4 %i a:port_a1_width=18 %i %u",
|
||||
"-assert-count 1 t:TDP36K"]),
|
||||
([("ADDRESS_WIDTH_A", 13), ("DATA_WIDTH_A", 2), ("DATA_WIDTH_B", 1), ("ADDRESS_WIDTH_B", 14)], "double_sync_ram_sdp",
|
||||
["-assert-count 1 t:TDP36K a:port_a1_width=2 %i a:port_a2_width=1 %i "
|
||||
+ "t:TDP36K a:port_a2_width=2 %i a:port_a1_width=1 %i %u",
|
||||
"-assert-count 1 t:TDP36K"]),
|
||||
]
|
||||
|
||||
sim_template = """\
|
||||
design -stash synthesized
|
||||
design -copy-from synthesized -as {top}_synth {top}
|
||||
design -delete synthesized
|
||||
read_verilog +/quicklogic/common/cells_sim.v +/quicklogic/qlf_k6n10f/cells_sim.v +/quicklogic/qlf_k6n10f/brams_sim.v +/quicklogic/qlf_k6n10f/sram1024x18_mem.v +/quicklogic/qlf_k6n10f/ufifo_ctl.v +/quicklogic/qlf_k6n10f/TDP18K_FIFO.v
|
||||
read_verilog <<EOF
|
||||
`define MEM_TEST_VECTOR {mem_test_vector}
|
||||
|
||||
`define UUT_SUBMODULE \\
|
||||
{uut_submodule}
|
||||
EOF
|
||||
read_verilog -defer -formal mem_tb.v
|
||||
chparam{param_str} -set VECTORLEN {vectorlen} TB
|
||||
hierarchy -top TB -check
|
||||
prep
|
||||
log ** CHECKING SIMULATION FOR TEST {top} WITH PARAMS{param_str}
|
||||
sim -clock clk -n {vectorlen} -assert
|
||||
"""
|
||||
|
||||
sync_ram_sdp_submodule = """\
|
||||
sync_ram_sdp_synth uut (\\
|
||||
.clk(clk),\\
|
||||
.address_in_r(ra_a),\\
|
||||
.data_out(rq_a),\\
|
||||
.write_enable(wce_a),\\
|
||||
.address_in_w(wa_a),\\
|
||||
.data_in(wd_a)\\
|
||||
);\
|
||||
"""
|
||||
|
||||
sync_ram_tdp_submodule = """\
|
||||
sync_ram_tdp_synth uut (\\
|
||||
.clk_a(clk),\\
|
||||
.clk_b(clk),\\
|
||||
.write_enable_a(wce_a),\\
|
||||
.write_enable_b(wce_b),\\
|
||||
.read_enable_a(rce_a),\\
|
||||
.read_enable_b(rce_b),\\
|
||||
.addr_a(ra_a),\\
|
||||
.addr_b(ra_b),\\
|
||||
.read_data_a(rq_a),\\
|
||||
.read_data_b(rq_b),\\
|
||||
.write_data_a(wd_a),\\
|
||||
.write_data_b(wd_b)\\
|
||||
);\
|
||||
"""
|
||||
|
||||
sync_ram_sdp_wwr_submodule = """\
|
||||
sync_ram_sdp_wwr_synth uut (\\
|
||||
.clk_w(clk),\\
|
||||
.clk_r(clk),\\
|
||||
.write_enable(wce_a),\\
|
||||
.data_in(wd_a),\\
|
||||
.address_in_w(wa_a),\\
|
||||
.address_in_r(ra_a),\\
|
||||
.data_out(rq_a)\\
|
||||
);\
|
||||
"""
|
||||
|
||||
sync_ram_sdp_wrr_submodule = """\
|
||||
sync_ram_sdp_wrr_synth uut (\\
|
||||
.clk_w(clk),\\
|
||||
.clk_r(clk),\\
|
||||
.write_enable(wce_a),\\
|
||||
.data_in(wd_a),\\
|
||||
.address_in_w(wa_a),\\
|
||||
.address_in_r(ra_a),\\
|
||||
.data_out(rq_a)\\
|
||||
);\
|
||||
"""
|
||||
|
||||
double_sync_ram_sdp_submodule = """\
|
||||
double_sync_ram_sdp_synth uut (\\
|
||||
.clk_a(clk),\\
|
||||
.write_enable_a(wce_a),\\
|
||||
.address_in_w_a(wa_a),\\
|
||||
.address_in_r_a(ra_a),\\
|
||||
.data_in_a(wd_a),\\
|
||||
.data_out_a(rq_a),\\
|
||||
.clk_b(clk),\\
|
||||
.write_enable_b(wce_b),\\
|
||||
.address_in_w_b(wa_b),\\
|
||||
.address_in_r_b(ra_b),\\
|
||||
.data_in_b(wd_b),\\
|
||||
.data_out_b(rq_b)\\
|
||||
);\
|
||||
"""
|
||||
|
||||
@dataclass
|
||||
class TestClass:
|
||||
params: dict[str, int]
|
||||
top: str
|
||||
assertions: list[str]
|
||||
test_steps: None | list[dict[str, int]]
|
||||
|
||||
test_val_map = {
|
||||
"rce_a": "rce_a_testvector",
|
||||
"ra_a": "ra_a_testvector",
|
||||
"rq_a": "rq_a_expected",
|
||||
"wce_a": "wce_a_testvector",
|
||||
"wa_a": "wa_a_testvector",
|
||||
"wd_a": "wd_a_testvector",
|
||||
"rce_b": "rce_b_testvector",
|
||||
"ra_b": "ra_b_testvector",
|
||||
"rq_b": "rq_b_expected",
|
||||
"wce_b": "wce_b_testvector",
|
||||
"wa_b": "wa_b_testvector",
|
||||
"wd_b": "wd_b_testvector",
|
||||
}
|
||||
|
||||
sim_tests: list[TestClass] = [
|
||||
TestClass( # basic SDP test
|
||||
# note that the common SDP model reads every cycle, but the testbench
|
||||
# still uses the rce signal to check read assertions
|
||||
params={"ADDRESS_WIDTH": 10, "DATA_WIDTH": 36},
|
||||
top="sync_ram_sdp",
|
||||
assertions=[],
|
||||
test_steps=[
|
||||
{"wce_a": 1, "wa_a": 0x0A, "wd_a": 0xdeadbeef},
|
||||
{"wce_a": 1, "wa_a": 0xBA, "wd_a": 0x5a5a5a5a},
|
||||
{"wce_a": 1, "wa_a": 0xFF, "wd_a": 0},
|
||||
{"rce_a": 1, "ra_a": 0x0A},
|
||||
{"rq_a": 0xdeadbeef},
|
||||
{"rce_a": 1, "ra_a": 0xFF},
|
||||
{"rq_a": 0},
|
||||
]
|
||||
),
|
||||
TestClass( # SDP read before write
|
||||
params={"ADDRESS_WIDTH": 4, "DATA_WIDTH": 16},
|
||||
top="sync_ram_sdp",
|
||||
assertions=[],
|
||||
test_steps=[
|
||||
{"wce_a": 1, "wa_a": 0xA, "wd_a": 0x1234},
|
||||
{"wce_a": 1, "wa_a": 0xA, "wd_a": 0x5678, "rce_a": 1, "ra_a": 0xA},
|
||||
{"rq_a": 0x1234, "rce_a": 1, "ra_a": 0xA},
|
||||
{"rq_a": 0x5678},
|
||||
]
|
||||
),
|
||||
TestClass( # basic TDP test
|
||||
# note that the testbench uses ra and wa, while the common TDP model
|
||||
# uses a shared address
|
||||
params={"ADDRESS_WIDTH": 10, "DATA_WIDTH": 36},
|
||||
top="sync_ram_tdp",
|
||||
assertions=[],
|
||||
test_steps=[
|
||||
{"wce_a": 1, "ra_a": 0x0A, "wce_b": 1, "ra_b": 0xBA,
|
||||
"wd_a": 0xdeadbeef, "wd_b": 0x5a5a5a5a},
|
||||
{"wce_a": 1, "ra_a": 0xFF,
|
||||
"wd_a": 0},
|
||||
{"rce_a": 1, "ra_a": 0x0A, "rce_b": 1, "ra_b": 0x0A},
|
||||
{"rq_a": 0xdeadbeef, "rq_b": 0xdeadbeef},
|
||||
{"rce_a": 1, "ra_a": 0xFF, "rce_b": 1, "ra_b": 0xBA},
|
||||
{"rq_a": 0, "rq_b": 0x5a5a5a5a},
|
||||
]
|
||||
),
|
||||
TestClass( # TDP with truncation
|
||||
params={"ADDRESS_WIDTH": 4, "DATA_WIDTH": 16},
|
||||
top="sync_ram_tdp",
|
||||
assertions=[],
|
||||
test_steps=[
|
||||
{"wce_a": 1, "ra_a": 0x0F, "wce_b": 1, "ra_b": 0xBA,
|
||||
"wd_a": 0xdeadbeef, "wd_b": 0x5a5a5a5a},
|
||||
{"wce_a": 1, "ra_a": 0xFF,
|
||||
"wd_a": 0},
|
||||
{"rce_a": 1, "ra_a": 0x0F, "rce_b": 1, "ra_b": 0x0A},
|
||||
{"rq_a": 0, "rq_b": 0x00005a5a},
|
||||
]
|
||||
),
|
||||
TestClass( # TDP read before write
|
||||
# note that the testbench uses rce and wce, while the common TDP model
|
||||
# uses a single enable for write, with reads on no write
|
||||
params={"ADDRESS_WIDTH": 10, "DATA_WIDTH": 36},
|
||||
top="sync_ram_tdp",
|
||||
assertions=[],
|
||||
test_steps=[
|
||||
{"wce_a": 1, "ra_a": 0x0A, "wce_b": 1, "ra_b": 0xBA,
|
||||
"wd_a": 0xdeadbeef, "wd_b": 0x5a5a5a5a},
|
||||
{"wce_a": 1, "ra_a": 0xBA, "rce_b": 1, "ra_b": 0xBA,
|
||||
"wd_a": 0xa5a5a5a5},
|
||||
{ "rq_b": 0x5a5a5a5a},
|
||||
{"rce_a": 1, "ra_a": 0x0A, "rce_b": 1, "ra_b": 0x0A},
|
||||
{"rq_a": 0xdeadbeef, "rq_b": 0xdeadbeef},
|
||||
{ "rce_b": 1, "ra_b": 0xBA},
|
||||
{ "rq_b": 0xa5a5a5a5},
|
||||
]
|
||||
),
|
||||
TestClass( # 2x wide write
|
||||
params={"ADDRESS_WIDTH": 11, "DATA_WIDTH": 18, "SHIFT_VAL": 1},
|
||||
top="sync_ram_sdp_wwr",
|
||||
assertions=[],
|
||||
test_steps=[
|
||||
{"wce_a": 1, "wa_a": 0b0000000001, "wd_a": 0xdeadbeef},
|
||||
{"rce_a": 0, "ra_a": 0b00000000010},
|
||||
{"rq_a": 0xdead},
|
||||
{"rce_a": 0, "ra_a": 0b00000000011},
|
||||
{"rq_a": 0xbeef},
|
||||
]
|
||||
),
|
||||
TestClass( # 4x wide write
|
||||
params={"ADDRESS_WIDTH": 10, "DATA_WIDTH": 8, "SHIFT_VAL": 2},
|
||||
top="sync_ram_sdp_wwr",
|
||||
assertions=[],
|
||||
test_steps=[
|
||||
{"wce_a": 1, "wa_a": 0b000100001, "wd_a": 0xdeadbeef},
|
||||
{"rce_a": 0, "ra_a": 0b00010000100},
|
||||
{"rq_a": 0xde},
|
||||
{"rce_a": 0, "ra_a": 0b00010000101},
|
||||
{"rq_a": 0xad},
|
||||
{"rce_a": 0, "ra_a": 0b00010000110},
|
||||
{"rq_a": 0xbe},
|
||||
{"rce_a": 0, "ra_a": 0b00010000111},
|
||||
{"rq_a": 0xef},
|
||||
]
|
||||
),
|
||||
TestClass( # 2x wide read
|
||||
params={"ADDRESS_WIDTH": 11, "DATA_WIDTH": 18, "SHIFT_VAL": 1},
|
||||
top="sync_ram_sdp_wrr",
|
||||
assertions=[],
|
||||
test_steps=[
|
||||
{"wce_a": 1, "wa_a": 0b00000000010, "wd_a": 0xdead},
|
||||
{"wce_a": 1, "wa_a": 0b00000000011, "wd_a": 0xbeef},
|
||||
{"rce_a": 0, "ra_a": 0b0000000001},
|
||||
{"rq_a": 0xdeadbeef},
|
||||
]
|
||||
),
|
||||
TestClass( # 4x wide read
|
||||
params={"ADDRESS_WIDTH": 10, "DATA_WIDTH": 8, "SHIFT_VAL": 2},
|
||||
top="sync_ram_sdp_wrr",
|
||||
assertions=[],
|
||||
test_steps=[
|
||||
{"wce_a": 1, "wa_a": 0b00010000100, "wd_a": 0xde},
|
||||
{"wce_a": 1, "wa_a": 0b00010000101, "wd_a": 0xad},
|
||||
{"wce_a": 1, "wa_a": 0b00010000110, "wd_a": 0xbe},
|
||||
{"wce_a": 1, "wa_a": 0b00010000111, "wd_a": 0xef},
|
||||
{"rce_a": 0, "ra_a": 0b000100001},
|
||||
{"rq_a": 0xdeadbeef},
|
||||
]
|
||||
),
|
||||
TestClass( # basic split SDP test
|
||||
params={"ADDRESS_WIDTH_A": 10, "DATA_WIDTH_A": 16,
|
||||
"ADDRESS_WIDTH_B": 10, "DATA_WIDTH_B": 16},
|
||||
top="double_sync_ram_sdp",
|
||||
assertions=[],
|
||||
test_steps=[
|
||||
{"wce_a": 1, "wa_a": 0x0A, "wce_b": 1, "wa_b": 0xBA,
|
||||
"wd_a": 0x1234, "wd_b": 0x4567},
|
||||
{"wce_a": 1, "wa_a": 0xFF, "wce_b": 1, "wa_b": 0x0A,
|
||||
"wd_a": 0, "wd_b": 0xbeef},
|
||||
{"rce_a": 1, "ra_a": 0x0A, "rce_b": 1, "ra_b": 0x0A},
|
||||
{"rq_a": 0x1234, "rq_b": 0xbeef},
|
||||
]
|
||||
),
|
||||
]
|
||||
|
||||
for (params, top, assertions) in blockram_tests:
|
||||
sim_test = TestClass(
|
||||
params=dict(params),
|
||||
top=top,
|
||||
assertions=assertions,
|
||||
test_steps=None
|
||||
)
|
||||
sim_tests.append(sim_test)
|
||||
|
||||
i = 0
|
||||
j = 0
|
||||
max_j = 16
|
||||
f = None
|
||||
for sim_test in sim_tests:
|
||||
# format params
|
||||
param_str = ""
|
||||
for (key, val) in sim_test.params.items():
|
||||
param_str += f" -set {key} {val}"
|
||||
|
||||
# resolve top module wildcards
|
||||
top_list = [sim_test.top]
|
||||
if "*dp" in sim_test.top:
|
||||
top_list += [
|
||||
sim_test.top.replace("*dp", dp_sub) for dp_sub in ["sdp", "tdp"]
|
||||
]
|
||||
if "w*r" in sim_test.top:
|
||||
top_list += [
|
||||
sim_test.top.replace("w*r", wr_sub) for wr_sub in ["wwr", "wrr"]
|
||||
]
|
||||
if len(top_list) > 1:
|
||||
top_list.pop(0)
|
||||
|
||||
# iterate over string substitutions
|
||||
for top in top_list:
|
||||
# limit number of tests per file to allow parallel make
|
||||
if not f:
|
||||
fn = f"t_mem{i}.ys"
|
||||
f = open(fn, mode="w")
|
||||
j = 0
|
||||
|
||||
# output yosys script test file
|
||||
print(
|
||||
blockram_template.format(param_str=param_str, top=top),
|
||||
file=f
|
||||
)
|
||||
for assertion in sim_test.assertions:
|
||||
print("log ** CHECKING CELL COUNTS FOR TEST {top} WITH PARAMS{param_str}".format(param_str=param_str, top=top), file=f)
|
||||
print("select {}".format(assertion), file=f)
|
||||
print("", file=f)
|
||||
|
||||
# prepare simulation tests
|
||||
test_steps = sim_test.test_steps
|
||||
if test_steps:
|
||||
if top == "sync_ram_sdp":
|
||||
uut_submodule = sync_ram_sdp_submodule
|
||||
elif top == "sync_ram_tdp":
|
||||
uut_submodule = sync_ram_tdp_submodule
|
||||
elif top == "sync_ram_sdp_wwr":
|
||||
uut_submodule = sync_ram_sdp_wwr_submodule
|
||||
elif top == "sync_ram_sdp_wrr":
|
||||
uut_submodule = sync_ram_sdp_wrr_submodule
|
||||
elif top == "double_sync_ram_sdp":
|
||||
uut_submodule = double_sync_ram_sdp_submodule
|
||||
else:
|
||||
raise NotImplementedError(f"missing submodule header for {top}")
|
||||
mem_test_vector = ""
|
||||
for step, test in enumerate(test_steps):
|
||||
for key, val in test.items():
|
||||
key = test_val_map[key]
|
||||
mem_test_vector += f"\\\n{key}[{step}] = 'h{val:x};"
|
||||
print(
|
||||
sim_template.format(
|
||||
top=top,
|
||||
mem_test_vector=mem_test_vector,
|
||||
uut_submodule=uut_submodule,
|
||||
param_str=param_str,
|
||||
vectorlen=len(test_steps) + 2
|
||||
), file=f
|
||||
)
|
||||
# simulation counts for 2 tests
|
||||
j += 1
|
||||
|
||||
# increment test counter
|
||||
j += 1
|
||||
if j >= max_j:
|
||||
f = f.close()
|
||||
i += 1
|
||||
|
||||
if f:
|
||||
f.close()
|
|
@ -0,0 +1,84 @@
|
|||
module TB(input clk);
|
||||
|
||||
parameter ADDRESS_WIDTH = 10;
|
||||
parameter ADDRESS_WIDTH_A = ADDRESS_WIDTH;
|
||||
parameter ADDRESS_WIDTH_B = ADDRESS_WIDTH;
|
||||
parameter DATA_WIDTH = 36;
|
||||
parameter DATA_WIDTH_A = DATA_WIDTH;
|
||||
parameter DATA_WIDTH_B = DATA_WIDTH;
|
||||
parameter VECTORLEN = 16;
|
||||
parameter SHIFT_VAL = 0;
|
||||
|
||||
// intentionally keep expected values at full width precision to allow testing
|
||||
// of truncation
|
||||
localparam MAX_WIDTH = 36;
|
||||
|
||||
reg rce_a_testvector [VECTORLEN-1:0];
|
||||
reg [ADDRESS_WIDTH_A-1:0] ra_a_testvector [VECTORLEN-1:0];
|
||||
reg [MAX_WIDTH-1:0] rq_a_expected [VECTORLEN-1:0];
|
||||
|
||||
reg wce_a_testvector [VECTORLEN-1:0];
|
||||
reg [ADDRESS_WIDTH_A-1:0] wa_a_testvector [VECTORLEN-1:0];
|
||||
reg [DATA_WIDTH_A-1:0] wd_a_testvector [VECTORLEN-1:0];
|
||||
|
||||
reg rce_b_testvector [VECTORLEN-1:0];
|
||||
reg [ADDRESS_WIDTH_B-1:0] ra_b_testvector [VECTORLEN-1:0];
|
||||
reg [MAX_WIDTH-1:0] rq_b_expected [VECTORLEN-1:0];
|
||||
|
||||
reg wce_b_testvector [VECTORLEN-1:0];
|
||||
reg [ADDRESS_WIDTH_B-1:0] wa_b_testvector [VECTORLEN-1:0];
|
||||
reg [DATA_WIDTH_B-1:0] wd_b_testvector [VECTORLEN-1:0];
|
||||
|
||||
reg [$clog2(VECTORLEN)-1:0] i = 0;
|
||||
|
||||
integer j;
|
||||
initial begin
|
||||
for (j = 0; j < VECTORLEN; j = j + 1) begin
|
||||
rce_a_testvector[j] = 1'b0;
|
||||
ra_a_testvector[j] = 10'h0;
|
||||
wce_a_testvector[j] = 1'b0;
|
||||
wa_a_testvector[j] = 10'h0;
|
||||
rce_b_testvector[j] = 1'b0;
|
||||
ra_b_testvector[j] = 10'h0;
|
||||
wce_b_testvector[j] = 1'b0;
|
||||
wa_b_testvector[j] = 10'h0;
|
||||
|
||||
end
|
||||
|
||||
`MEM_TEST_VECTOR
|
||||
|
||||
end
|
||||
|
||||
|
||||
wire rce_a = rce_a_testvector[i];
|
||||
wire [ADDRESS_WIDTH_A-1:0] ra_a = ra_a_testvector[i];
|
||||
wire [MAX_WIDTH-1:0] rq_a_e = rq_a_expected[i];
|
||||
wire [DATA_WIDTH_A-1:0] rq_a;
|
||||
|
||||
wire wce_a = wce_a_testvector[i];
|
||||
wire [ADDRESS_WIDTH_A-1:0] wa_a = wa_a_testvector[i];
|
||||
wire [DATA_WIDTH_A-1:0] wd_a = wd_a_testvector[i];
|
||||
|
||||
wire rce_b = rce_b_testvector[i];
|
||||
wire [ADDRESS_WIDTH_B-1:0] ra_b = ra_b_testvector[i];
|
||||
wire [MAX_WIDTH-1:0] rq_b_e = rq_b_expected[i];
|
||||
wire [DATA_WIDTH_B-1:0] rq_b;
|
||||
|
||||
wire wce_b = wce_b_testvector[i];
|
||||
wire [ADDRESS_WIDTH_B-1:0] wa_b = wa_b_testvector[i];
|
||||
wire [DATA_WIDTH_B-1:0] wd_b = wd_b_testvector[i];
|
||||
|
||||
`UUT_SUBMODULE
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (i < VECTORLEN-1) begin
|
||||
if (i > 0) begin
|
||||
if($past(rce_a))
|
||||
assert(rq_a == rq_a_e);
|
||||
if($past(rce_b))
|
||||
assert(rq_b == rq_b_e);
|
||||
end
|
||||
i <= i + 1;
|
||||
end
|
||||
end
|
||||
endmodule
|
|
@ -0,0 +1,50 @@
|
|||
module top(clk);
|
||||
parameter DEPTH_LOG2 = 10;
|
||||
parameter WIDTH = 36;
|
||||
parameter PRIME = 237481091;
|
||||
localparam DEPTH = 2**DEPTH_LOG2;
|
||||
|
||||
input wire clk;
|
||||
|
||||
(* syn_ramstyle = "block_ram" *)
|
||||
reg [WIDTH-1:0] mem [DEPTH-1:0];
|
||||
|
||||
integer i;
|
||||
initial begin
|
||||
for (i = 0; i < DEPTH; i = i + 1) begin
|
||||
// Make up data by multiplying a large prime with the address,
|
||||
// then cropping and retaining the lower bits
|
||||
mem[i] = PRIME * i;
|
||||
end
|
||||
end
|
||||
|
||||
reg [DEPTH_LOG2-1:0] counter = 0;
|
||||
reg done = 1'b0;
|
||||
|
||||
reg did_read = 1'b0;
|
||||
reg [DEPTH_LOG2-1:0] read_addr;
|
||||
reg [WIDTH-1:0] read_val;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (!done) begin
|
||||
did_read <= 1'b1;
|
||||
read_addr <= counter;
|
||||
read_val <= mem[counter];
|
||||
end else begin
|
||||
did_read <= 1'b0;
|
||||
end
|
||||
|
||||
if (!done)
|
||||
counter = counter + 1;
|
||||
if (counter == 0)
|
||||
done = 1;
|
||||
end
|
||||
|
||||
wire [WIDTH-1:0] expect_val = PRIME * read_addr;
|
||||
always @(posedge clk) begin
|
||||
if (did_read) begin
|
||||
$display("addr %x expected %x actual %x", read_addr, expect_val, read_val);
|
||||
assert(read_val == expect_val);
|
||||
end
|
||||
end
|
||||
endmodule
|
|
@ -0,0 +1,14 @@
|
|||
read_verilog -sv meminit.v
|
||||
chparam -set DEPTH_LOG2 3 -set WIDTH 36
|
||||
prep
|
||||
opt_dff
|
||||
prep -rdff
|
||||
synth_quicklogic -family qlf_k6n10f -run map_bram:map_bram
|
||||
select -assert-none t:$mem_v2 t:$mem
|
||||
select -assert-count 1 t:TDP36K
|
||||
select -assert-count 1 t:TDP36K a:is_split=0 %i
|
||||
select -assert-count 1 t:TDP36K a:was_split_candidate=0 %i
|
||||
read_verilog +/quicklogic/common/cells_sim.v +/quicklogic/qlf_k6n10f/cells_sim.v +/quicklogic/qlf_k6n10f/brams_sim.v +/quicklogic/qlf_k6n10f/sram1024x18_mem.v +/quicklogic/qlf_k6n10f/ufifo_ctl.v +/quicklogic/qlf_k6n10f/TDP18K_FIFO.v
|
||||
prep
|
||||
hierarchy -top top
|
||||
sim -assert -q -n 12 -clock clk
|
|
@ -0,0 +1,40 @@
|
|||
read_verilog ../../common/mux.v
|
||||
design -save read
|
||||
|
||||
hierarchy -top mux2
|
||||
proc
|
||||
equiv_opt -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd mux2 # Constrain all select calls below inside the top module
|
||||
select -assert-count 1 t:$lut r:WIDTH=3 %i
|
||||
select -assert-none t:$lut r:WIDTH=3 %i %% t:* %D
|
||||
|
||||
design -load read
|
||||
hierarchy -top mux4
|
||||
proc
|
||||
equiv_opt -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f # equivalency check
|
||||
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 1 t:$lut r:WIDTH=6 %i
|
||||
select -assert-none t:$lut r:WIDTH=6 %i %% t:* %D
|
||||
|
||||
design -load read
|
||||
hierarchy -top mux8
|
||||
proc
|
||||
equiv_opt -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd mux8 # Constrain all select calls below inside the top module
|
||||
select -assert-count 2 t:$lut r:WIDTH=6 %i
|
||||
select -assert-count 1 t:$lut r:WIDTH=3 %i
|
||||
select -assert-none t:$lut r:WIDTH=6 r:WIDTH=3 %u %i %% t:* %D
|
||||
|
||||
design -load read
|
||||
hierarchy -top mux16
|
||||
proc
|
||||
equiv_opt -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd mux16 # Constrain all select calls below inside the top module
|
||||
select -assert-max 5 t:$lut r:WIDTH=6 %i # OOT flow does 2
|
||||
select -assert-max 1 t:$lut r:WIDTH=3 %i # and here 1
|
||||
select -assert-max 1 t:$lut r:WIDTH=4 r:WIDTH=5 %u %i
|
||||
select -assert-none t:$lut r:WIDTH>2 %i %% t:* %D
|
|
@ -0,0 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
python3 mem_gen.py
|
||||
source ../../../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --bash
|
Loading…
Reference in New Issue