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

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

@ -1,5 +1,6 @@
// **AUTOGENERATED FILE** **DO NOT EDIT**
// Generated by qlf_k6n10f/generate_bram_types_sim.py at 2023-05-02 10:42:53.971682+00:00
// Generated by generate_bram_types_sim.py at 2023-08-17 16:34:43.930013+00:00
`timescale 1ns /10ps
module TDP36K_BRAM_A_X1_B_X1_nonsplit (
RESET_ni,

View File

@ -982,10 +982,10 @@ assign BE_A2_i = WR2_BE;
assign REN_B1_i = REN1_i;
assign WEN_B1_i = 1'b0;
assign BE_B1_i = 4'h0;
assign BE_B1_i = 2'h0;
assign REN_B2_i = REN2_i;
assign WEN_B2_i = 1'b0;
assign BE_B2_i = 4'h0;
assign BE_B2_i = 2'h0;
generate
if (WR1_DATA_WIDTH == 18) begin
@ -1394,10 +1394,10 @@ assign BE_A2_i = WR2_BE;
assign REN_B1_i = REN1_i;
assign WEN_B1_i = 1'b0;
assign BE_B1_i = 4'h0;
assign BE_B1_i = 2'h0;
assign REN_B2_i = REN2_i;
assign WEN_B2_i = 1'b0;
assign BE_B2_i = 4'h0;
assign BE_B2_i = 2'h0;
generate
if (WR1_DATA_WIDTH == 18) begin

View File

@ -109,7 +109,7 @@ module sh_dff(
input wire C
);
initial Q <= 1'b0;
initial Q = 1'b0;
always @(posedge C)
Q <= D;
@ -153,7 +153,7 @@ module dff(
(* clkbuf_sink *)
input wire C
);
initial Q <= 1'b0;
initial Q = 1'b0;
always @(posedge C)
Q <= D;
@ -172,7 +172,7 @@ module dffn(
(* clkbuf_sink *)
input wire C
);
initial Q <= 1'b0;
initial Q = 1'b0;
always @(negedge C)
Q <= D;
@ -194,7 +194,7 @@ module dffsre(
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)
@ -228,7 +228,7 @@ module dffnsre(
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)
@ -262,7 +262,7 @@ module sdffsre(
input wire R,
input wire S
);
initial Q <= 1'b0;
initial Q = 1'b0;
always @(posedge C)
if (!R)
@ -292,7 +292,7 @@ module sdffnsre(
input wire R,
input wire S
);
initial Q <= 1'b0;
initial Q = 1'b0;
always @(negedge C)
if (!R)
@ -321,7 +321,7 @@ module latchsre (
input wire G,
input wire E
);
initial Q <= 1'b0;
initial Q = 1'b0;
always @*
begin
@ -352,7 +352,7 @@ module latchnsre (
input wire G,
input wire E
);
initial Q <= 1'b0;
initial Q = 1'b0;
always @*
begin

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;