change ql-bram-types pass to use mode parameter; clean up primitive libraries

This commit is contained in:
N. Engelhardt 2023-08-14 16:20:36 +02:00 committed by Martin Povišer
parent 48c1fdc33d
commit 6682693888
13 changed files with 74503 additions and 74255 deletions

View File

@ -1,6 +1,6 @@
OBJS += techlibs/quicklogic/synth_quicklogic.o
OBJS += techlibs/quicklogic/ql-bram-merge.o
OBJS += techlibs/quicklogic/quicklogic_eqn.o
OBJS += techlibs/quicklogic/ql-bram-types.o
$(eval $(call add_share_file,share/quicklogic/common,techlibs/quicklogic/common/cells_sim.v))

View File

@ -31,184 +31,184 @@ PRIVATE_NAMESPACE_BEGIN
struct QlBramMergeWorker {
const RTLIL::IdString split_cell_type = ID($__QLF_TDP36K);
const RTLIL::IdString merged_cell_type = ID($__QLF_TDP36K_MERGED);
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;
// 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;
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);
}
}
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;
}
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) }
};
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;
}
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) }
};
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;
}
if(second)
return bram2_map;
else
return bram1_map;
}
void merge_brams(RTLIL::Cell* bram1, RTLIL::Cell* bram2)
{
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));
// 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 : 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);
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);
// 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());
}
}
}
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") {}
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 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");
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);
size_t argidx = 1;
extra_args(args, argidx, design);
for (RTLIL::Module* module : design->selected_modules())
{
QlBramMergeWorker worker(module);
worker.merge_bram_groups();
}
}
for (RTLIL::Module* module : design->selected_modules())
{
QlBramMergeWorker worker(module);
worker.merge_bram_groups();
}
}
} QlBramMergePass;

View File

@ -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

View File

@ -56,43 +56,43 @@ module _80_quicklogic_alu (A, B, CI, BI, X, Y, CO);
(* 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;
//assign CO[Y_WIDTH-1] = co;
generate
adder_carry intermediate_adder (
.cin ( ),
.cout (C[0]),
.p (1'b0),
.g (CI),
.sumout ()
);
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])
.cin (C[i]),
.g (AA[i]),
.p (S[i]),
.cout (C[i+1]),
.sumout (Y[i])
);
end
end
end endgenerate
generate
adder_carry final_adder (
.cin (C[Y_WIDTH-2]),
.cout (),
.p (1'b0),
.g (1'b0),
.sumout (co)
);
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 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 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

File diff suppressed because it is too large Load Diff

View File

@ -19,104 +19,104 @@
`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
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
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
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
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
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
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
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
initial Q = 1'b0;
always @(posedge C)
Q <= D;
specify
(posedge C => (Q +: D)) = 0;
$setuphold(posedge C, D, 0, 0);
endspecify
endmodule
@ -124,253 +124,253 @@ endmodule
(* blackbox *)
(* keep *)
module adder_carry(
output wire sumout,
(* abc9_carry *)
output wire cout,
input wire p,
input wire g,
(* abc9_carry *)
input wire cin
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
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
output reg Q,
input wire D,
(* clkbuf_sink *)
input wire C
);
initial Q <= 1'b0;
initial Q = 1'b0;
always @(posedge C)
Q <= D;
always @(posedge C)
Q <= D;
specify
(posedge C=>(Q+:D)) = 285;
$setuphold(posedge C, D, 56, 0);
endspecify
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
output reg Q,
input wire D,
(* clkbuf_sink *)
input wire C
);
initial Q <= 1'b0;
initial Q = 1'b0;
always @(negedge C)
Q <= D;
specify
(negedge C=>(Q+:D)) = 285;
$setuphold(negedge C, D, 56, 0);
endspecify
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
output reg Q,
input wire D,
(* clkbuf_sink *)
input wire C,
input wire E,
input wire R,
input wire S
);
initial Q <= 1'b0;
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;
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
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
output reg Q,
input wire D,
(* clkbuf_sink *)
input wire C,
input wire E,
input wire R,
input wire S
);
initial Q <= 1'b0;
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
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
output reg Q,
input wire D,
(* clkbuf_sink *)
input wire C,
input wire E,
input wire R,
input wire S
);
initial Q <= 1'b0;
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
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
output reg Q,
input wire D,
(* clkbuf_sink *)
input wire C,
input wire E,
input wire R,
input wire S
);
initial Q <= 1'b0;
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
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
output reg Q,
input wire S,
input wire R,
input wire D,
input wire G,
input wire E
);
initial Q <= 1'b0;
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
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
output reg Q,
input wire S,
input wire R,
input wire D,
input wire G,
input wire E
);
initial Q <= 1'b0;
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
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

View File

@ -16,116 +16,116 @@
// 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));
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));
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));
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));
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));
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));
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));
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));
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));
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));
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;
input D;
input C;
output Q;
parameter DEPTH = 2;
parameter DEPTH = 2;
reg [DEPTH-2:0] q;
reg [DEPTH-2:0] q;
genvar i;
generate for (i = 0; i < DEPTH; i = i + 1) begin: slice
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
// 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

View File

@ -0,0 +1,246 @@
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;
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)) 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;
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)) 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)

View File

@ -1,100 +0,0 @@
/*
* 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
struct QuicklogicEqnPass : public Pass {
QuicklogicEqnPass() : Pass("quicklogic_eqn", "Quicklogic: Calculate equations for luts") {}
void help() override
{
log("\n");
log(" quicklogic_eqn [selection]\n");
log("\n");
log("Calculate equations for luts since bitstream generator depends on it.\n");
log("\n");
}
Const init2eqn(Const init, int inputs)
{
std::string init_bits = init.as_string();
const char *names[] = {"I0", "I1", "I2", "I3", "I4"};
std::string eqn;
int width = (int)pow(2, inputs);
for (int i = 0; i < width; i++) {
if (init_bits[width - 1 - i] == '1') {
eqn += "(";
for (int j = 0; j < inputs; j++) {
if (i & (1 << j))
eqn += names[j];
else
eqn += std::string("~") + names[j];
if (j != (inputs - 1))
eqn += "*";
}
eqn += ")+";
}
}
if (eqn.empty())
return Const("0");
eqn = eqn.substr(0, eqn.length() - 1);
return Const(eqn);
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing Quicklogic_EQN pass (calculate equations for luts).\n");
extra_args(args, args.size(), design);
int cnt = 0;
for (auto module : design->selected_modules()) {
for (auto cell : module->selected_cells()) {
if (cell->type == ID(LUT1)) {
cell->setParam(ID(EQN), init2eqn(cell->getParam(ID::INIT), 1));
cnt++;
}
if (cell->type == ID(LUT2)) {
cell->setParam(ID(EQN), init2eqn(cell->getParam(ID::INIT), 2));
cnt++;
}
if (cell->type == ID(LUT3)) {
cell->setParam(ID(EQN), init2eqn(cell->getParam(ID::INIT), 3));
cnt++;
}
if (cell->type == ID(LUT4)) {
cell->setParam(ID(EQN), init2eqn(cell->getParam(ID::INIT), 4));
cnt++;
}
if (cell->type == ID(LUT5)) {
cell->setParam(ID(EQN), init2eqn(cell->getParam(ID::INIT), 5));
cnt++;
}
}
}
log_header(design, "Updated %d of LUT* elements with equation.\n", cnt);
}
} QuicklogicEqnPass;
PRIVATE_NAMESPACE_END

View File

@ -129,10 +129,6 @@ struct SynthQuickLogicPass : public ScriptPass {
blif_file = args[++argidx];
continue;
}
if (args[argidx] == "-edif" && argidx + 1 < args.size()) {
edif_file = args[++argidx];
continue;
}
if (args[argidx] == "-verilog" && argidx+1 < args.size()) {
verilog_file = args[++argidx];
continue;
@ -141,15 +137,15 @@ struct SynthQuickLogicPass : public ScriptPass {
abc9 = false;
continue;
}
if (args[argidx] == "-nocarry") {
if (args[argidx] == "-nocarry" || args[argidx] == "-no_adder") {
inferAdder = false;
continue;
}
if (args[argidx] == "-nobram") {
if (args[argidx] == "-nobram" || args[argidx] == "-no_bram") {
nobram = true;
continue;
}
if (args[argidx] == "-bramtypes") {
if (args[argidx] == "-bramtypes" || args[argidx] == "-bram_types") {
bramTypes = true;
continue;
}
@ -230,61 +226,8 @@ struct SynthQuickLogicPass : public ScriptPass {
run("techmap -autoproc -map " + lib_path + family + "/brams_map.v");
run("techmap -map " + lib_path + family + "/brams_final_map.v");
if (help_mode) {
run("chtype -set TDP36K_<mode> t:TDP36K a:<mode>", "(if -bram_types)");
}
else if (bramTypes) {
for (int a_dwidth : {1, 2, 4, 9, 18, 36})
for (int b_dwidth: {1, 2, 4, 9, 18, 36}) {
run(stringf("chtype -set TDP36K_BRAM_A_X%d_B_X%d_nonsplit t:TDP36K a:is_inferred=0 %%i "
"a:is_fifo=0 %%i a:port_a_dwidth=%d %%i a:port_b_dwidth=%d %%i",
a_dwidth, b_dwidth, a_dwidth, b_dwidth));
run(stringf("chtype -set TDP36K_FIFO_ASYNC_A_X%d_B_X%d_nonsplit t:TDP36K a:is_inferred=0 %%i "
"a:is_fifo=1 %%i a:sync_fifo=0 %%i a:port_a_dwidth=%d %%i a:port_b_dwidth=%d %%i",
a_dwidth, b_dwidth, a_dwidth, b_dwidth));
run(stringf("chtype -set TDP36K_FIFO_SYNC_A_X%d_B_X%d_nonsplit t:TDP36K a:is_inferred=0 %%i "
"a:is_fifo=1 %%i a:sync_fifo=1 %%i a:port_a_dwidth=%d %%i a:port_b_dwidth=%d %%i",
a_dwidth, b_dwidth, a_dwidth, b_dwidth));
}
for (int a1_dwidth : {1, 2, 4, 9, 18})
for (int b1_dwidth: {1, 2, 4, 9, 18})
for (int a2_dwidth : {1, 2, 4, 9, 18})
for (int b2_dwidth: {1, 2, 4, 9, 18}) {
run(stringf("chtype -set TDP36K_BRAM_A1_X%d_B1_X%d_A2_X%d_B2_X%d_split t:TDP36K a:is_inferred=0 %%i "
"a:is_split=1 %%i a:is_fifo=0 %%i "
"a:port_a1_dwidth=%d %%i a:port_b1_dwidth=%d %%i a:port_a2_dwidth=%d %%i a:port_b2_dwidth=%d %%i",
a1_dwidth, b1_dwidth, a2_dwidth, b2_dwidth, a1_dwidth, b1_dwidth, a2_dwidth, b2_dwidth));
run(stringf("chtype -set TDP36K_FIFO_ASYNC_A1_X%d_B1_X%d_A2_X%d_B2_X%d_split t:TDP36K a:is_inferred=0 %%i "
"a:is_split=1 %%i a:is_fifo=1 %%i a:sync_fifo=0 %%i "
"a:port_a1_dwidth=%d %%i a:port_b1_dwidth=%d %%i a:port_a2_dwidth=%d %%i a:port_b2_dwidth=%d %%i",
a1_dwidth, b1_dwidth, a2_dwidth, b2_dwidth, a1_dwidth, b1_dwidth, a2_dwidth, b2_dwidth));
run(stringf("chtype -set TDP36K_FIFO_SYNC_A1_X%d_B1_X%d_A2_X%d_B2_X%d_split t:TDP36K a:is_inferred=0 %%i "
"a:is_split=1 %%i a:is_fifo=1 %%i a:sync_fifo=1 %%i "
"a:port_a1_dwidth=%d %%i a:port_b1_dwidth=%d %%i a:port_a2_dwidth=%d %%i a:port_b2_dwidth=%d %%i",
a1_dwidth, b1_dwidth, a2_dwidth, b2_dwidth, a1_dwidth, b1_dwidth, a2_dwidth, b2_dwidth));
}
for (int a_width : {1, 2, 4, 9, 18, 36})
for (int b_width: {1, 2, 4, 9, 18, 36}) {
run(stringf("chtype -set TDP36K_BRAM_A_X%d_B_X%d_nonsplit t:TDP36K a:is_inferred=1 %%i "
"a:port_a_width=%d %%i a:port_b_width=%d %%i",
a_width, b_width, a_width, b_width));
}
for (int a1_width : {1, 2, 4, 9, 18})
for (int b1_width: {1, 2, 4, 9, 18})
for (int a2_width : {1, 2, 4, 9, 18})
for (int b2_width: {1, 2, 4, 9, 18}) {
run(stringf("chtype -set TDP36K_BRAM_A1_X%d_B1_X%d_A2_X%d_B2_X%d_split t:TDP36K a:is_inferred=1 %%i "
"a:port_a1_width=%d %%i a:port_b1_width=%d %%i a:port_a2_width=%d %%i a:port_b2_width=%d %%i",
a1_width, b1_width, a2_width, b2_width, a1_width, b1_width, a2_width, b2_width));
}
if (help_mode || bramTypes) {
run("ql_bram_types");
}
}
@ -393,13 +336,6 @@ struct SynthQuickLogicPass : public ScriptPass {
run(stringf("write_verilog -noattr -nohex %s", help_mode ? "<file-name>" : verilog_file.c_str()));
}
}
if (check_label("edif", "(if -edif)")) {
if (!edif_file.empty() || help_mode) {
run("splitnets -ports -format ()");
run(stringf("write_edif -nogndvcc -attrprop -pvector par %s %s", top_opt.c_str(), edif_file.c_str()));
}
}
}
} SynthQuicklogicPass;