mirror of
https://github.com/vortexgpgpu/vortex.git
synced 2025-04-24 05:47:35 -04:00
enabling Vivado's asynchronous bram suppot via direct netlist transformation
Some checks are pending
CI / setup (push) Waiting to run
CI / build (32) (push) Blocked by required conditions
CI / build (64) (push) Blocked by required conditions
CI / tests (cache, 32) (push) Blocked by required conditions
CI / tests (cache, 64) (push) Blocked by required conditions
CI / tests (config1, 32) (push) Blocked by required conditions
CI / tests (config1, 64) (push) Blocked by required conditions
CI / tests (config2, 32) (push) Blocked by required conditions
CI / tests (config2, 64) (push) Blocked by required conditions
CI / tests (debug, 32) (push) Blocked by required conditions
CI / tests (debug, 64) (push) Blocked by required conditions
CI / tests (opencl, 32) (push) Blocked by required conditions
CI / tests (opencl, 64) (push) Blocked by required conditions
CI / tests (regression, 32) (push) Blocked by required conditions
CI / tests (regression, 64) (push) Blocked by required conditions
CI / tests (scope, 32) (push) Blocked by required conditions
CI / tests (scope, 64) (push) Blocked by required conditions
CI / tests (stress, 32) (push) Blocked by required conditions
CI / tests (stress, 64) (push) Blocked by required conditions
CI / tests (synthesis, 32) (push) Blocked by required conditions
CI / tests (synthesis, 64) (push) Blocked by required conditions
CI / complete (push) Blocked by required conditions
Some checks are pending
CI / setup (push) Waiting to run
CI / build (32) (push) Blocked by required conditions
CI / build (64) (push) Blocked by required conditions
CI / tests (cache, 32) (push) Blocked by required conditions
CI / tests (cache, 64) (push) Blocked by required conditions
CI / tests (config1, 32) (push) Blocked by required conditions
CI / tests (config1, 64) (push) Blocked by required conditions
CI / tests (config2, 32) (push) Blocked by required conditions
CI / tests (config2, 64) (push) Blocked by required conditions
CI / tests (debug, 32) (push) Blocked by required conditions
CI / tests (debug, 64) (push) Blocked by required conditions
CI / tests (opencl, 32) (push) Blocked by required conditions
CI / tests (opencl, 64) (push) Blocked by required conditions
CI / tests (regression, 32) (push) Blocked by required conditions
CI / tests (regression, 64) (push) Blocked by required conditions
CI / tests (scope, 32) (push) Blocked by required conditions
CI / tests (scope, 64) (push) Blocked by required conditions
CI / tests (stress, 32) (push) Blocked by required conditions
CI / tests (stress, 64) (push) Blocked by required conditions
CI / tests (synthesis, 32) (push) Blocked by required conditions
CI / tests (synthesis, 64) (push) Blocked by required conditions
CI / complete (push) Blocked by required conditions
This commit is contained in:
parent
ce510d78c7
commit
bffc6d9610
15 changed files with 1401 additions and 283 deletions
8
configure
vendored
8
configure
vendored
|
@ -65,7 +65,7 @@ copy_files() {
|
|||
filename_no_ext="${filename%.in}"
|
||||
dest_file="$dest_dir/$filename_no_ext"
|
||||
mkdir -p "$dest_dir"
|
||||
sed "s|@VORTEX_HOME@|$SCRIPT_DIR|g; s|@XLEN@|$XLEN|g; s|@TOOLDIR@|$TOOLDIR|g; s|@OSVERSION@|$OSVERSION|g; s|@INSTALLDIR@|$PREFIX|g; s|@CURRENTDIR@|$CURRENT_DIR|g" "$file" > "$dest_file"
|
||||
sed "s|@VORTEX_HOME@|$SOURCE_DIR|g; s|@XLEN@|$XLEN|g; s|@TOOLDIR@|$TOOLDIR|g; s|@OSVERSION@|$OSVERSION|g; s|@INSTALLDIR@|$PREFIX|g; s|@BUILDDIR@|$CURRENT_DIR|g" "$file" > "$dest_file"
|
||||
# apply permissions to bash scripts
|
||||
read -r firstline < "$dest_file"
|
||||
if [[ "$firstline" =~ ^#!.*bash ]]; then
|
||||
|
@ -169,8 +169,8 @@ fi
|
|||
SUBDIRS=("." "!ci" "!perf" "hw*" "kernel*" "runtime*" "sim*" "tests*")
|
||||
|
||||
# Get the directory of the script
|
||||
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||
SOURCE_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||
|
||||
THIRD_PARTY_DIR=$SCRIPT_DIR/third_party
|
||||
THIRD_PARTY_DIR=$SOURCE_DIR/third_party
|
||||
|
||||
copy_files "$SCRIPT_DIR" "$CURRENT_DIR"
|
||||
copy_files "$SOURCE_DIR" "$CURRENT_DIR"
|
||||
|
|
|
@ -160,32 +160,32 @@ endgenerate
|
|||
`ifdef QUARTUS
|
||||
`define MAX_FANOUT 8
|
||||
`define MAX_LUTRAM 1024
|
||||
`define IF_DATA_SIZE(x) $bits(x.data)
|
||||
`define USE_BLOCK_BRAM (* ramstyle = "block" *)
|
||||
`define USE_FAST_BRAM (* ramstyle = "MLAB, no_rw_check" *)
|
||||
`define NO_RW_RAM_CHECK (* altera_attribute = "-name add_pass_through_logic_to_inferred_rams off" *)
|
||||
`define DISABLE_BRAM (* ramstyle = "logic" *)
|
||||
`define PRESERVE_NET (* preserve *)
|
||||
`define BLACKBOX_CELL (* black_box *)
|
||||
`define STRING string
|
||||
`elsif VIVADO
|
||||
`define MAX_FANOUT 8
|
||||
`define MAX_LUTRAM 1024
|
||||
`define IF_DATA_SIZE(x) $bits(x.data)
|
||||
`define USE_BLOCK_BRAM (* ram_style = "block" *)
|
||||
`define USE_FAST_BRAM (* ram_style = "distributed" *)
|
||||
`define NO_RW_RAM_CHECK (* rw_addr_collision = "no" *)
|
||||
`define DISABLE_BRAM (* ram_style = "registers" *)
|
||||
`define PRESERVE_NET (* keep = "true" *)
|
||||
`define BLACKBOX_CELL (* black_box *)
|
||||
`define STRING
|
||||
`else
|
||||
`define MAX_FANOUT 8
|
||||
`define MAX_LUTRAM 1024
|
||||
`define IF_DATA_SIZE(x) x.DATA_WIDTH
|
||||
`define USE_BLOCK_BRAM
|
||||
`define USE_FAST_BRAM
|
||||
`define NO_RW_RAM_CHECK
|
||||
`define DISABLE_BRAM
|
||||
`define PRESERVE_NET
|
||||
`define BLACKBOX_CELL
|
||||
`define STRING string
|
||||
`endif
|
||||
|
||||
|
|
12
hw/rtl/cache/VX_cache_top.sv
vendored
12
hw/rtl/cache/VX_cache_top.sv
vendored
|
@ -31,28 +31,28 @@ module VX_cache_top import VX_gpu_pkg::*; #(
|
|||
parameter WORD_SIZE = 16,
|
||||
|
||||
// Core Response Queue Size
|
||||
parameter CRSQ_SIZE = 4,
|
||||
parameter CRSQ_SIZE = 8,
|
||||
// Miss Reserv Queue Knob
|
||||
parameter MSHR_SIZE = 16,
|
||||
// Memory Response Queue Size
|
||||
parameter MRSQ_SIZE = 4,
|
||||
parameter MRSQ_SIZE = 8,
|
||||
// Memory Request Queue Size
|
||||
parameter MREQ_SIZE = 4,
|
||||
parameter MREQ_SIZE = 8,
|
||||
|
||||
// Enable cache writeable
|
||||
parameter WRITE_ENABLE = 1,
|
||||
|
||||
// Enable cache writeback
|
||||
parameter WRITEBACK = 0,
|
||||
parameter WRITEBACK = 1,
|
||||
|
||||
// Enable dirty bytes on writeback
|
||||
parameter DIRTY_BYTES = 0,
|
||||
parameter DIRTY_BYTES = 1,
|
||||
|
||||
// Request debug identifier
|
||||
parameter UUID_WIDTH = 0,
|
||||
|
||||
// core request tag size
|
||||
parameter TAG_WIDTH = 16,
|
||||
parameter TAG_WIDTH = 32,
|
||||
|
||||
// Core response output buffer
|
||||
parameter CORE_OUT_BUF = 3,
|
||||
|
|
158
hw/rtl/libs/VX_async_ram_patch.sv
Normal file
158
hw/rtl/libs/VX_async_ram_patch.sv
Normal file
|
@ -0,0 +1,158 @@
|
|||
// Copyright © 2019-2023
|
||||
//
|
||||
// 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.
|
||||
|
||||
`include "VX_platform.vh"
|
||||
|
||||
`define RAM_WRITE_WREN for (integer i = 0; i < WRENW; ++i) begin \
|
||||
if (wren[i]) begin \
|
||||
ram[waddr][i * WSELW +: WSELW] <= wdata[i * WSELW +: WSELW]; \
|
||||
end \
|
||||
end
|
||||
|
||||
`define RAM_INITIALIZATION \
|
||||
if (INIT_ENABLE != 0) begin : g_init \
|
||||
if (INIT_FILE != "") begin : g_file \
|
||||
initial $readmemh(INIT_FILE, ram); \
|
||||
end else begin : g_value \
|
||||
initial begin \
|
||||
for (integer i = 0; i < SIZE; ++i) begin : g_i \
|
||||
ram[i] = INIT_VALUE; \
|
||||
end \
|
||||
end \
|
||||
end \
|
||||
end
|
||||
|
||||
`define RAM_BYPASS(__d) \
|
||||
reg [DATAW-1:0] bypass_data_r; \
|
||||
reg bypass_valid_r; \
|
||||
always @(posedge clk) begin \
|
||||
bypass_valid_r <= read_s && write && (raddr_s == waddr); \
|
||||
bypass_data_r <= wdata; \
|
||||
end \
|
||||
assign __d = bypass_valid_r ? bypass_data_r : rdata_r
|
||||
|
||||
`TRACING_OFF
|
||||
module VX_async_ram_patch #(
|
||||
parameter DATAW = 1,
|
||||
parameter SIZE = 1,
|
||||
parameter WRENW = 1,
|
||||
parameter DUAL_PORT = 0,
|
||||
parameter INIT_ENABLE = 0,
|
||||
parameter INIT_FILE = "",
|
||||
parameter [DATAW-1:0] INIT_VALUE = 0,
|
||||
parameter ADDRW = `LOG2UP(SIZE)
|
||||
) (
|
||||
input wire clk,
|
||||
input wire reset,
|
||||
input wire read,
|
||||
input wire write,
|
||||
input wire [WRENW-1:0] wren,
|
||||
input wire [ADDRW-1:0] waddr,
|
||||
input wire [DATAW-1:0] wdata,
|
||||
input wire [ADDRW-1:0] raddr,
|
||||
output wire [DATAW-1:0] rdata
|
||||
);
|
||||
localparam WSELW = DATAW / WRENW;
|
||||
|
||||
`UNUSED_VAR (reset)
|
||||
|
||||
(* keep = "true" *) wire [ADDRW-1:0] raddr_w, raddr_s;
|
||||
(* keep = "true" *) wire read_s, is_raddr_reg;
|
||||
|
||||
assign raddr_w = raddr;
|
||||
|
||||
VX_placeholder #(
|
||||
.I (ADDRW),
|
||||
.O (ADDRW + 1 + 1)
|
||||
) placeholder (
|
||||
.in (raddr_w),
|
||||
.out ({raddr_s, read_s, is_raddr_reg})
|
||||
);
|
||||
|
||||
// synchroneous ram
|
||||
|
||||
wire [DATAW-1:0] rdata_s;
|
||||
|
||||
if (WRENW != 1) begin : g_wren_sync_ram
|
||||
`USE_BLOCK_BRAM reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (read_s || write) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
rdata_r <= ram[raddr_s];
|
||||
end
|
||||
end
|
||||
`RAM_BYPASS(rdata_s);
|
||||
end else begin : g_no_wren_sync_ram
|
||||
`USE_BLOCK_BRAM reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
`RAM_INITIALIZATION
|
||||
`UNUSED_VAR (wren)
|
||||
always @(posedge clk) begin
|
||||
if (read_s || write) begin
|
||||
if (write) begin
|
||||
ram[waddr] <= wdata;
|
||||
end
|
||||
rdata_r <= ram[raddr_s];
|
||||
end
|
||||
end
|
||||
`RAM_BYPASS(rdata_s);
|
||||
end
|
||||
|
||||
// asynchronous ram (fallback)
|
||||
|
||||
wire [DATAW-1:0] rdata_a;
|
||||
|
||||
if (DUAL_PORT != 0) begin : g_dp_async_ram
|
||||
reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
if (WRENW != 1) begin : g_wren
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
end
|
||||
end else begin : g_no_wren
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
ram[waddr] <= wdata;
|
||||
end
|
||||
end
|
||||
end
|
||||
assign rdata_a = ram[raddr];
|
||||
end else begin : g_sp_async_ram
|
||||
reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
if (WRENW != 1) begin : g_wren
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
end
|
||||
end else begin : g_no_wren
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
ram[waddr] <= wdata;
|
||||
end
|
||||
end
|
||||
end
|
||||
assign rdata_a = ram[waddr];
|
||||
end
|
||||
|
||||
assign rdata = is_raddr_reg ? rdata_s : rdata_a;
|
||||
|
||||
endmodule
|
||||
`TRACING_ON
|
|
@ -13,6 +13,35 @@
|
|||
|
||||
`include "VX_platform.vh"
|
||||
|
||||
`define RAM_INITIALIZATION \
|
||||
if (INIT_ENABLE != 0) begin : g_init \
|
||||
if (INIT_FILE != "") begin : g_file \
|
||||
initial $readmemh(INIT_FILE, ram); \
|
||||
end else begin : g_value \
|
||||
initial begin \
|
||||
for (integer i = 0; i < SIZE; ++i) begin : g_i \
|
||||
ram[i] = INIT_VALUE; \
|
||||
end \
|
||||
end \
|
||||
end \
|
||||
end
|
||||
|
||||
`ifdef QUARTUS
|
||||
`define RAM_ARRAY_WREN reg [WRENW-1:0][WSELW-1:0] ram [0:SIZE-1];
|
||||
`define RAM_WRITE_WREN for (integer i = 0; i < WRENW; ++i) begin \
|
||||
if (wren[i]) begin \
|
||||
ram[waddr][i] <= wdata[i * WSELW +: WSELW]; \
|
||||
end \
|
||||
end
|
||||
`else
|
||||
`define RAM_ARRAY_WREN reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`define RAM_WRITE_WREN for (integer i = 0; i < WRENW; ++i) begin \
|
||||
if (wren[i]) begin \
|
||||
ram[waddr][i * WSELW +: WSELW] <= wdata[i * WSELW +: WSELW]; \
|
||||
end \
|
||||
end
|
||||
`endif
|
||||
|
||||
`TRACING_OFF
|
||||
module VX_dp_ram #(
|
||||
parameter DATAW = 1,
|
||||
|
@ -45,163 +74,289 @@ module VX_dp_ram #(
|
|||
`STATIC_ASSERT((RDW_MODE == "R" || RDW_MODE == "W" || RDW_MODE == "U"), ("invalid parameter"))
|
||||
`UNUSED_PARAM (RDW_ASSERT)
|
||||
|
||||
`define RAM_INITIALIZATION \
|
||||
if (INIT_ENABLE != 0) begin : g_init \
|
||||
if (INIT_FILE != "") begin : g_file \
|
||||
initial $readmemh(INIT_FILE, ram); \
|
||||
end else begin : g_value \
|
||||
initial begin \
|
||||
for (integer i = 0; i < SIZE; ++i) begin : g_i \
|
||||
ram[i] = INIT_VALUE; \
|
||||
end \
|
||||
end \
|
||||
end \
|
||||
end
|
||||
|
||||
`ifdef SYNTHESIS
|
||||
localparam FORCE_BRAM = !LUTRAM && (SIZE * DATAW >= `MAX_LUTRAM);
|
||||
`ifdef QUARTUS
|
||||
`define RAM_ARRAY reg [WRENW-1:0][WSELW-1:0] ram [0:SIZE-1];
|
||||
`define RAM_WRITE for (integer i = 0; i < WRENW; ++i) begin \
|
||||
if (wren[i]) begin \
|
||||
ram[waddr][i] <= wdata[i * WSELW +: WSELW]; \
|
||||
end \
|
||||
end
|
||||
`else
|
||||
`define RAM_ARRAY reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`define RAM_WRITE for (integer i = 0; i < WRENW; ++i) begin \
|
||||
if (wren[i]) begin \
|
||||
ram[waddr][i * WSELW +: WSELW] <= wdata[i * WSELW +: WSELW]; \
|
||||
end \
|
||||
end
|
||||
`endif
|
||||
if (OUT_REG) begin : g_sync
|
||||
if (FORCE_BRAM) begin : g_bram
|
||||
if (RDW_MODE == "W") begin : g_write_first
|
||||
(* rw_addr_collision = "yes" *) `USE_BLOCK_BRAM `RAM_ARRAY
|
||||
`UNUSED_VAR (wren)
|
||||
`RAM_INITIALIZATION
|
||||
reg [ADDRW-1:0] addr_reg;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
if (WRENW != 1) begin : g_wren
|
||||
(* rw_addr_collision = "yes" *) `USE_BLOCK_BRAM `RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
reg [ADDRW-1:0] raddr_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
raddr_r <= raddr;
|
||||
end
|
||||
addr_reg <= raddr;
|
||||
end
|
||||
assign rdata = ram[raddr_r];
|
||||
end else begin : g_no_wren
|
||||
(* rw_addr_collision = "yes" *) `USE_BLOCK_BRAM reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
reg [ADDRW-1:0] raddr_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
ram[waddr] <= wdata;
|
||||
end
|
||||
raddr_r <= raddr;
|
||||
end
|
||||
end
|
||||
assign rdata = ram[raddr_r];
|
||||
end
|
||||
assign rdata = ram[addr_reg];
|
||||
end else if (RDW_MODE == "R") begin : g_read_first
|
||||
`USE_BLOCK_BRAM `RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`USE_BLOCK_BRAM `RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
rdata_r <= ram[raddr];
|
||||
end
|
||||
rdata_r <= ram[raddr];
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end else begin : g_no_wren
|
||||
`USE_BLOCK_BRAM reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
ram[waddr] <= wdata;
|
||||
end
|
||||
rdata_r <= ram[raddr];
|
||||
end
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end else begin : g_undefined
|
||||
`USE_BLOCK_BRAM `RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`USE_BLOCK_BRAM `RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
if (read) begin
|
||||
rdata_r <= ram[raddr];
|
||||
end
|
||||
end
|
||||
if (read) begin
|
||||
rdata_r <= ram[raddr];
|
||||
assign rdata = rdata_r;
|
||||
end else begin : g_no_wren
|
||||
`USE_BLOCK_BRAM reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
ram[waddr] <= wdata;
|
||||
end
|
||||
if (read) begin
|
||||
rdata_r <= ram[raddr];
|
||||
end
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end
|
||||
end else begin : g_auto
|
||||
if (RDW_MODE == "W") begin : g_write_first
|
||||
(* rw_addr_collision = "yes" *) `RAM_ARRAY
|
||||
`UNUSED_VAR (wren)
|
||||
`RAM_INITIALIZATION
|
||||
reg [ADDRW-1:0] addr_reg;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
if (WRENW != 1) begin : g_wren
|
||||
(* rw_addr_collision = "yes" *) `RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
reg [ADDRW-1:0] raddr_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
raddr_r <= raddr;
|
||||
end
|
||||
addr_reg <= raddr;
|
||||
end
|
||||
assign rdata = ram[raddr_r];
|
||||
end else begin : g_no_wren
|
||||
(* rw_addr_collision = "yes" *) reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
reg [ADDRW-1:0] raddr_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
ram[waddr] <= wdata;
|
||||
end
|
||||
raddr_r <= raddr;
|
||||
end
|
||||
end
|
||||
assign rdata = ram[raddr_r];
|
||||
end
|
||||
assign rdata = ram[addr_reg];
|
||||
end else if (RDW_MODE == "R") begin : g_read_first
|
||||
`RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
rdata_r <= ram[raddr];
|
||||
end
|
||||
rdata_r <= ram[raddr];
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end else begin : g_no_wren
|
||||
reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
ram[waddr] <= wdata;
|
||||
end
|
||||
rdata_r <= ram[raddr];
|
||||
end
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end else begin
|
||||
`RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
if (read) begin
|
||||
rdata_r <= ram[raddr];
|
||||
end
|
||||
end
|
||||
if (read) begin
|
||||
rdata_r <= ram[raddr];
|
||||
assign rdata = rdata_r;
|
||||
end else begin : g_no_wren
|
||||
reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
ram[waddr] <= wdata;
|
||||
end
|
||||
if (read) begin
|
||||
rdata_r <= ram[raddr];
|
||||
end
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end
|
||||
end
|
||||
end else begin : g_async
|
||||
`UNUSED_VAR (read)
|
||||
if (FORCE_BRAM) begin : g_bram
|
||||
if (RDW_MODE == "W") begin : g_write_first
|
||||
`USE_BLOCK_BRAM `RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
`ifdef VIVADO
|
||||
VX_async_ram_patch #(
|
||||
.DATAW (DATAW),
|
||||
.SIZE (SIZE),
|
||||
.WRENW (WRENW),
|
||||
.DUAL_PORT (1),
|
||||
.INIT_ENABLE(INIT_ENABLE),
|
||||
.INIT_FILE (INIT_FILE),
|
||||
.INIT_VALUE (INIT_VALUE)
|
||||
) async_ram_patch (
|
||||
.clk (clk),
|
||||
.reset (reset),
|
||||
.read (read),
|
||||
.write (write),
|
||||
.wren (wren),
|
||||
.waddr (waddr),
|
||||
.wdata (wdata),
|
||||
.raddr (raddr),
|
||||
.rdata (rdata)
|
||||
);
|
||||
`else
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`USE_BLOCK_BRAM `RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
end
|
||||
assign rdata = ram[raddr];
|
||||
end else begin : g_no_wren
|
||||
`USE_BLOCK_BRAM reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
ram[waddr] <= wdata;
|
||||
end
|
||||
end
|
||||
assign rdata = ram[raddr];
|
||||
end
|
||||
assign rdata = ram[raddr];
|
||||
`endif
|
||||
end else begin : g_read_first
|
||||
`NO_RW_RAM_CHECK `USE_BLOCK_BRAM `RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`NO_RW_RAM_CHECK `USE_BLOCK_BRAM `RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
end
|
||||
assign rdata = ram[raddr];
|
||||
end else begin : g_no_wren
|
||||
`NO_RW_RAM_CHECK `USE_BLOCK_BRAM reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
ram[waddr] <= wdata;
|
||||
end
|
||||
end
|
||||
assign rdata = ram[raddr];
|
||||
end
|
||||
assign rdata = ram[raddr];
|
||||
end
|
||||
end else begin : g_auto
|
||||
if (RDW_MODE == "W") begin : g_write_first
|
||||
`RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
end
|
||||
assign rdata = ram[raddr];
|
||||
end else begin : g_no_wren
|
||||
reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
ram[waddr] <= wdata;
|
||||
end
|
||||
end
|
||||
assign rdata = ram[raddr];
|
||||
end
|
||||
assign rdata = ram[raddr];
|
||||
end else begin : g_read_first
|
||||
`NO_RW_RAM_CHECK `RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`NO_RW_RAM_CHECK `RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
end
|
||||
assign rdata = ram[raddr];
|
||||
end else begin : g_no_wren
|
||||
`NO_RW_RAM_CHECK reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
ram[waddr] <= wdata;
|
||||
end
|
||||
end
|
||||
assign rdata = ram[raddr];
|
||||
end
|
||||
assign rdata = ram[raddr];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -226,13 +381,13 @@ module VX_dp_ram #(
|
|||
|
||||
if (OUT_REG) begin : g_sync
|
||||
if (RDW_MODE == "W") begin : g_write_first
|
||||
reg [ADDRW-1:0] addr_reg;
|
||||
reg [ADDRW-1:0] raddr_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
addr_reg <= raddr;
|
||||
raddr_r <= raddr;
|
||||
end
|
||||
end
|
||||
assign rdata = ram[addr_reg];
|
||||
assign rdata = ram[raddr_r];
|
||||
end else if (RDW_MODE == "R") begin : g_read_first
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
|
||||
`TRACING_OFF
|
||||
module VX_fifo_queue #(
|
||||
parameter DATAW = 1,
|
||||
parameter DEPTH = 1,
|
||||
parameter DATAW = 32,
|
||||
parameter DEPTH = 32,
|
||||
parameter ALM_FULL = (DEPTH - 1),
|
||||
parameter ALM_EMPTY = 1,
|
||||
parameter OUT_REG = 0,
|
||||
|
|
27
hw/rtl/libs/VX_placeholder.sv
Normal file
27
hw/rtl/libs/VX_placeholder.sv
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright © 2019-2023
|
||||
//
|
||||
// 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.
|
||||
|
||||
`include "VX_platform.vh"
|
||||
|
||||
`TRACING_OFF
|
||||
`BLACKBOX_CELL module VX_placeholder #(
|
||||
parameter I = 0,
|
||||
parameter O = 0
|
||||
) (
|
||||
input wire [`UP(I)-1:0] in,
|
||||
output wire [`UP(O)-1:0] out
|
||||
);
|
||||
// empty module
|
||||
|
||||
endmodule
|
||||
`TRACING_ON
|
|
@ -13,6 +13,35 @@
|
|||
|
||||
`include "VX_platform.vh"
|
||||
|
||||
`define RAM_INITIALIZATION \
|
||||
if (INIT_ENABLE != 0) begin : g_init \
|
||||
if (INIT_FILE != "") begin : g_file \
|
||||
initial $readmemh(INIT_FILE, ram); \
|
||||
end else begin : g_value \
|
||||
initial begin \
|
||||
for (integer i = 0; i < SIZE; ++i) begin : g_i \
|
||||
ram[i] = INIT_VALUE; \
|
||||
end \
|
||||
end \
|
||||
end \
|
||||
end
|
||||
|
||||
`ifdef QUARTUS
|
||||
`define RAM_ARRAY_WREN reg [WRENW-1:0][WSELW-1:0] ram [0:SIZE-1];
|
||||
`define RAM_WRITE_WREN for (integer i = 0; i < WRENW; ++i) begin \
|
||||
if (wren[i]) begin \
|
||||
ram[addr][i] <= wdata[i * WSELW +: WSELW]; \
|
||||
end \
|
||||
end
|
||||
`else
|
||||
`define RAM_ARRAY_WREN reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`define RAM_WRITE_WREN for (integer i = 0; i < WRENW; ++i) begin \
|
||||
if (wren[i]) begin \
|
||||
ram[addr][i * WSELW +: WSELW] <= wdata[i * WSELW +: WSELW]; \
|
||||
end \
|
||||
end
|
||||
`endif
|
||||
|
||||
`TRACING_OFF
|
||||
module VX_sp_ram #(
|
||||
parameter DATAW = 1,
|
||||
|
@ -44,67 +73,55 @@ module VX_sp_ram #(
|
|||
`STATIC_ASSERT((RDW_MODE == "R" || RDW_MODE == "W" || RDW_MODE == "N"), ("invalid parameter"))
|
||||
`UNUSED_PARAM (RDW_ASSERT)
|
||||
|
||||
`define RAM_INITIALIZATION \
|
||||
if (INIT_ENABLE != 0) begin : g_init \
|
||||
if (INIT_FILE != "") begin : g_file \
|
||||
initial $readmemh(INIT_FILE, ram); \
|
||||
end else begin : g_value \
|
||||
initial begin \
|
||||
for (integer i = 0; i < SIZE; ++i) begin : g_i \
|
||||
ram[i] = INIT_VALUE; \
|
||||
end \
|
||||
end \
|
||||
end \
|
||||
end
|
||||
|
||||
`ifdef SYNTHESIS
|
||||
localparam FORCE_BRAM = !LUTRAM && (SIZE * DATAW >= `MAX_LUTRAM);
|
||||
`ifdef QUARTUS
|
||||
`define RAM_ARRAY reg [WRENW-1:0][WSELW-1:0] ram [0:SIZE-1];
|
||||
`define RAM_WRITE for (integer i = 0; i < WRENW; ++i) begin \
|
||||
if (wren[i]) begin \
|
||||
ram[addr][i] <= wdata[i * WSELW +: WSELW]; \
|
||||
end \
|
||||
end
|
||||
`else
|
||||
`define RAM_ARRAY reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`define RAM_WRITE for (integer i = 0; i < WRENW; ++i) begin \
|
||||
if (wren[i]) begin \
|
||||
ram[addr][i * WSELW +: WSELW] <= wdata[i * WSELW +: WSELW]; \
|
||||
end \
|
||||
end
|
||||
`endif
|
||||
if (OUT_REG) begin : g_sync
|
||||
if (FORCE_BRAM) begin : g_bram
|
||||
if (RDW_MODE == "R") begin : g_read_first
|
||||
`USE_BLOCK_BRAM `RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
end
|
||||
rdata_r <= ram[addr];
|
||||
end
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end else if (RDW_MODE == "W") begin : g_write_first
|
||||
`USE_BLOCK_BRAM `RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
if (WRENW > 1) begin : g_wren
|
||||
reg [ADDRW-1:0] addr_reg;
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`USE_BLOCK_BRAM `RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
addr_reg <= addr;
|
||||
rdata_r <= ram[addr];
|
||||
end
|
||||
end
|
||||
assign rdata = ram[addr_reg];
|
||||
assign rdata = rdata_r;
|
||||
end else begin : g_no_wren
|
||||
`UNUSED_VAR (wren)
|
||||
`USE_BLOCK_BRAM reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
ram[addr] <= wdata;
|
||||
end
|
||||
rdata_r <= ram[addr];
|
||||
end
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end
|
||||
end else if (RDW_MODE == "W") begin : g_write_first
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`USE_BLOCK_BRAM `RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
reg [ADDRW-1:0] addr_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
addr_r <= addr;
|
||||
end
|
||||
end
|
||||
assign rdata = ram[addr_r];
|
||||
end else begin : g_no_wren
|
||||
`USE_BLOCK_BRAM reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
|
@ -119,63 +136,110 @@ module VX_sp_ram #(
|
|||
assign rdata = rdata_r;
|
||||
end
|
||||
end else if (RDW_MODE == "N") begin : g_no_change
|
||||
`USE_BLOCK_BRAM `RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`USE_BLOCK_BRAM `RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end else begin
|
||||
rdata_r <= ram[addr];
|
||||
end
|
||||
end
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end else begin : g_no_wren
|
||||
`USE_BLOCK_BRAM reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
ram[addr] <= wdata;
|
||||
end else begin
|
||||
rdata_r <= ram[addr];
|
||||
end
|
||||
end
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end
|
||||
end else if (RDW_MODE == "U") begin : g_unknown
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`USE_BLOCK_BRAM `RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
end else begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
if (read) begin
|
||||
rdata_r <= ram[addr];
|
||||
end
|
||||
end
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end else if (RDW_MODE == "U") begin : g_unknown
|
||||
`USE_BLOCK_BRAM `RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
end
|
||||
if (read) begin
|
||||
rdata_r <= ram[addr];
|
||||
assign rdata = rdata_r;
|
||||
end else begin : g_no_wren
|
||||
`USE_BLOCK_BRAM reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
ram[addr] <= wdata;
|
||||
end
|
||||
if (read) begin
|
||||
rdata_r <= ram[addr];
|
||||
end
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end
|
||||
end else begin : g_auto
|
||||
if (RDW_MODE == "R") begin : g_read_first
|
||||
`RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
end
|
||||
rdata_r <= ram[addr];
|
||||
end
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end else if (RDW_MODE == "W") begin : g_write_first
|
||||
`RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
if (WRENW > 1) begin : g_wren
|
||||
reg [ADDRW-1:0] addr_reg;
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
addr_reg <= addr;
|
||||
rdata_r <= ram[addr];
|
||||
end
|
||||
end
|
||||
assign rdata = ram[addr_reg];
|
||||
assign rdata = rdata_r;
|
||||
end else begin : g_no_wren
|
||||
`UNUSED_VAR (wren)
|
||||
reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
ram[addr] <= wdata;
|
||||
end
|
||||
rdata_r <= ram[addr];
|
||||
end
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end
|
||||
end else if (RDW_MODE == "W") begin : g_write_first
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
reg [ADDRW-1:0] addr_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
addr_r <= addr;
|
||||
end
|
||||
end
|
||||
assign rdata = ram[addr_r];
|
||||
end else begin : g_no_wren
|
||||
reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
|
@ -190,75 +254,172 @@ module VX_sp_ram #(
|
|||
assign rdata = rdata_r;
|
||||
end
|
||||
end else if (RDW_MODE == "N") begin : g_no_change
|
||||
`RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end else begin
|
||||
rdata_r <= ram[addr];
|
||||
end
|
||||
end
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end else begin : g_no_wren
|
||||
reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
if (write) begin
|
||||
ram[addr] <= wdata;
|
||||
end else begin
|
||||
rdata_r <= ram[addr];
|
||||
end
|
||||
end
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end
|
||||
end else if (RDW_MODE == "U") begin : g_unknown
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
end else begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
if (read) begin
|
||||
rdata_r <= ram[addr];
|
||||
end
|
||||
end
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end else if (RDW_MODE == "U") begin : g_unknown
|
||||
`RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
end
|
||||
if (read) begin
|
||||
rdata_r <= ram[addr];
|
||||
assign rdata = rdata_r;
|
||||
end else begin : g_no_wren
|
||||
reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
ram[addr] <= wdata;
|
||||
end
|
||||
if (read) begin
|
||||
rdata_r <= ram[addr];
|
||||
end
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end
|
||||
assign rdata = rdata_r;
|
||||
end
|
||||
end
|
||||
end else begin : g_async
|
||||
`UNUSED_VAR (read)
|
||||
if (FORCE_BRAM) begin : g_bram
|
||||
if (RDW_MODE == "W") begin : g_write_first
|
||||
`USE_BLOCK_BRAM `RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
`ifdef VIVADO
|
||||
VX_async_ram_patch #(
|
||||
.DATAW (DATAW),
|
||||
.SIZE (SIZE),
|
||||
.WRENW (WRENW),
|
||||
.DUAL_PORT (0),
|
||||
.INIT_ENABLE(INIT_ENABLE),
|
||||
.INIT_FILE (INIT_FILE),
|
||||
.INIT_VALUE (INIT_VALUE)
|
||||
) async_ram_patch (
|
||||
.clk (clk),
|
||||
.reset (reset),
|
||||
.read (read),
|
||||
.write (write),
|
||||
.wren (wren),
|
||||
.waddr (addr),
|
||||
.wdata (wdata),
|
||||
.raddr (addr),
|
||||
.rdata (rdata)
|
||||
);
|
||||
`else
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`USE_BLOCK_BRAM `RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
end
|
||||
assign rdata = ram[addr];
|
||||
end else begin : g_no_wren
|
||||
`USE_BLOCK_BRAM reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
ram[addr] <= wdata;
|
||||
end
|
||||
end
|
||||
assign rdata = ram[addr];
|
||||
end
|
||||
assign rdata = ram[addr];
|
||||
`endif
|
||||
end else begin : g_read_first
|
||||
`NO_RW_RAM_CHECK `USE_BLOCK_BRAM `RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`NO_RW_RAM_CHECK `USE_BLOCK_BRAM `RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
end
|
||||
assign rdata = ram[addr];
|
||||
end else begin : g_no_wren
|
||||
`NO_RW_RAM_CHECK `USE_BLOCK_BRAM reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
ram[addr] <= wdata;
|
||||
end
|
||||
end
|
||||
assign rdata = ram[addr];
|
||||
end
|
||||
assign rdata = ram[addr];
|
||||
end
|
||||
end else begin : g_auto
|
||||
if (RDW_MODE == "W") begin : g_write_first
|
||||
`RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
end
|
||||
assign rdata = ram[addr];
|
||||
end else begin : g_no_wren
|
||||
reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
ram[addr] <= wdata;
|
||||
end
|
||||
end
|
||||
assign rdata = ram[addr];
|
||||
end
|
||||
assign rdata = ram[addr];
|
||||
end else begin : g_read_first
|
||||
`NO_RW_RAM_CHECK `RAM_ARRAY
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE
|
||||
if (WRENW != 1) begin : g_wren
|
||||
`NO_RW_RAM_CHECK `RAM_ARRAY_WREN
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
`RAM_WRITE_WREN
|
||||
end
|
||||
end
|
||||
assign rdata = ram[addr];
|
||||
end else begin : g_no_wren
|
||||
`NO_RW_RAM_CHECK reg [DATAW-1:0] ram [0:SIZE-1];
|
||||
`RAM_INITIALIZATION
|
||||
always @(posedge clk) begin
|
||||
if (write) begin
|
||||
ram[addr] <= wdata;
|
||||
end
|
||||
end
|
||||
assign rdata = ram[addr];
|
||||
end
|
||||
assign rdata = ram[addr];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -291,13 +452,13 @@ module VX_sp_ram #(
|
|||
end
|
||||
assign rdata = rdata_r;
|
||||
end else if (RDW_MODE == "W") begin : g_write_first
|
||||
reg [ADDRW-1:0] addr_reg;
|
||||
reg [ADDRW-1:0] addr_r;
|
||||
always @(posedge clk) begin
|
||||
if (read || write) begin
|
||||
addr_reg <= addr;
|
||||
addr_r <= addr;
|
||||
end
|
||||
end
|
||||
assign rdata = ram[addr_reg];
|
||||
assign rdata = ram[addr_r];
|
||||
end else if (RDW_MODE == "N") begin : g_no_change
|
||||
reg [DATAW-1:0] rdata_r;
|
||||
always @(posedge clk) begin
|
||||
|
|
525
hw/scripts/xilinx_async_bram_patch.tcl
Normal file
525
hw/scripts/xilinx_async_bram_patch.tcl
Normal file
|
@ -0,0 +1,525 @@
|
|||
namespace eval vortex {
|
||||
|
||||
variable debug 0
|
||||
|
||||
proc print_error {msg {do_exit 1}} {
|
||||
if {$do_exit} {
|
||||
puts "ERROR: $msg"
|
||||
exit -1
|
||||
} else {
|
||||
puts "WARNING: $msg"
|
||||
}
|
||||
}
|
||||
|
||||
proc str_replace {str match repl} {
|
||||
set result ""
|
||||
regsub $match $str $repl result
|
||||
return $result
|
||||
}
|
||||
|
||||
proc unique_cell_name {name} {
|
||||
if {[get_cells -quiet $name] == {}} { return $name }
|
||||
set index 0
|
||||
while {[get_cells -quiet ${name}_${index}] != {}} { incr index }
|
||||
return ${name}_${index}
|
||||
}
|
||||
|
||||
proc unique_net_name {name} {
|
||||
if {[get_nets -quiet $name] == {}} { return $name }
|
||||
set index 0
|
||||
while {[get_nets -quiet ${name}_${index}] != {}} { incr index }
|
||||
return ${name}_${index}
|
||||
}
|
||||
|
||||
proc find_nested_cells {parent name_match {should_exist 1}} {
|
||||
set matching_cells {}
|
||||
foreach cell [get_cells -hierarchical -include_replicated_objects -filter "PARENT == $parent"] {
|
||||
set name [get_property NAME $cell]
|
||||
if {[regexp $name_match $name]} {
|
||||
lappend matching_cells $cell
|
||||
}
|
||||
}
|
||||
if {[llength $matching_cells] == 0} {
|
||||
print_error "No matching cell found for '$parent' matching '$name_match'." $should_exist
|
||||
}
|
||||
return $matching_cells
|
||||
}
|
||||
|
||||
proc find_nested_cell {parent name_match} {
|
||||
foreach cell [get_cells -hierarchical -filter "PARENT == $parent"] {
|
||||
set name [get_property NAME $cell]
|
||||
if {$name == $name_match} {
|
||||
return $cell
|
||||
}
|
||||
}
|
||||
puts "ERROR: No matching cell found for '$parent' matching '$name_match'."
|
||||
exit -1
|
||||
}
|
||||
|
||||
proc find_cell_nets {cell name_match {should_exist 1}} {
|
||||
set matching_nets {}
|
||||
foreach net [get_nets -hierarchical -filter "PARENT_CELL == $cell"] {
|
||||
set name [get_property NAME $net]
|
||||
if {[regexp $name_match $name]} {
|
||||
lappend matching_nets $net
|
||||
}
|
||||
}
|
||||
if {[llength $matching_nets] == 0} {
|
||||
print_error "No matching net found for '$cell' matching '$name_match'." $should_exist
|
||||
}
|
||||
return $matching_nets
|
||||
}
|
||||
|
||||
proc get_cell_net {cell name_match} {
|
||||
foreach net [get_nets -hierarchical -filter "PARENT_CELL == $cell"] {
|
||||
set name [get_property NAME $net]
|
||||
if {$name == $name_match} {
|
||||
return $net
|
||||
}
|
||||
}
|
||||
puts "ERROR: No matching net found for '$cell' matching '$name_match'."
|
||||
exit -1
|
||||
}
|
||||
|
||||
proc find_cell_pins {cell name_match {should_exist 1}} {
|
||||
set matching_pins {}
|
||||
foreach pin [get_pins -of_objects $cell] {
|
||||
set name [get_property NAME $pin]
|
||||
if {[regexp $name_match $name]} {
|
||||
lappend matching_pins $pin
|
||||
}
|
||||
}
|
||||
if {[llength $matching_pins] == 0} {
|
||||
print_error "No matching pin found for '$cell' matching '$name_match'." $should_exist
|
||||
}
|
||||
return $matching_pins
|
||||
}
|
||||
|
||||
proc get_cell_pin {cell name_match} {
|
||||
foreach pin [get_pins -of_objects $cell] {
|
||||
set name [get_property NAME $pin]
|
||||
if {$name == $name_match} {
|
||||
return $pin
|
||||
}
|
||||
}
|
||||
puts "ERROR: No matching pin found for '$cell' matching '$name_match'."
|
||||
exit -1
|
||||
}
|
||||
|
||||
proc replace_pin_source {pin source_pin} {
|
||||
variable debug
|
||||
|
||||
# Disconnect existing net from pin
|
||||
set net [get_nets -of_objects $pin]
|
||||
if {[llength $net] == 1} {
|
||||
disconnect_net -net $net -objects $pin
|
||||
if {$debug} {puts "DEBUG: Disconnected net '$net' from pin '$pin'."}
|
||||
} elseif {[llength $net] > 1} {
|
||||
puts "ERROR: Multiple nets connected to pin '$pin'."
|
||||
exit -1
|
||||
} else {
|
||||
puts "WARNING: No net connected to pin '$pin'."
|
||||
}
|
||||
|
||||
set source_net [get_nets -quiet -of_objects $source_pin]
|
||||
if {[llength $source_net] == 0} {
|
||||
# Create a new net if none exists
|
||||
set source_cell [get_cells -of_objects $source_pin]
|
||||
set net_name [unique_net_name "${source_cell}_net"]
|
||||
set source_net [create_net $net_name]
|
||||
if {$debug} {puts "DEBUG: Created source_net: '$source_net'"}
|
||||
# Connect the source pin to the new net
|
||||
connect_net -net $source_net -objects $source_pin -hierarchical
|
||||
if {$debug} {puts "DEBUG: Connected net '$source_net' to pin '$source_pin'."}
|
||||
} elseif {[llength $source_net] > 1} {
|
||||
puts "ERROR: Multiple nets connected to pin '$source_pin'."
|
||||
exit -1
|
||||
}
|
||||
|
||||
# Connect pin to the new source net
|
||||
connect_net -net $source_net -objects $pin -hierarchical
|
||||
if {$debug} {puts "DEBUG: Connected net '$source_net' to pin '$pin'."}
|
||||
}
|
||||
|
||||
proc create_register_next {reg_cell prefix_name} {
|
||||
variable debug
|
||||
|
||||
set reg_d_pin [get_pins -of_objects $reg_cell -filter {NAME =~ "*/D"}]
|
||||
if {[llength $reg_d_pin] == 0} {
|
||||
puts "ERROR: No D pin found on register cell '$reg_cell'."
|
||||
exit -1
|
||||
} elseif {[llength $reg_d_pin] > 1} {
|
||||
puts "ERROR: Multiple D pins found on register cell '$reg_cell'."
|
||||
exit -1
|
||||
}
|
||||
|
||||
if {$debug} {puts "DEBUG: reg_d_pin: '$reg_d_pin'"}
|
||||
|
||||
set reg_d_src_pin [find_pin_driver $reg_d_pin]
|
||||
if {$reg_d_src_pin == ""} {
|
||||
puts "ERROR: No source pin found connected to '$reg_d_pin'."
|
||||
exit -1
|
||||
}
|
||||
|
||||
if {$debug} {puts "DEBUG: reg_d_src_pin: '$reg_d_src_pin'"}
|
||||
|
||||
set reg_r_src_pin ""
|
||||
|
||||
set register_type [get_property REF_NAME $reg_cell]
|
||||
if {$register_type == "FDRE"} {
|
||||
set reg_r_pin [get_pins -of_objects $reg_cell -filter {NAME =~ "*/R"}]
|
||||
if {[llength $reg_r_pin] == 0} {
|
||||
puts "ERROR: No R pin found on FDRE cell '$reg_cell'."
|
||||
exit -1
|
||||
} elseif {[llength $reg_r_pin] > 1} {
|
||||
puts "ERROR: Multiple R pins found on FDRE cell '$reg_cell'."
|
||||
exit -1
|
||||
}
|
||||
|
||||
if {$debug} {puts "DEBUG: reg_r_pin: '$reg_r_pin'"}
|
||||
|
||||
set reg_r_src_pin [find_pin_driver $reg_r_pin]
|
||||
if {$reg_r_src_pin == ""} {
|
||||
puts "ERROR: No source pin found connected to '$reg_r_pin'."
|
||||
exit -1
|
||||
}
|
||||
} elseif {$register_type == "FDSE"} {
|
||||
set reg_s_pin [get_pins -of_objects $reg_cell -filter {NAME =~ "*/S"}]
|
||||
if {[llength $reg_s_pin] == 0} {
|
||||
puts "ERROR: No S pin found on FDSE cell '$reg_cell'."
|
||||
exit -1
|
||||
} elseif {[llength $reg_s_pin] > 1} {
|
||||
puts "ERROR: Multiple S pins found on FDSE cell '$reg_cell'."
|
||||
exit -1
|
||||
}
|
||||
|
||||
if {$debug} {puts "DEBUG: reg_s_pin: '$reg_s_pin'"}
|
||||
|
||||
set reg_r_src_pin [find_pin_driver $reg_s_pin]
|
||||
if {$reg_r_src_pin == ""} {
|
||||
puts "ERROR: No source pin found connected to '$reg_s_pin'."
|
||||
exit -1
|
||||
}
|
||||
} else {
|
||||
puts "ERROR: Unsupported register type: '$register_type'."
|
||||
exit 1
|
||||
}
|
||||
|
||||
if {$debug} {puts "DEBUG: reg_r_src_pin: '$reg_r_src_pin'"}
|
||||
|
||||
set reg_d_src_net [get_nets -of_objects $reg_d_src_pin]
|
||||
if {[llength $reg_d_src_net] == 0} {
|
||||
puts "ERROR: Unable to get source nets for pins."
|
||||
exit -1
|
||||
} elseif {[llength $reg_d_src_net] > 1} {
|
||||
puts "ERROR: Multiple source nets found for pins."
|
||||
exit -1
|
||||
}
|
||||
|
||||
set reg_r_src_net [get_nets -of_objects $reg_r_src_pin]
|
||||
if {[llength $reg_r_src_net] == 0} {
|
||||
puts "ERROR: Unable to get source nets for pins."
|
||||
exit -1
|
||||
} elseif {[llength $reg_r_src_net] > 1} {
|
||||
puts "ERROR: Multiple source nets found for pins."
|
||||
exit -1
|
||||
}
|
||||
|
||||
# Create a MUX cell to implement register next value
|
||||
# Use a 2x1 LUT to describe the logic:
|
||||
# FDRE: O = I1 ? 0 : I0; where I0=D, I1=R
|
||||
# FDSE: O = I1 ? 1 : I0; where I0=D, I1=S
|
||||
set lut_name [unique_cell_name $prefix_name]
|
||||
set lut_cell [create_cell -reference LUT2 $lut_name]
|
||||
puts "INFO: Created lut cell: '$lut_cell'"
|
||||
|
||||
if {$register_type == "FDRE"} {
|
||||
set_property INIT 4'b0010 $lut_cell
|
||||
} elseif {$register_type == "FDSE"} {
|
||||
set_property INIT 4'b1110 $lut_cell
|
||||
} else {
|
||||
puts "ERROR: Unsupported register type: '$register_type'."
|
||||
exit 1
|
||||
}
|
||||
|
||||
set lut_i0_pin [get_pins -of_objects $lut_cell -filter {NAME =~ "*/I0"}]
|
||||
if {[llength $lut_i0_pin] == 0} {
|
||||
puts "ERROR: No I0 pin found on FDSE cell '$lut_cell'."
|
||||
exit -1
|
||||
} elseif {[llength $lut_i0_pin] > 1} {
|
||||
puts "ERROR: Multiple I0 pins found on FDSE cell '$lut_cell'."
|
||||
exit -1
|
||||
}
|
||||
|
||||
set lut_i1_pin [get_pins -of_objects $lut_cell -filter {NAME =~ "*/I1"}]
|
||||
if {[llength $lut_i1_pin] == 0} {
|
||||
puts "ERROR: No I1 pin found on FDSE cell '$lut_cell'."
|
||||
exit -1
|
||||
} elseif {[llength $lut_i1_pin] > 1} {
|
||||
puts "ERROR: Multiple I1 pins found on FDSE cell '$lut_cell'."
|
||||
exit -1
|
||||
}
|
||||
|
||||
set lut_o_pin [get_pins -of_objects $lut_cell -filter {NAME =~ "*/O"}]
|
||||
if {[llength $lut_o_pin] == 0} {
|
||||
puts "ERROR: No O pin found on FDSE cell '$lut_cell'."
|
||||
exit -1
|
||||
} elseif {[llength $lut_o_pin] > 1} {
|
||||
puts "ERROR: Multiple O pins found on FDSE cell '$lut_cell'."
|
||||
exit -1
|
||||
}
|
||||
|
||||
connect_net -net $reg_d_src_net -objects $lut_i0_pin -hierarchical
|
||||
if {$debug} {puts "DEBUG: Connected net '$reg_d_src_net' to pin '$lut_i0_pin'."}
|
||||
|
||||
connect_net -net $reg_r_src_net -objects $lut_i1_pin -hierarchical
|
||||
if {$debug} {puts "DEBUG: Connected net '$reg_r_src_net' to pin '$lut_i1_pin'."}
|
||||
|
||||
return $lut_o_pin
|
||||
}
|
||||
|
||||
proc getOrCreateVCCPin {prefix_name} {
|
||||
variable debug
|
||||
|
||||
set vcc_cell ""
|
||||
set vcc_cells [get_cells -quiet -filter {REF_NAME == VCC}]
|
||||
if {[llength $vcc_cells] == 0} {
|
||||
set cell_name [unique_cell_name $prefix_name]
|
||||
set vcc_cell [create_cell -reference VCC $cell_name]
|
||||
puts "INFO: Created VCC cell: '$vcc_cell'"
|
||||
} else {
|
||||
set vcc_cell [lindex $vcc_cells 0]
|
||||
}
|
||||
set vcc_pin [get_pins -of_objects $vcc_cell -filter {NAME =~ "*/P"}]
|
||||
if {[llength $vcc_pin] == 0} {
|
||||
puts "ERROR: No VCC pin found on VCC cell '$vcc_cell'."
|
||||
exit -1
|
||||
} elseif {[llength $vcc_pin] > 1} {
|
||||
puts "ERROR: Multiple VCC pins found on VCC cell '$vcc_cell'."
|
||||
exit -1
|
||||
}
|
||||
return $vcc_pin
|
||||
}
|
||||
|
||||
proc getOrCreateGNDPin {prefix_name} {
|
||||
variable debug
|
||||
|
||||
set gnd_cell ""
|
||||
set gnd_cells [get_cells -quiet -filter {REF_NAME == GND}]
|
||||
if {[llength $gnd_cells] == 0} {
|
||||
set cell_name [unique_cell_name $prefix_name]
|
||||
set gnd_cell [create_cell -reference GND $cell_name]
|
||||
puts "INFO: Created GND cell: '$gnd_cell'"
|
||||
} else {
|
||||
set gnd_cell [lindex $gnd_cells 0]
|
||||
}
|
||||
set gnd_pin [get_pins -of_objects $gnd_cell -filter {NAME =~ "*/G"}]
|
||||
if {[llength $gnd_pin] == 0} {
|
||||
puts "ERROR: No GND pin found on GND cell '$gnd_cell'."
|
||||
exit -1
|
||||
} elseif {[llength $gnd_pin] > 1} {
|
||||
puts "ERROR: Multiple GND pins found on GND cell '$gnd_cell'."
|
||||
exit -1
|
||||
}
|
||||
return $gnd_pin
|
||||
}
|
||||
|
||||
proc find_net_sinks {input_net {should_exist 1}} {
|
||||
set sink_pins {}
|
||||
foreach pin [get_pins -quiet -leaf -of_objects $input_net -filter {DIRECTION == "IN"}] {
|
||||
lappend sink_pins $pin
|
||||
}
|
||||
foreach port [get_ports -quiet -of_objects $input_net -filter {DIRECTION == "OUT"}] {
|
||||
lappend sink_pins $port
|
||||
}
|
||||
if {[llength $sink_pins] == 0} {
|
||||
print_error "No sink found for '$input_net'." $should_exist
|
||||
}
|
||||
return $sink_pins
|
||||
}
|
||||
|
||||
proc find_net_driver {input_net {should_exist 1}} {
|
||||
set driverPins [get_pins -quiet -leaf -of_objects $input_net -filter {DIRECTION == "OUT"}]
|
||||
if {[llength $driverPins] == 0} {
|
||||
set driverPorts [get_ports -quiet -of_objects $input_net -filter {DIRECTION == "IN"}]
|
||||
if {[llength $driverPorts] == 0} {
|
||||
print_error "No driver found for '$input_net'." $should_exist
|
||||
} elseif {[llength $driverPorts] > 1} {
|
||||
puts "WARNING: Multiple driver ports found for '$input_net'."
|
||||
return [lindex $driverPorts 0]
|
||||
}
|
||||
return $driverPorts
|
||||
} elseif {[llength $driverPins] > 1} {
|
||||
puts "WARNING: Multiple driver pins found for '$input_net'."
|
||||
return [lindex $driverPins 0]
|
||||
}
|
||||
return $driverPins
|
||||
}
|
||||
|
||||
proc find_pin_driver {input_pin {should_exist 1}} {
|
||||
set net [get_nets -quiet -of_objects $input_pin]
|
||||
if {[llength $net] == 0} {
|
||||
print_error "No net connected to pin '$input_pin'." $should_exist
|
||||
} elseif {[llength $net] > 1} {
|
||||
puts "ERROR: Multiple nets connected to pin '$input_pin'."
|
||||
exit -1
|
||||
}
|
||||
return [find_net_driver $net]
|
||||
}
|
||||
|
||||
proc find_matching_nets {cell nets match repl} {
|
||||
set matching_nets {}
|
||||
foreach net $nets {
|
||||
set net_name [str_replace $net $match $repl]
|
||||
set matching_net [get_cell_net $cell $net_name]
|
||||
if {$matching_net != ""} {
|
||||
lappend matching_nets $matching_net
|
||||
}
|
||||
}
|
||||
if {[llength $matching_nets] == 0} {
|
||||
puts "ERROR: No matching nets found for '$nets'."
|
||||
exit -1
|
||||
} elseif {[llength $matching_nets] != [llength $nets]} {
|
||||
puts "ERROR: Mismatch in number of matching nets."
|
||||
exit -1
|
||||
}
|
||||
return $matching_nets
|
||||
}
|
||||
|
||||
proc replace_net_source {net source_pin} {
|
||||
foreach pin [find_net_sinks $net 0] {
|
||||
replace_pin_source $pin $source_pin
|
||||
}
|
||||
}
|
||||
|
||||
proc resolve_async_bram {inst} {
|
||||
variable debug
|
||||
|
||||
puts "INFO: Resolving asynchronous BRAM patch: '$inst'."
|
||||
|
||||
set raddr_w_nets [find_cell_nets $inst "raddr_w(\\\[\\d+\\\])?$"]
|
||||
set read_s_net [find_cell_nets $inst "read_s$"]
|
||||
set is_raddr_reg_net [find_cell_nets $inst "is_raddr_reg$"]
|
||||
|
||||
set raddr_s_nets [find_matching_nets $inst $raddr_w_nets "raddr_w(\\\[\\d+\\\])?$" "raddr_s\\1"]
|
||||
|
||||
set reg_next_pins {}
|
||||
set reg_ce_src_pin ""
|
||||
|
||||
foreach raddr_w_net $raddr_w_nets {
|
||||
if {$debug} {puts "DEBUG: Processing raddr_w net: '$raddr_w_net'"}
|
||||
|
||||
# Find raddr_w_net's driver pin
|
||||
set raddr_src_pin [find_net_driver $raddr_w_net]
|
||||
if {$debug} {puts "DEBUG: raddr_src_pin: '$raddr_src_pin'"}
|
||||
|
||||
# Get the driver cell
|
||||
set raddr_src_cell [get_cells -of_objects $raddr_src_pin]
|
||||
if {[llength $raddr_src_cell] == 0} {
|
||||
puts "ERROR: No source cell found connected to pin '$raddr_src_pin'."
|
||||
exit -1
|
||||
} elseif {[llength $raddr_src_cell] > 1} {
|
||||
puts "ERROR: Multiple source cells found connected to pin '$raddr_src_pin'."
|
||||
exit -1
|
||||
}
|
||||
|
||||
# Check driver type
|
||||
set driver_type [get_property REF_NAME $raddr_src_cell]
|
||||
if {$driver_type == "FDRE" || $driver_type == "FDSE"} {
|
||||
if {$debug} {puts "DEBUG: Net '$raddr_w_net' is registered, driver_type='$driver_type'"}
|
||||
} else {
|
||||
puts "WARNING: Net '$raddr_w_net' is not be registered, driver_type='$driver_type'"
|
||||
break
|
||||
}
|
||||
|
||||
# Create register next cell and return output pin
|
||||
set reg_next_pin [create_register_next $raddr_src_cell "$inst/raddr_next"]
|
||||
if {$reg_next_pin == ""} {
|
||||
puts "ERROR: failed to create register next value for '$raddr_src_cell'."
|
||||
exit -1
|
||||
}
|
||||
if {$debug} {puts "DEBUG: reg_next_pin: '$reg_next_pin'"}
|
||||
|
||||
lappend reg_next_pins $reg_next_pin
|
||||
|
||||
# Find the CE pin on raddr_src_cell
|
||||
if {$reg_ce_src_pin == ""} {
|
||||
set reg_ce_pin [get_pins -of_objects $raddr_src_cell -filter {NAME =~ "*/CE"}]
|
||||
if {[llength $reg_ce_pin] == 0} {
|
||||
puts "ERROR: No CE pin found on register cell '$raddr_src_cell'."
|
||||
exit -1
|
||||
} elseif {[llength $reg_ce_pin] > 1} {
|
||||
puts "ERROR: Multiple CE pins found on register cell '$raddr_src_cell'."
|
||||
exit -1
|
||||
}
|
||||
if {$debug} {puts "DEBUG: reg_ce_pin: '$reg_ce_pin'"}
|
||||
|
||||
set reg_ce_src_pin [find_pin_driver $reg_ce_pin]
|
||||
if {$reg_ce_src_pin == ""} {
|
||||
puts "ERROR: No source pin found connected to '$reg_ce_pin'."
|
||||
exit -1
|
||||
}
|
||||
if {$debug} {puts "DEBUG: reg_ce_src_pin: '$reg_ce_src_pin'"}
|
||||
}
|
||||
}
|
||||
|
||||
# do we have a fully registered read address?
|
||||
if {[llength $reg_next_pins] == [llength $raddr_w_nets]} {
|
||||
puts "INFO: Fully registered read address detected."
|
||||
set addr_width [llength $raddr_w_nets]
|
||||
for {set addr_idx 0} {$addr_idx < $addr_width} {incr addr_idx} {
|
||||
set raddr_w_net [lindex $raddr_w_nets $addr_idx]
|
||||
set raddr_s_net [lindex $raddr_s_nets $addr_idx]
|
||||
set reg_next_pin [lindex $reg_next_pins $addr_idx]
|
||||
puts "INFO: Connecting pin '$reg_next_pin' to '$raddr_s_net's pins."
|
||||
# Connect reg_next_pin to all input pins attached to raddr_s_net
|
||||
replace_net_source $raddr_s_net $reg_next_pin
|
||||
}
|
||||
|
||||
# Connect reg_ce_src_pin to all input pins attached to read_s_net
|
||||
puts "INFO: Connecting pin '$reg_ce_src_pin' to '$read_s_net's pins."
|
||||
replace_net_source $read_s_net $reg_ce_src_pin
|
||||
|
||||
# Create Const<1>'s pin
|
||||
set vcc_pin [getOrCreateVCCPin "$inst/VCC"]
|
||||
|
||||
# Connect vcc_pin to all input pins attached to is_raddr_reg_net
|
||||
puts "INFO: Connecting pin '$vcc_pin' to '$is_raddr_reg_net's pins."
|
||||
replace_net_source $is_raddr_reg_net $vcc_pin
|
||||
} else {
|
||||
puts "WARNING: Not all read addresses are registered!"
|
||||
|
||||
# Create Const<0>'s pin
|
||||
set gnd_pin [getOrCreateGNDPin "$inst/GND"]
|
||||
|
||||
# Connect gnd_pin to all input pins attached to is_raddr_reg_net
|
||||
puts "INFO: Connecting pin '$gnd_pin' to '$is_raddr_reg_net's pins."
|
||||
replace_net_source $is_raddr_reg_net $gnd_pin
|
||||
}
|
||||
|
||||
# Remove all placeholder cells
|
||||
foreach cell [find_nested_cells $inst "placeholder$"] {
|
||||
remove_cell $cell
|
||||
if {$debug} {puts "DEBUG: Cell '$cell' was removed successfully."}
|
||||
}
|
||||
}
|
||||
|
||||
proc resolve_async_brams {} {
|
||||
set bram_patch_cells {}
|
||||
foreach cell [get_cells -hierarchical -filter {REF_NAME =~ "*VX_async_ram_patch*"}] {
|
||||
puts "INFO: Found async BRAM patch cell: '$cell'."
|
||||
lappend bram_patch_cells $cell
|
||||
}
|
||||
if {[llength $bram_patch_cells] != 0} {
|
||||
foreach cell $bram_patch_cells {
|
||||
resolve_async_bram $cell
|
||||
}
|
||||
} else {
|
||||
puts "INFO: No async BRAM patch cells found in the design."
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# Invoke the procedure to resolve async BRAM
|
||||
vortex::resolve_async_brams
|
71
hw/scripts/xilinx_export_netlist.tcl
Normal file
71
hw/scripts/xilinx_export_netlist.tcl
Normal file
|
@ -0,0 +1,71 @@
|
|||
# Function to export netlist to a Graphviz DOT file
|
||||
proc export_netlist {dot_file_name} {
|
||||
# Open the DOT file for writing
|
||||
set dot_file [open $dot_file_name "w"]
|
||||
|
||||
# Start the DOT graph definition
|
||||
puts $dot_file "digraph Netlist {"
|
||||
puts $dot_file "rankdir=LR;" ;# Set the graph direction from left to right
|
||||
|
||||
# Extract and add cells to the graph
|
||||
foreach cell [get_cells -hierarchical] {
|
||||
set cell_name [get_property NAME $cell]
|
||||
set cell_type [get_property REF_NAME $cell]
|
||||
puts $dot_file "\"$cell_name\" \[label=\"$cell_name\\n($cell_type)\", shape=box\];"
|
||||
}
|
||||
|
||||
# Extract and add ports to the graph
|
||||
foreach port [get_ports] {
|
||||
set port_name [get_property NAME $port]
|
||||
set direction [get_property DIRECTION $port]
|
||||
set shape "ellipse"
|
||||
|
||||
# Color code input and output ports for easier identification
|
||||
if {$direction == "IN"} {
|
||||
set color "lightblue"
|
||||
} else {
|
||||
set color "lightgreen"
|
||||
}
|
||||
puts $dot_file "\"$port_name\" \[label=\"$port_name\", shape=$shape, style=filled, fillcolor=$color\];"
|
||||
}
|
||||
|
||||
# Traverse nets and create edges between ports and pins
|
||||
foreach net [get_nets -hierarchical] {
|
||||
set net_name [get_property NAME $net]
|
||||
|
||||
# Find source and destination pins
|
||||
set source_pin ""
|
||||
set sink_pins {}
|
||||
|
||||
foreach pin [get_pins -of_objects $net] {
|
||||
set direction [get_property DIRECTION $pin]
|
||||
set cell [get_cells -of_objects $pin]
|
||||
set pin_name [get_property NAME $pin]
|
||||
|
||||
if {$direction == "OUT"} {
|
||||
# Set as source pin
|
||||
set source_pin "$cell/$pin_name"
|
||||
} else {
|
||||
# Collect as sink pin
|
||||
lappend sink_pins "$cell/$pin_name"
|
||||
}
|
||||
}
|
||||
|
||||
# Output edges from source to all sinks
|
||||
if {$source_pin != ""} {
|
||||
foreach sink_pin $sink_pins {
|
||||
puts $dot_file "\"$source_pin\" -> \"$sink_pin\" \[label=\"$net_name\"\];"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# End the DOT graph definition
|
||||
puts $dot_file "}"
|
||||
|
||||
# Close the DOT file
|
||||
close $dot_file
|
||||
puts "Netlist exported to DOT file: $dot_file_name"
|
||||
}
|
||||
|
||||
# Run the export function
|
||||
export_netlist "netlist.dot"
|
|
@ -31,9 +31,9 @@ project_1/sources.txt:
|
|||
build: $(PROJECT).xpr
|
||||
$(PROJECT).xpr: project_1/sources.txt
|
||||
ifdef FPU_IP
|
||||
MAX_JOBS=$(JOBS) FPU_IP=project_1/ip $(VIVADO) -mode batch -source $(SRC_DIR)/project.tcl -tclargs $(TOP_LEVEL_ENTITY) $(DEVICE) project_1/sources.txt $(SRC_DIR)/project.xdc $(SCRIPT_DIR)
|
||||
MAX_JOBS=$(JOBS) FPU_IP=project_1/ip SCRIPT_DIR=$(SCRIPT_DIR) $(VIVADO) -mode batch -source $(SRC_DIR)/project.tcl -tclargs $(TOP_LEVEL_ENTITY) $(DEVICE) project_1/sources.txt $(SRC_DIR)/project.xdc
|
||||
else
|
||||
MAX_JOBS=$(JOBS) $(VIVADO) -mode batch -source $(SRC_DIR)/project.tcl -tclargs $(TOP_LEVEL_ENTITY) $(DEVICE) project_1/sources.txt $(SRC_DIR)/project.xdc $(SCRIPT_DIR)
|
||||
MAX_JOBS=$(JOBS) SCRIPT_DIR=$(SCRIPT_DIR) $(VIVADO) -mode batch -source $(SRC_DIR)/project.tcl -tclargs $(TOP_LEVEL_ENTITY) $(DEVICE) project_1/sources.txt $(SRC_DIR)/project.xdc
|
||||
endif
|
||||
|
||||
clean:
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
# Start time
|
||||
set start_time [clock seconds]
|
||||
|
||||
if { $::argc != 5 } {
|
||||
puts "ERROR: Program \"$::argv0\" requires 5 arguments!\n"
|
||||
puts "Usage: $::argv0 <top_module> <device_part> <vcs_file> <xdc_file> <tool_dir>\n"
|
||||
if { $::argc != 4 } {
|
||||
puts "ERROR: Program \"$::argv0\" requires 4 arguments!\n"
|
||||
puts "Usage: $::argv0 <top_module> <device_part> <vcs_file> <xdc_file>\n"
|
||||
exit
|
||||
}
|
||||
|
||||
|
@ -27,13 +27,16 @@ set top_module [lindex $::argv 0]
|
|||
set device_part [lindex $::argv 1]
|
||||
set vcs_file [lindex $::argv 2]
|
||||
set xdc_file [lindex $::argv 3]
|
||||
set tool_dir [lindex $::argv 4]
|
||||
|
||||
set script_dir $::env(SCRIPT_DIR)
|
||||
set source_dir [file dirname [info script]]
|
||||
|
||||
puts "Using top_module=$top_module"
|
||||
puts "Using device_part=$device_part"
|
||||
puts "Using vcs_file=$vcs_file"
|
||||
puts "Using xdc_file=$xdc_file"
|
||||
puts "Using tool_dir=$tool_dir"
|
||||
puts "Using script_dir=$script_dir"
|
||||
puts "Using source_dir=$source_dir"
|
||||
|
||||
# Set the number of jobs based on MAX_JOBS environment variable
|
||||
if {[info exists ::env(MAX_JOBS)]} {
|
||||
|
@ -48,10 +51,10 @@ if {[info exists ::env(FPU_IP)]} {
|
|||
set ip_dir $::env(FPU_IP)
|
||||
set argv [list $ip_dir $device_part]
|
||||
set argc 2
|
||||
source ${tool_dir}/xilinx_ip_gen.tcl
|
||||
source ${script_dir}/xilinx_ip_gen.tcl
|
||||
}
|
||||
|
||||
source "${tool_dir}/parse_vcs_list.tcl"
|
||||
source "${script_dir}/parse_vcs_list.tcl"
|
||||
set vlist [parse_vcs_list "${vcs_file}"]
|
||||
|
||||
set vsources_list [lindex $vlist 0]
|
||||
|
@ -84,37 +87,52 @@ if {[info exists ::env(FPU_IP)]} {
|
|||
|
||||
update_compile_order -fileset sources_1
|
||||
|
||||
# Synthesis
|
||||
set_property top $top_module [current_fileset]
|
||||
|
||||
set_property \
|
||||
-name {STEPS.SYNTH_DESIGN.ARGS.MORE OPTIONS} \
|
||||
-value {-mode out_of_context -flatten_hierarchy "rebuilt"} \
|
||||
-objects [get_runs synth_1]
|
||||
|
||||
# Synthesis
|
||||
# register compilation hooks
|
||||
#set_property STEPS.SYNTH_DESIGN.TCL.PRE ${source_dir}/pre_synth_hook.tcl [get_runs synth_1]
|
||||
#set_property STEPS.SYNTH_DESIGN.TCL.POST ${source_dir}/post_synth_hook.tcl [get_runs synth_1]
|
||||
set_property STEPS.OPT_DESIGN.TCL.PRE ${script_dir}/xilinx_async_bram_patch.tcl [get_runs impl_1]
|
||||
#set_property STEPS.OPT_DESIGN.TCL.POST ${source_dir}/post_opt_hook.tcl [get_runs impl_1]
|
||||
#set_property STEPS.ROUTE_DESIGN.TCL.PRE ${source_dir}/pre_route_hook.tcl [get_runs impl_1]
|
||||
#set_property STEPS.ROUTE_DESIGN.TCL.POST ${source_dir}/post_route_hook.tcl [get_runs impl_1]
|
||||
|
||||
if {$num_jobs != 0} {
|
||||
launch_runs synth_1 -jobs $num_jobs
|
||||
launch_runs synth_1 -verbose -jobs $num_jobs
|
||||
} else {
|
||||
launch_runs synth_1
|
||||
launch_runs synth_1 -verbose
|
||||
}
|
||||
wait_on_run synth_1
|
||||
open_run synth_1
|
||||
write_checkpoint -force post_synth.dcp
|
||||
report_utilization -file utilization.rpt -hierarchical -hierarchical_percentages
|
||||
report_utilization -file post_synth_util.rpt -hierarchical -hierarchical_percentages
|
||||
|
||||
# Implementation
|
||||
if {$num_jobs != 0} {
|
||||
launch_runs impl_1 -jobs $num_jobs
|
||||
launch_runs impl_1 -verbose -jobs $num_jobs
|
||||
} else {
|
||||
launch_runs impl_1
|
||||
launch_runs impl_1 -verbose
|
||||
}
|
||||
wait_on_run impl_1
|
||||
open_run impl_1
|
||||
write_checkpoint -force post_impl.dcp
|
||||
report_utilization -file post_impl_util.rpt -hierarchical -hierarchical_percentages
|
||||
|
||||
# Generate the synthesis report
|
||||
report_place_status -file place.rpt
|
||||
report_route_status -file route.rpt
|
||||
report_timing_summary -file timing.rpt
|
||||
|
||||
# Generate timing report
|
||||
report_timing -nworst 10 -delay_type max -sort_by group -file timing.rpt
|
||||
|
||||
# Generate power and drc reports
|
||||
report_power -file power.rpt
|
||||
report_drc -file drc.rpt
|
||||
|
||||
|
@ -125,4 +143,4 @@ set elapsed_time [expr {[clock seconds] - $start_time}]
|
|||
set hours [format "%02d" [expr {$elapsed_time / 3600}]]
|
||||
set minutes [format "%02d" [expr {($elapsed_time % 3600) / 60}]]
|
||||
set seconds [format "%02d" [expr {$elapsed_time % 60}]]
|
||||
puts "Total elapsed time: ${hours}h ${minutes}m ${seconds}s"
|
||||
puts "Total elapsed time: ${hours}h ${minutes}m ${seconds}s"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
PROJECT = Unittest
|
||||
PROJECT = VX_fifo_queue
|
||||
TOP_LEVEL_ENTITY = $(PROJECT)
|
||||
SRC_FILE = $(PROJECT).sv
|
||||
|
||||
|
|
|
@ -121,8 +121,8 @@ proc run_setup {} {
|
|||
# None
|
||||
|
||||
# Set 'sim_1' fileset file properties for local files
|
||||
set file "testbench.v"
|
||||
set file_obj [get_files -of_objects [get_filesets sim_1] [list "*$file"]]
|
||||
set file "testbench.v"
|
||||
set file_obj [get_files -of_objects [get_filesets sim_1] [list "*$file"]]
|
||||
set_property -name "file_type" -value "Verilog" -objects $file_obj
|
||||
set_property -name "is_enabled" -value "1" -objects $file_obj
|
||||
set_property -name "is_global_include" -value "0" -objects $file_obj
|
||||
|
@ -300,7 +300,7 @@ set file_obj [get_files -of_objects [get_filesets sim_1] [list "*$file"]]
|
|||
CONFIG.Assume_Synchronous_Clk {true} \
|
||||
CONFIG.Byte_Size {8} \
|
||||
CONFIG.Load_Init_File {true} \
|
||||
CONFIG.Coe_File {@CURRENTDIR@/hw/syn/xilinx/sandbox/kernel.bin.coe} \
|
||||
CONFIG.Coe_File {@BUILDDIR@/hw/syn/xilinx/sandbox/kernel.bin.coe} \
|
||||
CONFIG.EN_SAFETY_CKT {true} \
|
||||
CONFIG.Enable_32bit_Address {true} \
|
||||
CONFIG.Fill_Remaining_Memory_Locations {false} \
|
||||
|
|
|
@ -88,6 +88,9 @@ RTL_INCLUDE += $(FPU_INCLUDE)
|
|||
VPP_FLAGS += --link --target $(TARGET) --platform $(PLATFORM) --save-temps --no_ip_cache
|
||||
VPP_FLAGS += --vivado.synth.jobs $(JOBS) --vivado.impl.jobs $(JOBS)
|
||||
|
||||
# register compilation hooks
|
||||
VPP_FLAGS += --xp "vivado_prop:run.impl_1.STEPS.OPT_DESIGN.TCL.PRE={$(SCRIPT_DIR)/xilinx_async_bram_patch.tcl}"
|
||||
|
||||
# load platform settings
|
||||
include $(SRC_DIR)/platforms.mk
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue