3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-24 01:25:33 +00:00

Merge pull request #4474 from tony-min-1/mchp

Add PolarFire FPGA support
This commit is contained in:
N. Engelhardt 2024-07-29 15:28:44 +02:00 committed by GitHub
commit 9f869b265c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 4620 additions and 0 deletions

View file

@ -0,0 +1,191 @@
# ISC License
#
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# LSRAM true dual-port
ram block $__LSRAM_TDP_ {
# Cost of a given cell is assumed to be:
# (cost-widthscale) + [widthscale * (used_bits/14)]
cost 129;
# INIT is supported
init any;
# port A and port B are allowed to have different widths, but they MUST have
# WIDTH values of the same set.
# Example: Port A has a Data Width of 1. Then Port B's Data Width must be either
# 1, 2, 4, 8, or 16 (both values are in the 'WIDTH_1' set).
# WIDTH_1 = {1, 2, 4, 8, 16}
# WIDTH_2 = {5, 10, 20}
# "byte" specifies how many data bits correspond to one write enable bit.
# "byte" must be larger than width, or width must be a multipler of "byte"
# if "byte" > WIDTH, a single enable wire is inferred
# otherwise, WIDTH/byte number of enable wires are inferred
#
# WIDTH = {1, 2, 4, 5, 8, 10} requires 1 enable wire
# WIDTH = {16, 20} requires 2 enable wire
option "WIDTH_CONFIG" "REGULAR" {
# Data-Width| Address bits
# 1 | 14
# 2 | 13
# 4 | 12
# 8 | 11
# 16 | 10
# 14 address bits
abits 14;
widths 1 2 4 8 16 per_port;
byte 8;
}
option "WIDTH_CONFIG" "ALIGN" {
# Data-Width| Address bits
# 5 | 12
# 10 | 11
# 20 | 10
# Quick "hack" to fix address bit alignment by setting address bits to 12.
# If abits=14, tool will think there are 14 bits for width=5, 13 bits for width=10, 12 bits for width=20
# THe LSRAM_map.v file detects if this option is being used, and adjusts the address port alignments accordingly.
abits 12;
widths 5 10 20 per_port;
byte 10;
}
port srsw "A" "B" {
# read & write width must be same
width tied;
# clock polarity is rising
clock posedge;
# A/B read-enable
rden;
# initial value of read port data (not supported)
rdinit none;
# write modes (<A/B>_WMODE)
# 1. Simple Write: read-data port holds prev value (similar to "NO_CHANGE" for RAMB18E1)
# 2. Feed-through: read-data port takes new write value (similar to "WRITE_FIRST" for RAMB18E1)
# 3. Read-Before-Write: read-data port holds old value while being written (similar to "READ_FIRST" for RAMB18E1)
portoption "WRITE_MODE" "NO_CHANGE" {
# Read-write interaction
rdwr no_change;
# Write transparency:
# For write ports, define behaviour when another synchronous read port
# reads from the same memory cell that said write port is writing to at the same time.
wrtrans all old;
}
portoption "WRITE_MODE" "WRITE_FIRST" {
# bits corresponding to high A/B_WEN are updated
rdwr new_only;
wrtrans all new;
}
portoption "WRITE_MODE" "READ_FIRST" {
rdwr old;
wrtrans all old;
}
# generate params to indicate if read or write is used for each port
optional_rw;
}
}
# two-port configuration
ram block $__LSRAM_SDP_ {
# since two-port configuration is dedicated for wide-read/write,
# we want to prioritize this configuration over TDP to avoid tool picking multiple TDP RAMs
# inplace of a single SDP RAM for wide read/write. This means the cost of a single SDP should
# be less than 2 TDP.
cost 129;
init any;
option "WIDTH_CONFIG" "REGULAR" {
# Data-Width| Address bits
# 1 | 14
# 2 | 13
# 4 | 12
# 8 | 11
# 16 | 10
# 32 | 9
abits 14;
widths 1 2 4 8 16 32 per_port;
# width = 32, byte-write size is 8, ignore other widths
byte 8;
}
option "WIDTH_CONFIG" "ALIGN" {
# Data-Width| Address bits
# 5 | 12
# 10 | 11
# 20 | 10
# 40 | 9
# Same trick as TSP RAM for alignment
abits 12;
widths 5 10 20 40 per_port;
byte 10;
}
port sw "W" {
# only consider wide write
option "WIDTH_CONFIG" "REGULAR" width 32;
option "WIDTH_CONFIG" "ALIGN" width 40;
clock posedge;
# only simple write supported for two-port mode
wrtrans all old;
optional;
}
port sr "R" {
option "WIDTH_CONFIG" "REGULAR" width 32;
option "WIDTH_CONFIG" "ALIGN" width 40;
clock posedge;
rden;
rdinit none;
optional;
}
}

View file

@ -0,0 +1,320 @@
/*
ISC License
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// See document PolarFire Family Fabric User Guide
// section 4.1 for port list.
//LSRAM true dual-port
module $__LSRAM_TDP_ (...);
parameter INIT = 0;
parameter ADDR_BITS = 14;
parameter OPTION_WIDTH_CONFIG = "A";
parameter PORT_A_WIDTH = 1;
parameter PORT_A_WR_EN_WIDTH = 1;
parameter PORT_A_RD_USED = 0;
parameter PORT_A_WR_USED = 0;
parameter PORT_A_OPTION_WRITE_MODE = "NO_CHANGE";
parameter PORT_B_WIDTH = 1;
parameter PORT_B_WR_EN_WIDTH = 1;
parameter PORT_B_RD_USED = 0;
parameter PORT_B_WR_USED = 0;
parameter PORT_B_OPTION_WRITE_MODE = "NO_CHANGE";
input PORT_A_CLK;
input PORT_A_RD_EN;
input [ADDR_BITS-1:0] PORT_A_ADDR;
input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA;
input [PORT_A_WR_EN_WIDTH-1:0] PORT_A_WR_EN;
output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA;
input PORT_B_CLK;
input PORT_B_RD_EN;
input [ADDR_BITS-1:0] PORT_B_ADDR;
input [PORT_B_WIDTH-1:0] PORT_B_WR_DATA;
input [PORT_B_WR_EN_WIDTH-1:0] PORT_B_WR_EN;
output [PORT_B_WIDTH-1:0] PORT_B_RD_DATA;
`include "brams_defs.vh"
// address wires
wire [ADDR_BITS-1:0] A_address;
wire [ADDR_BITS-1:0] B_address;
assign A_address = (OPTION_WIDTH_CONFIG == "REGULAR") ? PORT_A_ADDR : {PORT_A_ADDR, 2'b00};
assign B_address = (OPTION_WIDTH_CONFIG == "REGULAR") ? PORT_B_ADDR : {PORT_B_ADDR, 2'b00};
// if port is not used, set block sel to 0 to disable it (read-data output is set to 0)
parameter PORT_A_RD_USED = 0;
parameter PORT_A_WR_USED = 0;
wire [2:0] A_BLK_SEL = (PORT_A_RD_USED == 1 || PORT_A_WR_USED == 1) ? 3'b111 : 3'b000;
wire [2:0] B_BLK_SEL = (PORT_B_RD_USED == 1 || PORT_B_WR_USED == 1) ? 3'b111 : 3'b000;
// wires for write data
generate
wire [19:0] A_write_data;
wire [19:0] B_write_data;
if (PORT_A_WIDTH == 16) begin
assign A_write_data[7:0] = PORT_A_WR_DATA[7:0];
assign A_write_data[17:10] = PORT_A_WR_DATA[15:8];
assign A_write_data[9:8] = 2'b0;
assign A_write_data[19:18] = 2'b0;
end else begin
assign A_write_data[PORT_A_WIDTH-1:0] = PORT_A_WR_DATA;
end
if (PORT_B_WIDTH == 16) begin
assign B_write_data[7:0] = PORT_B_WR_DATA[7:0];
assign B_write_data[17:10] = PORT_B_WR_DATA[15:8];
assign B_write_data[9:8] = 2'b0;
assign B_write_data[19:18] = 2'b0;
end else begin
assign B_write_data[PORT_B_WIDTH-1:0] = PORT_B_WR_DATA;
end
endgenerate
// wires for read data
wire [19:0] A_read_data;
assign PORT_A_RD_DATA = A_read_data[PORT_A_WIDTH-1:0];
wire [19:0] B_read_data;
assign PORT_B_RD_DATA = B_read_data[PORT_B_WIDTH-1:0];
// byte-write enables
wire [1:0] A_write_EN = (PORT_A_WR_EN_WIDTH == 1) ? {1'b0, PORT_A_WR_EN} : PORT_A_WR_EN;
wire [1:0] B_write_EN = (PORT_B_WR_EN_WIDTH == 1) ? {1'b0, PORT_B_WR_EN} : PORT_B_WR_EN;
// port width
wire [2:0] A_width = (PORT_A_WIDTH == 1) ? 3'b000 :
(PORT_A_WIDTH == 2) ? 3'b001 :
(PORT_A_WIDTH == 4 || PORT_A_WIDTH == 5) ? 3'b010 :
(PORT_A_WIDTH == 8 || PORT_A_WIDTH == 10) ? 3'b011 : 3'b100;
wire [2:0] B_width = (PORT_B_WIDTH == 1) ? 3'b000 :
(PORT_B_WIDTH == 2) ? 3'b001 :
(PORT_B_WIDTH == 4 || PORT_B_WIDTH == 5) ? 3'b010 :
(PORT_B_WIDTH == 8 || PORT_B_WIDTH == 10) ? 3'b011 : 3'b100;
// write modes
wire [1:0] A_write_mode = PORT_A_OPTION_WRITE_MODE == "NO_CHANGE" ? 2'b00 :
PORT_A_OPTION_WRITE_MODE == "WRITE_FIRST" ? 2'b01 : 2'b10;
wire [1:0] B_write_mode = PORT_B_OPTION_WRITE_MODE == "NO_CHANGE" ? 2'b00 :
PORT_B_OPTION_WRITE_MODE == "WRITE_FIRST" ? 2'b01 : 2'b10;
RAM1K20 #(
`PARAMS_INIT_LSRAM
) _TECHMAP_REPLACE_ (
// port A
.A_ADDR(A_address),
.A_BLK_EN(A_BLK_SEL),
.A_CLK(PORT_A_CLK),
.A_DIN(A_write_data),
.A_DOUT(A_read_data),
.A_WEN(A_write_EN),
.A_REN(PORT_A_RD_EN),
.A_WIDTH(A_width),
.A_WMODE(A_write_mode),
.A_BYPASS(1'b1),
.A_DOUT_EN(1'b1),
.A_DOUT_SRST_N(1'b1),
.A_DOUT_ARST_N(1'b1),
// port B
.B_ADDR(B_address),
.B_BLK_EN(B_BLK_SEL),
.B_CLK(PORT_B_CLK),
.B_DIN(B_write_data),
.B_DOUT(B_read_data),
.B_WEN(B_write_EN),
.B_REN(PORT_B_RD_EN),
.B_WIDTH(B_width),
.B_WMODE(B_write_mode),
.B_BYPASS(1'b1),
.B_DOUT_EN(1'b1),
.B_DOUT_SRST_N(1'b1),
.B_DOUT_ARST_N(1'b1),
// Disable ECC for TDP
.ECC_EN(1'b0),
.ECC_BYPASS(1'b1),
.BUSY_FB(1'b0)
);
endmodule
// single dual port configuration
module $__LSRAM_SDP_ (...);
parameter INIT = 0;
parameter OPTION_WIDTH_CONFIG = "REGULAR";
parameter ADDR_BITS = 14;
parameter PORT_W_WIDTH = 1;
parameter PORT_W_WR_EN_WIDTH = 4;
parameter PORT_W_USED = 1;
parameter PORT_R_WIDTH = 1;
parameter PORT_R_USED = 0;
input PORT_W_CLK;
input [ADDR_BITS-1:0] PORT_W_ADDR;
input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
input [PORT_W_WR_EN_WIDTH-1:0] PORT_W_WR_EN;
input PORT_R_CLK;
input PORT_R_RD_EN;
input [ADDR_BITS-1:0] PORT_R_ADDR;
output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA;
input PORT_R_RD_SRST;
`include "brams_defs.vh"
// address wires
wire [ADDR_BITS-1:0] A_address;
wire [ADDR_BITS-1:0] B_address;
assign A_address = (OPTION_WIDTH_CONFIG == "REGULAR") ? PORT_R_ADDR : {PORT_R_ADDR, 2'b00};
assign B_address = (OPTION_WIDTH_CONFIG == "REGULAR") ? PORT_W_ADDR : {PORT_W_ADDR, 2'b00};
// if port is not used, set block sel to 0 to disable it (read-data output is set to 0)
// port A is for read, port B for write
parameter PORT_W_USED = 0;
parameter PORT_R_USED = 0;
wire [2:0] A_BLK_SEL = (PORT_R_USED == 1) ? 3'b111 : 3'b000;
wire [2:0] B_BLK_SEL = (PORT_W_USED == 1) ? 3'b111 : 3'b000;
// read/write data & write enables
// Currently support only wide write, width = {32, 40}
generate
wire [19:0] A_write_data;
wire [19:0] B_write_data;
wire [1:0] A_write_EN;
wire [1:0] B_write_EN;
// write port (A provides MSB)
if (PORT_W_WIDTH == 32) begin
assign B_write_data[3:0] = PORT_W_WR_DATA[3:0];
assign B_write_data[8:5] = PORT_W_WR_DATA[7:4];
assign B_write_data[13:10] = PORT_W_WR_DATA[11:8];
assign B_write_data[18:15] = PORT_W_WR_DATA[15:12];
assign B_write_data[4] = 1'b0;
assign B_write_data[9] = 1'b0;
assign B_write_data[14] = 1'b0;
assign B_write_data[19] = 1'b0;
assign A_write_data[3:0] = PORT_W_WR_DATA[19:16];
assign A_write_data[8:5] = PORT_W_WR_DATA[23:20];
assign A_write_data[13:10] = PORT_W_WR_DATA[27:24];
assign A_write_data[18:15] = PORT_W_WR_DATA[31:28];
assign A_write_data[4] = 1'b0;
assign A_write_data[9] = 1'b0;
assign A_write_data[14] = 1'b0;
assign A_write_data[19] = 1'b0;
end else if (PORT_W_WIDTH == 40) begin
assign B_write_data = PORT_W_WR_DATA[19:0];
assign A_write_data = PORT_W_WR_DATA[39:20];
end
// byte-write enables
assign A_write_EN = PORT_W_WR_EN[1:0];
assign B_write_EN = PORT_W_WR_EN[3:2];
// read ports (A provides MSB)
wire [19:0] A_read_data;
wire [19:0] B_read_data;
if (PORT_R_WIDTH == 32) begin
assign PORT_R_RD_DATA[3:0] = B_read_data[3:0];
assign PORT_R_RD_DATA[8:5] = B_read_data[7:4];
assign PORT_R_RD_DATA[13:10] = B_read_data[11:8];
assign PORT_R_RD_DATA[18:15] = B_read_data[15:12];
assign PORT_R_RD_DATA[19:16] = A_read_data[3:0];
assign PORT_R_RD_DATA[23:20] = A_read_data[8:5];
assign PORT_R_RD_DATA[27:24] = A_read_data[13:10];
assign PORT_R_RD_DATA[31:28] = A_read_data[18:15];
end else if (PORT_R_WIDTH == 40) begin
assign PORT_R_RD_DATA[19:0] = B_read_data[19:0];
assign PORT_R_RD_DATA[39:20] = A_read_data[19:0];
end
endgenerate
// port width
wire [2:0] A_width = (PORT_R_WIDTH == 1) ? 3'b000 :
(PORT_R_WIDTH == 2) ? 3'b001 :
(PORT_R_WIDTH == 4 || PORT_R_WIDTH == 5) ? 3'b010 :
(PORT_R_WIDTH == 8 || PORT_R_WIDTH == 10) ? 3'b011 :
(PORT_R_WIDTH == 16 || PORT_R_WIDTH == 20) ? 3'b100 : 3'b101;
wire [2:0] B_width = (PORT_W_WIDTH == 1) ? 3'b000 :
(PORT_W_WIDTH == 2) ? 3'b001 :
(PORT_W_WIDTH == 4 || PORT_W_WIDTH == 5) ? 3'b010 :
(PORT_W_WIDTH == 8 || PORT_W_WIDTH == 10) ? 3'b011 :
(PORT_W_WIDTH == 16 || PORT_W_WIDTH == 20) ? 3'b100 : 3'b101;
// write modes
wire [1:0] A_write_mode = 2'b00;
wire [1:0] B_write_mode = 2'b00;
RAM1K20 #(
`PARAMS_INIT_LSRAM
) _TECHMAP_REPLACE_ (
// port A - read
.A_ADDR(A_address),
.A_BLK_EN(A_BLK_SEL),
.A_CLK(PORT_R_CLK),
.A_DIN(A_write_data),
.A_DOUT(A_read_data),
.A_WEN(A_write_EN),
.A_REN(PORT_R_RD_EN),
.A_WIDTH(A_width),
.A_WMODE(A_write_mode),
.A_BYPASS(1'b1),
.A_DOUT_EN(1'b1),
.A_DOUT_SRST_N(1'b1),
.A_DOUT_ARST_N(1'b1),
// port B - write
.B_ADDR(B_address),
.B_BLK_EN(B_BLK_SEL),
.B_CLK(PORT_W_CLK),
.B_DIN(B_write_data),
.B_DOUT(B_read_data),
.B_WEN(B_write_EN),
.B_REN(PORT_R_RD_EN),
.B_WIDTH(B_width),
.B_WMODE(B_write_mode),
.B_BYPASS(1'b1),
.B_DOUT_EN(1'b1),
.B_DOUT_SRST_N(1'b1),
.B_DOUT_ARST_N(1'b1),
// Disable ECC for SDP
.ECC_EN(1'b0),
.ECC_BYPASS(1'b1),
.BUSY_FB(1'b0)
);
endmodule

View file

@ -0,0 +1,31 @@
# ISC License
#
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
OBJS += techlibs/microchip/synth_microchip.o
OBJS += techlibs/microchip/microchip_dffopt.o
$(eval $(call add_share_file,share/microchip,techlibs/microchip/arith_map.v))
$(eval $(call add_share_file,share/microchip,techlibs/microchip/cells_map.v))
$(eval $(call add_share_file,share/microchip,techlibs/microchip/cells_sim.v))
$(eval $(call add_share_file,share/microchip,techlibs/microchip/polarfire_dsp_map.v))
$(eval $(call add_share_file,share/microchip,techlibs/microchip/brams_defs.vh))
$(eval $(call add_share_file,share/microchip,techlibs/microchip/LSRAM_map.v))
$(eval $(call add_share_file,share/microchip,techlibs/microchip/LSRAM.txt))
$(eval $(call add_share_file,share/microchip,techlibs/microchip/uSRAM_map.v))
$(eval $(call add_share_file,share/microchip,techlibs/microchip/uSRAM.txt))

View file

@ -0,0 +1,105 @@
/*
ISC License
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// Based on Macro Library for PolarFire https://coredocs.s3.amazonaws.com/Libero/2021_2/Tool/pf_mlg.pdf
// NOTE: prefix module names with \$__ so that mapping prioritizes these cells over internal Yosys cells
(* techmap_celltype = "$_MUX4_" *)
module \$__microchip_MUX4_ (A, B, C, D, S, T, Y);
input A, B, C, D, S, T;
output Y;
MX4 _TECHMAP_REPLACE_.MUX4(.D3(D), .D2(C), .D1(B), .D0(A), .S1(T), .S0(S), .Y(Y));
endmodule
(* techmap_celltype = "$reduce_xor" *)
module \$__microchip_XOR8_ (A, Y);
parameter A_SIGNED = 1;
parameter A_WIDTH = 8;
parameter Y_WIDTH = 1;
input [A_WIDTH-1:0] A;
output [Y_WIDTH-1:0] Y;
// check if mapping should proceed
generate
if (A_WIDTH != 8 || A_SIGNED || Y_WIDTH != 1) begin
wire _TECHMAP_FAIL_ = 1;
end
endgenerate
XOR8 _TECHMAP_REPLACE_.XOR8 (.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]), .E(A[4]), .F(A[5]), .G(A[6]), .H(A[7]), .Y(Y));
endmodule
(* techmap_celltype = "$alu" *)
module \$__SF2_ALU (A, B, CI, BI, X, Y, CO);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 1;
parameter B_WIDTH = 1;
parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] X, Y;
input CI, BI;
(* force_downto *)
output [Y_WIDTH-1:0] CO;
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
(* force_downto *)
wire [Y_WIDTH-1:0] AA, BB;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(AA));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(BB));
(* force_downto *)
wire [Y_WIDTH-1:0] C = {CO, CI};
genvar i;
generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
ARI1 #(
// See section 1.4 of PolarFire Macro Library
// G = F1 = A[i] & (B[i]^BI)
// Y = F0 = A[i]^B[i]^BI
// P = Y
// ADCB
.INIT(20'b 01_11_0010_1000_1001_0110)
) carry (
.A(1'b0),
.B(AA[i]),
.C(BB[i]),
.D(BI),
.FCI(C[i]),
.Y(X[i]),
.S(Y[i]),
.FCO(CO[i])
);
end endgenerate
endmodule

View file

@ -0,0 +1,69 @@
/*
ISC License
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
`define PARAMS_INIT_LSRAM \
.INIT0(slice_init_LSRAM(00)), \
.INIT1(slice_init_LSRAM(01)), \
.INIT2(slice_init_LSRAM(02)), \
.INIT3(slice_init_LSRAM(03)), \
.INIT4(slice_init_LSRAM(04)), \
.INIT5(slice_init_LSRAM(05)), \
.INIT6(slice_init_LSRAM(06)), \
.INIT7(slice_init_LSRAM(07)), \
.INIT8(slice_init_LSRAM(08)), \
.INIT9(slice_init_LSRAM(09)), \
.INIT10(slice_init_LSRAM(10)), \
.INIT11(slice_init_LSRAM(11)), \
.INIT12(slice_init_LSRAM(12)), \
.INIT13(slice_init_LSRAM(13)), \
.INIT14(slice_init_LSRAM(14)), \
.INIT15(slice_init_LSRAM(15)), \
.INIT16(slice_init_LSRAM(16)), \
.INIT17(slice_init_LSRAM(17)), \
.INIT18(slice_init_LSRAM(18)), \
.INIT19(slice_init_LSRAM(19))
`define PARAMS_INIT_uSRAM \
.INIT0(slice_init_uSRAM(00)), \
.INIT1(slice_init_uSRAM(01)), \
.INIT2(slice_init_uSRAM(02)), \
.INIT3(slice_init_uSRAM(03)), \
.INIT4(slice_init_uSRAM(04)), \
.INIT5(slice_init_uSRAM(05)), \
.INIT6(slice_init_uSRAM(06)), \
.INIT7(slice_init_uSRAM(07)), \
.INIT8(slice_init_uSRAM(08)), \
.INIT9(slice_init_uSRAM(09)), \
.INIT10(slice_init_uSRAM(10)), \
.INIT11(slice_init_uSRAM(11)) \
// Helper function for initializing the LSRAM
function [1023:0] slice_init_LSRAM;
input integer slice_idx;
integer i;
for (i = 0; i < 1024; i = i + 1)
slice_init_LSRAM[i] = INIT[(slice_idx * 1024 + i)];
endfunction
// Helper function for initializing the uSRAM
function [63:0] slice_init_uSRAM;
input integer slice_idx;
integer i;
for (i = 0; i < 64; i = i + 1)
slice_init_uSRAM[i] = INIT[(slice_idx * 64 + i)];
endfunction

View file

@ -0,0 +1,104 @@
/*
ISC License
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// DFFs
module \$_DFFE_PN0P_ (input D, C, R, E, output Q);
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(E), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
endmodule
module \$_DFFE_PN1P_ (input D, C, R, E, output Q);
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(E), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
endmodule
// for sync set/reset registers, we can pass them into ABC9. So we need to follow the simplification idiom
// and map to intermediate cell types
module \$_SDFFCE_PN0P_ (input D, C, R, E, output Q);
MICROCHIP_SYNC_RESET_DFF _TECHMAP_REPLACE_ (.D(D), .CLK(C), .Reset(R), .En(E), .Q(Q));
endmodule
module \$_SDFFCE_PN1P_ (input D, C, R, E, output Q);
MICROCHIP_SYNC_SET_DFF _TECHMAP_REPLACE_ (.D(D), .CLK(C), .Set(R), .En(E), .Q(Q));
endmodule
// LATCHES
module \$_DLATCH_PN0_ (input D, R, E, output Q);
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(E), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b1), .Q(Q));
endmodule
module \$_DLATCH_PN1_ (input D, R, E, output Q);
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(E), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b1), .Q(Q));
endmodule
module \$_DLATCH_P_ (input D, E, output Q);
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(E), .EN(1'b1), .ALn(1'b1), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b1), .Q(Q));
endmodule
// map intermediate flops to SLE
`ifdef FINAL_MAP
module MICROCHIP_SYNC_SET_DFF(
input D,
input CLK,
input Set,
input En,
output Q);
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(CLK), .EN(En), .ALn(1'b1), .ADn(1'b0), .SLn(Set), .SD(1'b1), .LAT(1'b0), .Q(Q));
endmodule
module MICROCHIP_SYNC_RESET_DFF(
input D,
input CLK,
input Reset,
input En,
output Q);
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(CLK), .EN(En), .ALn(1'b1), .ADn(1'b0), .SLn(Reset), .SD(1'b0), .LAT(1'b0), .Q(Q));
endmodule
`endif
// LUT
`ifndef NO_LUT
module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
(* force_downto *)
input [WIDTH-1:0] A;
output Y;
generate
if (WIDTH == 1) begin
CFG1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0]));
end else
if (WIDTH == 2) begin
CFG2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0]), .B(A[1]));
end else
if (WIDTH == 3) begin
CFG3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0]), .B(A[1]), .C(A[2]));
end else
if (WIDTH == 4) begin
CFG4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
end else begin
wire _TECHMAP_FAIL_ = 1;
end
endgenerate
endmodule
`endif

View file

@ -0,0 +1,719 @@
/*
ISC License
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// Macro Library for PolarFire https://coredocs.s3.amazonaws.com/Libero/2021_2/Tool/pf_mlg.pdf
module AND2 (
input A, B,
output Y
);
assign Y = A & B;
endmodule
module AND3 (
input A, B, C,
output Y
);
assign Y = A & B & C;
endmodule
module AND4 (
input A, B, C, D,
output Y
);
assign Y = A & B & C & D;
endmodule
(* abc9_lut=1 *)
module CFG1 (
output Y,
input A
);
parameter [1:0] INIT = 2'h0;
assign Y = INIT >> A;
specify
(A => Y) = 127;
endspecify
endmodule
(* abc9_lut=1 *)
module CFG2 (
output Y,
input A,
input B
);
parameter [3:0] INIT = 4'h0;
assign Y = INIT >> {B, A};
specify
(A => Y) = 238;
(B => Y) = 127;
endspecify
endmodule
(* abc9_lut=1 *)
module CFG3 (
output Y,
input A,
input B,
input C
);
parameter [7:0] INIT = 8'h0;
assign Y = INIT >> {C, B, A};
specify
(A => Y) = 407;
(B => Y) = 238;
(C => Y) = 127;
endspecify
endmodule
(* abc9_lut=1 *)
module CFG4 (
output Y,
input A,
input B,
input C,
input D
);
parameter [15:0] INIT = 16'h0;
assign Y = INIT >> {D, C, B, A};
specify
(A => Y) = 472;
(B => Y) = 407;
(C => Y) = 238;
(D => Y) = 127;
endspecify
endmodule
module BUFF (
input A,
output Y
);
assign Y = A;
endmodule
module BUFD (
input A,
output Y
);
assign Y = A;
endmodule
module CLKINT (
input A,
(* clkbuf_driver *)
output Y
);
assign Y = A;
endmodule
module CLKINT_PRESERVE (
input A,
(* clkbuf_driver *)
output Y
);
assign Y = A;
endmodule
module GCLKINT (
input A, EN,
(* clkbuf_driver *)
output Y
);
assign Y = A & EN;
endmodule
module RCLKINT (
input A,
(* clkbuf_driver *)
output Y
);
assign Y = A;
endmodule
module RGCLKINT (
input A, EN,
(* clkbuf_driver *)
output Y
);
assign Y = A & EN;
endmodule
// sequential elements
// MICROCHIP_SYNC_SET_DFF and MICROCHIP_SYNC_RESET_DFF are intermediate cell types to implement the simplification idiom for abc9 flow
// see: https://yosyshq.readthedocs.io/projects/yosys/en/latest/yosys_internals/extending_yosys/abc_flow.html
(* abc9_flop, lib_whitebox *)
module MICROCHIP_SYNC_SET_DFF(
input D,
input CLK,
input Set,
input En,
output reg Q);
parameter [0:0] INIT = 1'b0; // unused
always @(posedge CLK) begin
if (En == 1) begin
if (Set == 0)
Q <= 1;
else
Q <= D;
end
end
specify
$setup(D , posedge CLK &&& En && Set, 0); // neg setup not supported?
$setup(En, posedge CLK, 109);
$setup(Set, posedge CLK &&& En, 404);
if (En && !Set) (posedge CLK => (Q : 1'b1)) = 303;
if (En && Set) (posedge CLK => (Q : D)) = 303;
endspecify
endmodule
(* abc9_flop, lib_whitebox *)
module MICROCHIP_SYNC_RESET_DFF(
input D,
input CLK,
input Reset,
input En,
output reg Q);
parameter [0:0] INIT = 1'b0; // unused
always @(posedge CLK) begin
if (En == 1) begin
if (Reset == 0)
Q <= 0;
else
Q <= D;
end
end
specify
$setup(D , posedge CLK &&& En && Reset, 0); // neg setup not supported?
$setup(En, posedge CLK, 109);
$setup(Reset, posedge CLK &&& En, 404);
if (En && !Reset) (posedge CLK => (Q : 1'b0)) = 303;
if (En && Reset) (posedge CLK => (Q : D)) = 303;
endspecify
endmodule
module SLE (
output Q,
input ADn,
input ALn,
(* clkbuf_sink *)
input CLK,
input D,
input LAT,
input SD,
input EN,
input SLn
);
reg q_latch, q_ff;
always @(posedge CLK, negedge ALn) begin
if (!ALn) begin
q_ff <= !ADn;
end else if (EN) begin
if (!SLn)
q_ff <= SD;
else
q_ff <= D;
end
end
always @* begin
if (!ALn) begin
q_latch <= !ADn;
end else if (CLK && EN) begin
if (!SLn)
q_ff <= SD;
else
q_ff <= D;
end
end
assign Q = LAT ? q_latch : q_ff;
endmodule
(* abc9_box, lib_whitebox *)
module ARI1 (
(* abc9_carry *)
input FCI,
(* abc9_carry *)
output FCO,
input A, B, C, D,
output Y, S
);
parameter [19:0] INIT = 20'h0;
wire [2:0] Fsel = {D, C, B};
wire F0 = INIT[Fsel];
wire F1 = INIT[8 + Fsel];
wire Yout = A ? F1 : F0;
assign Y = Yout;
assign S = FCI ^ Yout;
wire G = INIT[16] ? (INIT[17] ? F1 : F0) : INIT[17];
wire P = INIT[19] ? 1'b1 : (INIT[18] ? Yout : 1'b0);
assign FCO = P ? FCI : G;
specify
//pin to pin path delay
(A => Y ) = 472;
(B => Y ) = 407;
(C => Y ) = 238;
(D => Y ) = 127;
(A => S ) = 572;
(B => S ) = 507;
(C => S ) = 338;
(D => S ) = 227;
(FCI => S ) = 100;
(A => FCO ) = 522;
(B => FCO ) = 457;
(C => FCO ) = 288;
(D => FCO ) = 177;
(FCI => FCO ) = 50;
endspecify
endmodule
(* blackbox *)
module GCLKBUF (
(* iopad_external_pin *)
input PAD,
input EN,
(* clkbuf_driver *)
output Y
);
endmodule
(* blackbox *)
module GCLKBUF_DIFF (
(* iopad_external_pin *)
input PADP,
(* iopad_external_pin *)
input PADN,
input EN,
(* clkbuf_driver *)
output Y
);
endmodule
module INV (
input A,
output Y
);
assign Y = !A;
endmodule
module INVD (
input A,
output Y
);
assign Y = !A;
endmodule
module MX2 (
input A, B, S,
output Y
);
assign Y = S ? B : A;
endmodule
module MX4 (
input D0, D1, D2, D3, S0, S1,
output Y
);
assign Y = S1 ? (S0 ? D3 : D2) : (S0 ? D1 : D0);
endmodule
module NAND2 (
input A, B,
output Y
);
assign Y = !(A & B);
endmodule
module NAND3 (
input A, B, C,
output Y
);
assign Y = !(A & B & C);
endmodule
module NAND4 (
input A, B, C, D,
output Y
);
assign Y = !(A & B & C & D);
endmodule
module NOR2 (
input A, B,
output Y
);
assign Y = !(A | B);
endmodule
module NOR3 (
input A, B, C,
output Y
);
assign Y = !(A | B | C);
endmodule
module NOR4 (
input A, B, C, D,
output Y
);
assign Y = !(A | B | C | D);
endmodule
module OR2 (
input A, B,
output Y
);
assign Y = A | B;
endmodule
module OR3 (
input A, B, C,
output Y
);
assign Y = A | B | C;
endmodule
module OR4 (
input A, B, C, D,
output Y
);
assign Y = A | B | C | D;
endmodule
module XOR2 (
input A, B,
output Y
);
assign Y = A ^ B;
endmodule
module XOR3 (
input A, B, C,
output Y
);
assign Y = A ^ B ^ C;
endmodule
module XOR4 (
input A, B, C, D,
output Y
);
assign Y = A ^ B ^ C ^ D;
endmodule
module XOR8 (
input A, B, C, D, E, F, G, H,
output Y
);
assign Y = A ^ B ^ C ^ D ^ E ^ F ^ G ^ H;
endmodule
// module UJTAG
module BIBUF (
input D,
input E,
(* iopad_external_pin *)
inout PAD,
output Y
);
parameter IOSTD = "";
assign PAD = E ? D : 1'bz;
assign Y = PAD;
endmodule
(* blackbox *)
module BIBUF_DIFF (
input D,
input E,
(* iopad_external_pin *)
inout PADP,
(* iopad_external_pin *)
inout PADN,
output Y
);
parameter IOSTD = "";
endmodule
module CLKBIBUF (
input D,
input E,
(* iopad_external_pin *)
inout PAD,
(* clkbuf_driver *)
output Y
);
parameter IOSTD = "";
assign PAD = E ? D : 1'bz;
assign Y = PAD;
endmodule
module CLKBUF (
(* iopad_external_pin *)
input PAD,
(* clkbuf_driver *)
output Y
);
parameter IOSTD = "";
assign Y = PAD;
specify
(PAD => Y) = 50;
endspecify
endmodule
(* blackbox *)
module CLKBUF_DIFF (
(* iopad_external_pin *)
input PADP,
(* iopad_external_pin *)
input PADN,
(* clkbuf_driver *)
output Y
);
parameter IOSTD = "";
endmodule
module INBUF (
(* iopad_external_pin *)
input PAD,
output Y
);
parameter IOSTD = "";
assign Y = PAD;
endmodule
(* blackbox *)
module INBUF_DIFF (
(* iopad_external_pin *)
input PADP,
(* iopad_external_pin *)
input PADN,
output Y
);
parameter IOSTD = "";
endmodule
module OUTBUF (
input D,
(* iopad_external_pin *)
output PAD
);
parameter IOSTD = "";
assign PAD = D;
endmodule
(* blackbox *)
module OUTBUF_DIFF (
input D,
(* iopad_external_pin *)
output PADP,
(* iopad_external_pin *)
output PADN
);
parameter IOSTD = "";
endmodule
module TRIBUFF (
input D,
input E,
(* iopad_external_pin *)
output PAD
);
parameter IOSTD = "";
assign PAD = E ? D : 1'bz;
endmodule
(* blackbox *)
module TRIBUFF_DIFF (
input D,
input E,
(* iopad_external_pin *)
output PADP,
(* iopad_external_pin *)
output PADN
);
parameter IOSTD = "";
endmodule
(* blackbox *)
module MACC_PA (
input DOTP,
input SIMD,
input OVFL_CARRYOUT_SEL,
input CLK,
input AL_N,
input [17:0] A,
input A_BYPASS,
input A_SRST_N,
input A_EN,
input [17:0] B,
input B_BYPASS,
input B_SRST_N,
input B_EN,
input [17:0] D,
input D_BYPASS,
input D_ARST_N,
input D_SRST_N,
input D_EN,
input CARRYIN,
input [47:0] C,
input C_BYPASS,
input C_ARST_N,
input C_SRST_N,
input C_EN,
input [47:0] CDIN,
output [47:0] P,
output OVFL_CARRYOUT,
input P_BYPASS,
input P_SRST_N,
input P_EN,
output [47:0] CDOUT,
input PASUB,
input PASUB_BYPASS,
input PASUB_AD_N,
input PASUB_SL_N,
input PASUB_SD_N,
input PASUB_EN,
input [1:0] CDIN_FDBK_SEL,
input CDIN_FDBK_SEL_BYPASS,
input [1:0] CDIN_FDBK_SEL_AD_N,
input CDIN_FDBK_SEL_SL_N,
input [1:0] CDIN_FDBK_SEL_SD_N,
input CDIN_FDBK_SEL_EN,
input ARSHFT17,
input ARSHFT17_BYPASS,
input ARSHFT17_AD_N,
input ARSHFT17_SL_N,
input ARSHFT17_SD_N,
input ARSHFT17_EN,
input SUB,
input SUB_BYPASS,
input SUB_AD_N,
input SUB_SL_N,
input SUB_SD_N,
input SUB_EN
);
endmodule
(* blackbox *)
module RAM1K20 (
input [13:0] A_ADDR,
input [2:0] A_BLK_EN,
input A_CLK,
input [19:0] A_DIN,
output [19:0] A_DOUT,
input [1:0] A_WEN,
input A_REN,
input [2:0] A_WIDTH,
input [1:0] A_WMODE,
input A_BYPASS,
input A_DOUT_EN,
input A_DOUT_SRST_N,
input A_DOUT_ARST_N,
input [13:0] B_ADDR,
input [2:0] B_BLK_EN,
input B_CLK,
input [19:0] B_DIN,
output [19:0] B_DOUT,
input [1:0] B_WEN,
input B_REN,
input [2:0] B_WIDTH,
input [1:0] B_WMODE,
input B_BYPASS,
input B_DOUT_EN,
input B_DOUT_SRST_N,
input B_DOUT_ARST_N,
input ECC_EN,
input ECC_BYPASS,
output SB_CORRECT,
output DB_DETECT,
input BUSY_FB,
output ACCESS_BUSY
);
parameter INIT0 = 1024'h0;
parameter INIT1 = 1024'h0;
parameter INIT2 = 1024'h0;
parameter INIT3 = 1024'h0;
parameter INIT4 = 1024'h0;
parameter INIT5 = 1024'h0;
parameter INIT6 = 1024'h0;
parameter INIT7 = 1024'h0;
parameter INIT8 = 1024'h0;
parameter INIT9 = 1024'h0;
parameter INIT10 = 1024'h0;
parameter INIT11 = 1024'h0;
parameter INIT12 = 1024'h0;
parameter INIT13 = 1024'h0;
parameter INIT14 = 1024'h0;
parameter INIT15 = 1024'h0;
parameter INIT16 = 1024'h0;
parameter INIT17 = 1024'h0;
parameter INIT18 = 1024'h0;
parameter INIT19 = 1024'h0;
endmodule
(* blackbox *)
module RAM64x12 (
input R_CLK,
input [5:0] R_ADDR,
input R_ADDR_BYPASS,
input R_ADDR_EN,
input R_ADDR_SL_N,
input R_ADDR_SD,
input R_ADDR_AL_N,
input R_ADDR_AD_N,
input BLK_EN,
output [11:0] R_DATA,
input R_DATA_BYPASS,
input R_DATA_EN,
input R_DATA_SL_N,
input R_DATA_SD,
input R_DATA_AL_N,
input R_DATA_AD_N,
input W_CLK,
input [5:0] W_ADDR,
input [11:0]W_DATA,
input W_EN,
input BUSY_FB,
output ACCESS_BUSY
);
parameter INIT0 = 64'h0;
parameter INIT1 = 64'h0;
parameter INIT2 = 64'h0;
parameter INIT3 = 64'h0;
parameter INIT4 = 64'h0;
parameter INIT5 = 64'h0;
parameter INIT6 = 64'h0;
parameter INIT7 = 64'h0;
parameter INIT8 = 64'h0;
parameter INIT9 = 64'h0;
parameter INIT10 = 64'h0;
parameter INIT11 = 64'h0;
endmodule

View file

@ -0,0 +1,343 @@
/*
ISC License
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "kernel/sigtools.h"
#include "kernel/yosys.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
typedef std::pair<Const, std::vector<SigBit>> LutData;
// Compute a LUT implementing (select ^ select_inv) ? alt_data : data. Returns true if successful.
bool merge_lut(LutData &result, const LutData &data, const LutData select, bool select_inv, SigBit alt_data, int max_lut_size)
{
// First, gather input signals -- insert new signals at the beginning
// of the vector, so they don't disturb the likely-critical D LUT input
// timings.
result.second = data.second;
// D lut inputs initially start at 0.
int idx_data = 0;
// Now add the control input LUT inputs.
std::vector<int> idx_sel;
for (auto bit : select.second) {
int idx = -1;
for (int i = 0; i < GetSize(result.second); i++)
if (result.second[i] == bit)
idx = i;
if (idx == -1) {
idx = 0;
// Insert new signal at the beginning and bump all indices.
result.second.insert(result.second.begin(), bit);
idx_data++;
for (int &sidx : idx_sel)
sidx++;
}
idx_sel.push_back(idx);
}
// Insert the Q signal, if any, to the slowest input -- it will have
// no problem meeting timing.
// This is to emulate CLK_EN, where output data is retained
int idx_alt = -1;
if (alt_data.wire) {
// Check if we already have it.
for (int i = 0; i < GetSize(result.second); i++)
if (result.second[i] == alt_data)
idx_alt = i;
// If not, add it.
if (idx_alt == -1) {
idx_alt = 0;
result.second.insert(result.second.begin(), alt_data);
idx_data++;
for (int &sidx : idx_sel)
sidx++;
}
}
// If LUT would be too large, bail.
if (GetSize(result.second) > max_lut_size)
return false;
// Okay, we're doing it — compute the LUT mask.
result.first = Const(0, 1 << GetSize(result.second));
for (int i = 0; i < GetSize(result.first); i++) {
int sel_lut_idx = 0;
for (int j = 0; j < GetSize(select.second); j++)
if (i & 1 << idx_sel[j])
sel_lut_idx |= 1 << j;
bool select_val = (select.first.bits[sel_lut_idx] == State::S1);
bool new_bit;
if (select_val ^ select_inv) {
// Use alt_data.
if (alt_data.wire)
new_bit = (i & 1 << idx_alt) != 0;
else
new_bit = alt_data.data == State::S1;
} else {
// Use original LUT.
int lut_idx = i >> idx_data & ((1 << GetSize(data.second)) - 1);
new_bit = data.first.bits[lut_idx] == State::S1;
}
result.first.bits[i] = new_bit ? State::S1 : State::S0;
}
return true;
}
struct MicrochipDffOptPass : public Pass {
MicrochipDffOptPass() : Pass("microchip_dffopt", "MICROCHIP: optimize FF control signal usage") {}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" microchip_dffopt [options] [selection]\n");
log("\n");
log("Converts hardware clock enable and set/reset signals on FFs to emulation\n");
log("using LUTs, if doing so would improve area. Operates on post-techmap LUT, DFF\n");
log("cells. \n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing MICROCHIP_DFFOPT pass (optimize FF control signal usage).\n");
size_t argidx = 1;
int max_lut_size = 4;
extra_args(args, argidx, design);
for (auto module : design->selected_modules()) {
log("Optimizing FFs in %s.\n", log_id(module));
SigMap sigmap(module);
dict<SigBit, pair<LutData, Cell *>> bit_to_lut;
dict<SigBit, int> bit_uses;
// Gather LUTs.
for (auto cell : module->selected_cells()) {
for (auto port : cell->connections())
for (auto bit : port.second)
bit_uses[sigmap(bit)]++;
if (cell->get_bool_attribute(ID::keep))
continue;
if (cell->type == ID(INV)) {
SigBit sigout = sigmap(cell->getPort(ID::Y));
SigBit sigin = sigmap(cell->getPort(ID::A));
bit_to_lut[sigout] = make_pair(LutData(Const(1, 2), {sigin}), cell); // INIT = 01
} else if (cell->type.in(ID(CFG1), ID(CFG2), ID(CFG3), ID(CFG4))) {
SigBit sigout = sigmap(cell->getPort(ID::Y));
const Const &init = cell->getParam(ID::INIT);
std::vector<SigBit> sigin;
sigin.push_back(sigmap(cell->getPort(ID(A))));
if (cell->type == ID(CFG1))
goto lut_sigin_done;
sigin.push_back(sigmap(cell->getPort(ID(B))));
if (cell->type == ID(CFG2))
goto lut_sigin_done;
sigin.push_back(sigmap(cell->getPort(ID(C))));
if (cell->type == ID(CFG3))
goto lut_sigin_done;
sigin.push_back(sigmap(cell->getPort(ID(D))));
lut_sigin_done:
bit_to_lut[sigout] = make_pair(LutData(init, sigin), cell);
}
}
for (auto wire : module->wires())
if (wire->port_output || wire->port_input)
for (int i = 0; i < GetSize(wire); i++)
bit_uses[sigmap(SigBit(wire, i))]++;
// Iterate through FFs.
for (auto cell : module->selected_cells()) {
if (!cell->type.in(ID(SLE))) // not a SLE
continue;
if (cell->getPort(ID(LAT)).is_fully_ones()) // skip latch
continue;
if (cell->get_bool_attribute(ID::keep)) // keep attribute
continue;
if (!cell->getPort(ID(ALn)).is_fully_ones()) // async FF
continue;
const bool hasSyncLoad = cell->getPort(ID(SLn)).is_wire();
const bool has_s = hasSyncLoad && cell->getPort(ID(SD)).is_fully_ones();
const bool has_r = hasSyncLoad && cell->getPort(ID(SD)).is_fully_zero();
// SLE cannot have both synchronous set and reset implemented at the same time
log_assert(!(has_s && has_r));
// Don't bother if D has more than one use.
SigBit sig_D = sigmap(cell->getPort(ID::D));
if (bit_uses[sig_D] > 2)
continue;
// Find the D LUT.
auto it_D = bit_to_lut.find(sig_D);
if (it_D == bit_to_lut.end())
continue;
LutData lut_d = it_D->second.first;
Cell *cell_d = it_D->second.second;
LutData lut_d_post_ce;
LutData lut_d_post_s;
LutData lut_d_post_r;
bool worthy_post_ce = false;
bool worthy_post_s = false;
bool worthy_post_r = false;
// First, unmap CE.
SigBit sig_Q = sigmap(cell->getPort(ID::Q));
SigBit sig_CE = sigmap(cell->getPort(ID(EN)));
LutData lut_ce = LutData(Const(2, 2), {sig_CE}); // INIT = 10
auto it_CE = bit_to_lut.find(sig_CE);
if (it_CE != bit_to_lut.end())
lut_ce = it_CE->second.first;
if (sig_CE.wire) {
// Merge CE LUT and D LUT into one. If it cannot be done, nothing to do about this FF.
if (!merge_lut(lut_d_post_ce, lut_d, lut_ce, true, sig_Q, max_lut_size))
continue;
// If this gets rid of a CE LUT, it's worth it. If not, it still may be worth it, if we can remove set/reset
// as well.
if (it_CE != bit_to_lut.end())
worthy_post_ce = true;
} else if (sig_CE.data != State::S1) {
// Strange. Should not happen in a reasonable flow, so bail.
log_assert(false); // This DFF is always off
continue;
} else {
lut_d_post_ce = lut_d;
}
// Second, unmap S, if any.
lut_d_post_s = lut_d_post_ce;
if (has_s) {
SigBit sig_S = sigmap(cell->getPort(ID(SLn)));
LutData lut_s = LutData(Const(2, 2), {sig_S}); // INIT = 10
bool inv_s = true; // active low
auto it_S = bit_to_lut.find(sig_S);
if (it_S != bit_to_lut.end())
lut_s = it_S->second.first;
if (sig_S.wire) {
// Merge S LUT and D LUT into one. If it cannot be done, try to at least merge CE.
if (!merge_lut(lut_d_post_s, lut_d_post_ce, lut_s, inv_s, SigBit(State::S1), max_lut_size))
goto unmap;
// If this gets rid of an S LUT, it's worth it.
if (it_S != bit_to_lut.end())
worthy_post_s = true;
} else if (sig_S.data != (inv_s ? State::S1 : State::S0)) {
// Strange. Should not happen in a reasonable flow, so bail.
log_assert(false); // DFF is always in set mode
continue;
}
}
// Third, unmap R, if any.
lut_d_post_r = lut_d_post_s;
if (has_r) {
SigBit sig_R = sigmap(cell->getPort(ID(SLn)));
LutData lut_r = LutData(Const(2, 2), {sig_R}); // INIT = 10
bool inv_r = true; // active low
auto it_R = bit_to_lut.find(sig_R);
if (it_R != bit_to_lut.end())
lut_r = it_R->second.first;
if (sig_R.wire) {
// Merge R LUT and D LUT into one. If it cannot be done, try to at least merge CE/S.
if (!merge_lut(lut_d_post_r, lut_d_post_s, lut_r, inv_r, SigBit(State::S0), max_lut_size))
goto unmap;
// If this gets rid of an S LUT, it's worth it.
if (it_R != bit_to_lut.end())
worthy_post_r = true;
} else if (sig_R.data != (inv_r ? State::S1 : State::S0)) {
// Strange. Should not happen in a reasonable flow, so bail.
log_assert(false); // DFF is always in reset mode
continue;
}
}
unmap:
// SLE cannot have both synchronous set and reset implemented at the same time
log_assert(!(worthy_post_r && worthy_post_s));
LutData final_lut;
if (worthy_post_r) {
final_lut = lut_d_post_r;
} else if (worthy_post_s) {
final_lut = lut_d_post_s;
} else if (worthy_post_ce) {
final_lut = lut_d_post_ce;
} else {
// Nothing to do here.
continue;
}
std::string ports;
if (worthy_post_r)
ports += " + R";
if (worthy_post_s)
ports += " + S";
if (worthy_post_ce)
ports += " + CE";
log(" Merging D%s LUTs for %s/%s (%d -> %d)\n", ports.c_str(), log_id(cell), log_id(sig_Q.wire),
GetSize(lut_d.second), GetSize(final_lut.second));
// Okay, we're doing it. Unmap ports.
if ((has_s && worthy_post_s) || worthy_post_r) {
cell->setPort(ID(SLn), Const(1, 1));
}
// if we made it this far, clk enable is always merged into D
cell->setPort(ID(EN), Const(1, 1));
// Create the new LUT.
Cell *lut_cell = nullptr;
switch (GetSize(final_lut.second)) {
case 1:
lut_cell = module->addCell(NEW_ID, ID(CFG1));
break;
case 2:
lut_cell = module->addCell(NEW_ID, ID(CFG2));
break;
case 3:
lut_cell = module->addCell(NEW_ID, ID(CFG3));
break;
case 4:
lut_cell = module->addCell(NEW_ID, ID(CFG4));
break;
default:
log_assert(!"unknown lut size");
}
lut_cell->attributes = cell_d->attributes;
Wire *lut_out = module->addWire(NEW_ID);
lut_cell->setParam(ID::INIT, final_lut.first);
cell->setPort(ID::D, lut_out);
lut_cell->setPort(ID::Y, lut_out);
lut_cell->setPort(ID(A), final_lut.second[0]);
if (GetSize(final_lut.second) >= 2)
lut_cell->setPort(ID(B), final_lut.second[1]);
if (GetSize(final_lut.second) >= 3)
lut_cell->setPort(ID(C), final_lut.second[2]);
if (GetSize(final_lut.second) >= 4)
lut_cell->setPort(ID(D), final_lut.second[3]);
}
}
}
} MicrochipDffOptPass;
PRIVATE_NAMESPACE_END

View file

@ -0,0 +1,95 @@
/*
ISC License
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 0;
parameter B_WIDTH = 0;
parameter Y_WIDTH = 0;
wire [47:0] P_48;
// For pin descriptions, see Section 9 of PolarFire FPGA Macro Library Guide:
// https://coredocs.s3.amazonaws.com/Libero/2021_2/Tool/pf_mlg.pdf
MACC_PA _TECHMAP_REPLACE_ (
.DOTP(1'b0),
.SIMD(1'b0),
.OVFL_CARRYOUT_SEL(1'b0),
.AL_N(1'b1),
.A(A),
.A_BYPASS(1'b1),
.A_SRST_N(1'b1),
.A_EN(1'b1),
.B(B),
.B_BYPASS(1'b1),
.B_SRST_N(1'b1),
.B_EN(1'b1),
.D(18'b0),
.D_BYPASS(1'b1),
.D_ARST_N(1'b1),
.D_SRST_N(1'b1),
.D_EN(1'b1),
.CARRYIN(1'b0),
.C(48'b0),
.C_BYPASS(1'b1),
.C_ARST_N(1'b1),
.C_SRST_N(1'b1),
.C_EN(1'b1),
.P(P_48),
.P_BYPASS(1'b1),
.P_SRST_N(1'b1),
.P_EN(1'b1),
.PASUB(1'b0),
.PASUB_BYPASS(1'b1),
.PASUB_AD_N(1'b0),
.PASUB_SL_N(1'b1),
.PASUB_SD_N(1'b0),
.PASUB_EN(1'b1),
.CDIN_FDBK_SEL(2'b00),
.CDIN_FDBK_SEL_BYPASS(1'b1),
.CDIN_FDBK_SEL_AD_N(2'b00),
.CDIN_FDBK_SEL_SL_N(1'b1),
.CDIN_FDBK_SEL_SD_N(2'b00),
.CDIN_FDBK_SEL_EN(1'b1),
.ARSHFT17(1'b0),
.ARSHFT17_BYPASS(1'b1),
.ARSHFT17_AD_N(1'b0),
.ARSHFT17_SL_N(1'b1),
.ARSHFT17_SD_N(1'b0),
.ARSHFT17_EN(1'b1),
.SUB(1'b0),
.SUB_BYPASS(1'b1),
.SUB_AD_N(1'b0),
.SUB_SL_N(1'b1),
.SUB_SD_N(1'b0),
.SUB_EN(1'b1)
);
assign Y = P_48;
endmodule

View file

@ -0,0 +1,553 @@
/*
ISC License
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include "kernel/register.h"
#include "kernel/rtlil.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct SynthMicrochipPass : public ScriptPass {
SynthMicrochipPass() : ScriptPass("synth_microchip", "synthesis for Microchip FPGAs") {}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" synth_microchip [options]\n");
log("\n");
log("This command runs synthesis for Microchip FPGAs. This command creates \n");
log("netlists that are compatible with Microchip PolarFire devices. \n");
log("\n");
log(" -top <module>\n");
log(" use the specified module as the top module\n");
log("\n");
log(" -family <family>\n");
log(" Run synthesis for the specified Microchip architecture. \n");
log(" Generate the synthesis netlist for the specified family.\n");
log(" supported values:\n");
log(" - polarfire: PolarFire\n");
log("\n");
log(" -edif <file>\n");
log(" Write the design to the specified edif file. Writing of an output file\n");
log(" is omitted if this parameter is not specified.\n");
log("\n");
log(" -blif <file>\n");
log(" Write the design to the specified BLIF file. Writing of an output file\n");
log(" is omitted if this parameter is not specified.\n");
log("\n");
log(" -vlog <file>\n");
log(" write the design to the specified Verilog file. writing of an output\n");
log(" file is omitted if this parameter is not specified.\n");
log(" -nobram\n");
log(" Do not use block RAM cells in output netlist\n");
log("\n");
log(" -nocarry\n");
log(" Do not use ARI1 cells in output netlist\n");
log("\n");
log(" -nodsp\n");
log(" Do not use MATH blocks to implement multipliers and associated logic\n");
log("\n");
log(" -noiopad\n");
log(" Disable I/O buffer insertion (useful for hierarchical or \n");
log(" out-of-context flows)\n");
log("\n");
log(" -noclkbuf\n");
log(" Disable automatic clock buffer insertion\n");
log("\n");
log(" -run <from_label>:<to_label>\n");
log(" Only run the commands between the labels (see below). an empty\n");
log(" 'from_label' is synonymous to 'begin', and empty 'to_label' is\n");
log(" synonymous to the end of the command list.\n");
log("\n");
log(" -noflatten\n");
log(" do not flatten design before synthesis\n");
log("\n");
log(" -dff\n");
log(" Run 'abc'/'abc9' with -dff option\n");
log("\n");
log(" -retime\n");
log(" Run 'abc' with '-D 1' option to enable flip-flop retiming.\n");
log(" implies -dff.\n");
log("\n");
log(" -noabc9\n");
log(" Use classic ABC flow instead of ABC9\n");
log("\n");
log(" -discard-ffinit\n");
log(" discard FF init value instead of emitting an error\n");
log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
help_script();
log("\n");
}
std::string top_opt, edif_file, blif_file, vlog_file, family;
bool flatten, retime, noiopad, noclkbuf, nobram, nocarry, nowidelut, nodsp;
bool abc9, dff;
bool discard_ffinit;
int lut_size;
// debug dump switches
bool debug_memory, debug_carry;
void clear_flags() override
{
top_opt = "-auto-top";
edif_file.clear();
blif_file.clear();
vlog_file.clear();
family = "polarfire";
flatten = true;
retime = false;
noiopad = false;
noclkbuf = false;
nocarry = false;
nobram = false;
nowidelut = false;
nodsp = false;
abc9 = true;
dff = false;
lut_size = 4;
discard_ffinit = false;
debug_memory = false;
debug_carry = false;
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::string run_from, run_to;
clear_flags();
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-top" && argidx + 1 < args.size()) {
top_opt = "-top " + args[++argidx];
continue;
}
if ((args[argidx] == "-family" || args[argidx] == "-arch") && argidx + 1 < args.size()) {
family = args[++argidx];
continue;
}
if (args[argidx] == "-edif" && argidx + 1 < args.size()) {
edif_file = args[++argidx];
continue;
}
if (args[argidx] == "-blif" && argidx + 1 < args.size()) {
blif_file = args[++argidx];
continue;
}
if (args[argidx] == "-vlog" && argidx + 1 < args.size()) {
vlog_file = args[++argidx];
continue;
}
if (args[argidx] == "-run" && argidx + 1 < args.size()) {
size_t pos = args[argidx + 1].find(':');
if (pos == std::string::npos)
break;
run_from = args[++argidx].substr(0, pos);
run_to = args[argidx].substr(pos + 1);
continue;
}
if (args[argidx] == "-noflatten") {
flatten = false;
continue;
}
if (args[argidx] == "-retime") {
dff = true;
retime = true;
continue;
}
if (args[argidx] == "-nocarry") {
nocarry = true;
continue;
}
if (args[argidx] == "-nowidelut") {
nowidelut = true;
continue;
}
if (args[argidx] == "-iopad") {
continue;
}
if (args[argidx] == "-noiopad") {
noiopad = true;
continue;
}
if (args[argidx] == "-noclkbuf") {
noclkbuf = true;
continue;
}
if (args[argidx] == "-nocarry") {
nocarry = true;
continue;
}
if (args[argidx] == "-nobram") {
nobram = true;
continue;
}
if (args[argidx] == "-noabc9") {
abc9 = false;
continue;
}
if (args[argidx] == "-nodsp") {
nodsp = true;
continue;
}
if (args[argidx] == "-dff") {
dff = true;
continue;
}
if (args[argidx] == "-debug_memory") {
debug_memory = true;
continue;
}
if (args[argidx] == "-debug_carry") {
debug_carry = true;
continue;
}
if (args[argidx] == "-discard-ffinit") {
discard_ffinit = true;
continue;
}
break;
}
extra_args(args, argidx, design);
if (family == "polarfire") {
lut_size = 4;
} else {
log_cmd_error("Invalid Microchip -family setting: '%s'.\n", family.c_str());
}
if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n");
if (abc9 && retime)
log_cmd_error("-retime option not currently compatible with -abc9!\n");
log_header(design, "Executing SYNTH_MICROCHIP pass.\n");
log_push();
run_script(design, run_from, run_to);
log_pop();
}
void script() override
{
std::string lut_size_s = std::to_string(lut_size);
if (help_mode)
lut_size_s = "[4]";
if (check_label("begin")) {
std::string read_args;
read_args += " -lib -specify +/microchip/cells_sim.v";
run("read_verilog" + read_args);
run(stringf("hierarchy -check %s", top_opt.c_str()));
}
if (check_label("prepare")) {
run("proc");
if (flatten || help_mode)
run("flatten", "(with '-flatten')");
if (active_design)
active_design->scratchpad_unset("tribuf.added_something");
run("tribuf -logic");
if (noiopad && active_design && active_design->scratchpad_get_bool("tribuf.added_something"))
log_error("Tristate buffers are unsupported without the '-iopad' option.\n");
run("deminout");
run("opt_expr");
run("opt_clean");
run("check");
run("opt -nodffe -nosdff");
run("fsm");
run("opt");
run("wreduce");
run("peepopt");
run("opt_clean");
}
if (check_label("map_dsp", "(skip if '-nodsp')")) {
if (!nodsp || help_mode) {
run("memory_dff"); // microchip_dsp will merge registers, reserve memory port registers first
if (help_mode)
run("techmap -map +/mul2dsp.v -map +/microchip/{family}_dsp_map.v {options}");
else if (family == "polarfire") // Microchip - map multipliers to DSP
run("techmap -map +/mul2dsp.v -map +/microchip/polarfire_dsp_map.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 "
"-D DSP_A_MAXWIDTH_PARTIAL=18 " // Partial multipliers are intentionally
// limited to 18x18 in order to take
// advantage of the (PCOUT >> 17) -> PCIN
// dedicated cascade chain capability
"-D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 " // Blocks Nx1 multipliers
"-D DSP_Y_MINWIDTH=9 "
"-D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL18X18");
run("select a:mul2dsp");
run("setattr -unset mul2dsp");
run("opt_expr -fine");
run("wreduce");
run("select -clear");
if (help_mode)
run("microchip_dsp -family <family>");
else if (family == "polarfire") // Microchip - absorb cells into DSP
run("microchip_dsp -family " + family);
run("chtype -set $mul t:$__soft_mul");
}
}
if (check_label("coarse")) {
run("techmap -map +/cmp2lut.v -map +/cmp2lcu.v -D LUT_WIDTH=" + lut_size_s);
run("alumacc");
run("share");
run("opt");
run("memory -nomap");
run("opt_clean");
if (discard_ffinit || help_mode)
run("attrmap -remove init", "(only if -discard-ffinit)");
}
if (check_label("map_memory")) {
std::string params = "";
std::string LSRAM_map = "+/microchip/LSRAM_map.v";
std::string uSRAM_map = "+/microchip/uSRAM_map.v";
if (debug_memory)
run("write_verilog -noexpr memory_map_pre.vm");
if (help_mode) {
params = " [...]";
} else {
if (family == "polarfire") {
// cost of a single bit for memory lowered to soft logic
params += " -logic-cost-rom 0.015625";
params += " -lib +/microchip/LSRAM.txt";
params += " -lib +/microchip/uSRAM.txt";
LSRAM_map = "+/microchip/LSRAM_map.v";
uSRAM_map = "+/microchip/uSRAM_map.v";
}
if (nobram)
params += " -no-auto-block";
}
// transform memories into intermediate cells
// Cost based transformation. The cost is assigned by us for each cell.
run("memory_libmap" + params);
if (debug_memory)
run("write_verilog -noexpr memory_map_libmap.vm");
// map intermediate cells to actual RAM macros
// NOTE: order doesnt matter here
run("techmap -map " + LSRAM_map);
run("techmap -map " + uSRAM_map);
if (debug_memory)
run("write_verilog -noexpr memory_map_final.vm");
}
if (check_label("map_ffram")) {
run("opt -fast -full");
// blast unmapped RAM to flops or LUTs
run("memory_map");
}
if (check_label("fine")) {
run("opt -full");
if (debug_carry)
run("write_verilog -noexpr ARI1_cells.vm");
if (!nocarry) {
// converts $mux -> $_MUX_ to allow muxcover to work
run("simplemap t:$mux");
// converts $and/$or/$xor to gate representation for extract_reduce to work
run("simplemap t:$xor"); // only mapping reduce_xor
// mapping based on Yosys internal gates
if (debug_carry)
run("write_verilog -noexpr ARI1_pre.vm");
// collapse $_AND_/$_OR_/$_XOR_ chains into reduction cells
run("extract_reduce");
if (debug_carry)
run("write_verilog -noexpr ARI1_extract_reduce.vm");
// pack mux trees into $_MUX4_
run("muxcover -nodecode -mux4=220");
if (debug_carry)
run("write_verilog -noexpr ARI1_muxcover.vm");
run("techmap -map +/microchip/arith_map.v");
if (debug_carry)
run("write_verilog -noexpr ARI1_post.vm");
}
// convert all remaining cells to gates
run("techmap -map +/techmap.v");
run("opt -fast");
}
if (check_label("map_cells")) {
// Needs to be done before logic optimization, so that inverters (inserted
// here because of negative-polarity output enable) are handled.
if (help_mode || !noiopad) {
run("iopadmap -bits -inpad INBUF Y:PAD -outpad OUTBUF D:PAD -toutpad TRIBUFF E:D:PAD -tinoutpad BIBUF E:Y:D:PAD",
"(unless -noiobs)");
}
std::string techmap_args = "-map +/techmap.v -map +/microchip/cells_map.v";
run("techmap " + techmap_args);
run("clean");
}
if (check_label("map_ffs")) {
// dfflegalize : Converts FFs to types supported by the target
// this can convert less capable cells into more capable cells (e.g. dff -> dffe)
// Based on PolarFire® FPGA Macro Library Guide
// D-flop:
// active high enable
// active low clear or active low set
// Latch:
// active low clear or active low set
// SLE (can implement D-flop/Latch):
// active high EN
// active low async load (set/reset) with static load configuration via ADn (Q = ~ADn)
// active low sync load (set/reset) with static load configuration via SD
// static latch configuration bit
// init not supported
// Yosys internal cell description
// see: https://yosyshq.readthedocs.io/projects/yosys/en/latest/yosys_internals/formats/cell_library.html
// see: common/simcells.v
// $_DFF_[NP]_ (regular dff)
// $_DFFE_[NP][NP]_ (enable)
// $_DFF_[NP][NP][01]_ (async reset to 0/1)
// $_DFFE_[NP][NP][01][NP]_ (async reset to 0/1 + enable)
// $_ALDFF_[NP][NP]_ (async load)
// $_ALDFFE_[NP][NP][NP]_ (async load + enable)
// $_DFFSR_[NP][NP][NP]_ (async set & reset)
// $_DFFSRE_[NP][NP][NP][NP]_ (async set & reset + enable)
// $_SDFF_[NP][NP][01]_ (sync reset to 0/1)
// $_SDFFE_[NP][NP][01][NP]_ (sync reset to 0/1 + enable, reset prioritize over enable)
// $_SDFFCE_[NP][NP][01][NP]_ (sync reset to 0/1 + enable, enable prioritize over reset)
// $_SR_[NP][NP]_ (set/reset latch)
// $_DLATCH_[NP]_ (D-latch)
// $_DLATCH_[NP][NP][01]_ (D-latch + reset to 0/1)
// $_DLATCHSR_[NP][NP][NP]_ (D-latch + set + reset)
if (family == "polarfire") {
std::string params = "";
// D-flop with async reset and enable
// posedge CLK, active low reset to 1 or 0, active high EN
params += " -cell $_DFFE_PN?P_ x";
// D-flop with sync reset and enable, enable takes priority over reset
// posedge CLK, active low reset to 1 or 0, active high EN
params += " -cell $_SDFFCE_PN?P_ x";
// D-latch + reset to 0/1
// posedge CLK, active low reset to 1 or 0
params += " -cell $_DLATCH_PN?_ x";
run("dfflegalize" + params, "(Converts FFs to supported types)");
}
if (abc9 || help_mode) {
if (dff || help_mode)
run("zinit -all w:* t:$_SDFFCE_*", "('-dff' only)");
run("techmap -D NO_LUT -map +/microchip/cells_map.v", "('-abc9' only)");
}
}
if (check_label("map_luts")) {
run("opt_expr -mux_undef -noclkinv");
if (help_mode)
run("abc -luts 2:2,3,6:5[,10,20] [-dff] [-D 1]", "(option for '-nowidelut', '-dff', '-retime')");
else if (abc9) {
std::string abc9_opts;
// for the if command in abc to specify wire delay between adjacent LUTs (default = 0)
// NOTE: should not have 0 wire delay between LUTs,
// otherwise abc might use LUT2+LUT3 instead of single LUT4
abc9_opts += " -W 300";
if (nowidelut)
abc9_opts += stringf(" -maxlut %d", lut_size);
if (dff)
abc9_opts += " -dff";
run("abc9" + abc9_opts);
} else {
std::string abc_opts = " -lut " + lut_size_s;
if (dff)
abc_opts += " -dff";
if (retime)
abc_opts += " -D 1";
run("abc" + abc_opts);
}
run("clean");
if (help_mode || !abc9)
run("techmap -D NO_LUT -map +/microchip/cells_map.v", "(only if not '-abc9')");
std::string techmap_args = "-map +/microchip/cells_map.v -D FINAL_MAP";
techmap_args += " -D LUT_WIDTH=" + lut_size_s;
run("techmap " + techmap_args);
if (help_mode || lut_size == 4)
run("microchip_dffopt");
}
run("clkbufmap -buf CLKINT Y:A -inpad CLKBUF Y:PAD");
run("clean -purge");
if (check_label("check")) {
run("hierarchy -check");
run("stat");
run("check -noinit");
run("blackbox =A:whitebox");
}
if (check_label("edif")) {
if (!edif_file.empty() || help_mode)
run(stringf("write_edif -pvector bra %s", edif_file.c_str()));
}
if (check_label("blif")) {
if (!blif_file.empty() || help_mode)
run(stringf("write_blif %s", blif_file.c_str()));
}
if (check_label("vlog"))
{
if (!vlog_file.empty() || help_mode)
run(stringf("write_verilog %s", help_mode ? "<file-name>" : vlog_file.c_str()));
}
}
} SynthMicrochipPass;
PRIVATE_NAMESPACE_END

View file

@ -0,0 +1,69 @@
# ISC License
#
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# asynchronous read
ram block $__uSRAM_AR_ {
#(LSRAM cost)/3
cost 43;
# INIT supported
init any;
abits 6;
widths 12 per_port;
# single write enable wire
port sw "W" {
clock posedge;
# collision not supported, but write takes precedence and read data is invalid while writing to
# the same address
wrtrans all new;
optional;
}
port ar "R" {
optional;
}
}
# synchronous read
# NOTE: synchronous read can be realized by the address pipeline register or data pipeline register.
# This assumes address is synchronized
ram block $__uSRAM_SR_ {
cost 42;
init any;
abits 6;
widths 12 per_port;
port sw "W" {
clock posedge;
# collision not supported
wrtrans all new;
optional;
}
port sr "R" {
clock posedge;
rden;
rdinit none;
optional;
}
}

View file

@ -0,0 +1,126 @@
/*
ISC License
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// See document PolarFire Family Fabric User Guide
// section 4.2 for port list.
// Asynchronous read
module $__uSRAM_AR_ (...);
parameter INIT = 0;
parameter ADDR_BITS = 6;
parameter PORT_W_WIDTH = 12;
parameter PORT_R_WIDTH = 12;
parameter PORT_R_USED = 0;
parameter PORT_W_USED = 0;
input PORT_W_CLK;
input [ADDR_BITS-1:0] PORT_W_ADDR;
input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
input PORT_W_WR_EN;
input [ADDR_BITS-1:0] PORT_R_ADDR;
output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA;
`include "brams_defs.vh"
RAM64x12 #(
`PARAMS_INIT_uSRAM
) _TECHMAP_REPLACE_ (
.R_ADDR(PORT_R_ADDR),
.R_ADDR_BYPASS(1'b1),
.R_ADDR_EN(1'b0),
.R_ADDR_SL_N(1'b1),
.R_ADDR_SD(1'b0),
.R_ADDR_AL_N(1'b1),
.R_ADDR_AD_N(1'b0),
.BLK_EN(PORT_R_USED ? 1'b1 : 1'b0),
.R_DATA(PORT_R_RD_DATA),
.R_DATA_BYPASS(1'b1),
.R_DATA_EN(1'b0),
.R_DATA_SL_N(1'b1),
.R_DATA_SD(1'b0),
.R_DATA_AL_N(1'b1),
.R_DATA_AD_N(1'b0),
.W_CLK(PORT_W_CLK),
.W_ADDR(PORT_W_ADDR),
.W_DATA(PORT_W_WR_DATA),
.W_EN(PORT_W_WR_EN),
.BUSY_FB(1'b0)
);
endmodule
// Synchronous read
module $__uSRAM_SR_ (...);
parameter INIT = 0;
parameter ADDR_BITS = 6;
parameter PORT_W_WIDTH = 12;
parameter PORT_R_WIDTH = 12;
parameter PORT_R_USED = 0;
parameter PORT_W_USED = 0;
input PORT_W_CLK;
input [ADDR_BITS-1:0] PORT_W_ADDR;
input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
input PORT_W_WR_EN;
// Read port clock and enable signal
// that async read uSRAM doesn't have
input PORT_R_CLK;
input PORT_R_RD_EN;
input [ADDR_BITS-1:0] PORT_R_ADDR;
output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA;
`include "brams_defs.vh"
RAM64x12 #(
`PARAMS_INIT_uSRAM
) _TECHMAP_REPLACE_ (
.R_CLK(PORT_R_CLK),
.R_ADDR(PORT_R_ADDR),
.R_ADDR_BYPASS(1'b0),
.R_ADDR_EN(PORT_R_RD_EN),
.R_ADDR_SL_N(1'b1),
.R_ADDR_SD(1'b0),
.R_ADDR_AL_N(1'b1),
.R_ADDR_AD_N(1'b0),
.BLK_EN(PORT_R_USED ? 1'b1 : 1'b0),
.R_DATA(PORT_R_RD_DATA),
.R_DATA_BYPASS(1'b1),
.R_DATA_EN(1'b0),
.R_DATA_SL_N(1'b1),
.R_DATA_SD(1'b0),
.R_DATA_AL_N(1'b1),
.R_DATA_AD_N(1'b0),
.W_CLK(PORT_W_CLK),
.W_ADDR(PORT_W_ADDR),
.W_DATA(PORT_W_WR_DATA),
.W_EN(PORT_W_WR_EN),
.BUSY_FB(1'b0)
);
endmodule