Merge remote-tracking branch 'lnis_origin/dev' into ganesh_dev

This commit is contained in:
Ganesh Gore 2019-11-15 14:54:13 -07:00
commit 1c4acff79b
127 changed files with 8961 additions and 1927 deletions

View File

@ -1,87 +1,116 @@
language: cpp
# cache results
cache:
directories:
- "$TRAVIS_BUILD_DIR/abc"
- "$TRAVIS_BUILD_DIR/yosys"
- "$TRAVIS_BUILD_DIR/ace2"
- "$TRAVIS_BUILD_DIR/libs"
- "$HOME/.ccache"
- "$HOME/deps"
- $TRAVIS_BUILD_DIR/abc
- $TRAVIS_BUILD_DIR/yosys
- $TRAVIS_BUILD_DIR/ace2
- $TRAVIS_BUILD_DIR/libs
- $HOME/.ccache
# - $HOME/deps
# Currently sudo is not required, NO ENV is used
# Supported Operating systems
#os:
# - linux
# - osx
# Create a matrix to branch the building environment
matrix:
include:
- os: linux
sudo: false
dist: bionic
compiler: g++-8
addons:
apt:
sources:
- sourceline: ppa:ubuntu-toolchain-r/test
packages:
- autoconf
- automake
- bash
- bison
- build-essential
- cmake
- ctags
- curl
- doxygen
- flex
- fontconfig
- g++-8
- gcc-8
- gdb
- git
- gperf
- iverilog
- libcairo2-dev
- libevent-dev
- libfontconfig1-dev
- liblist-moreutils-perl
- libncurses5-dev
- libx11-dev
- libxft-dev
- libxml++2.6-dev
- perl
- python
- texinfo
- time
- valgrind
- zip
- qt5-default
- os: linux
# Compiler is specified in ./travis/common.sh
sudo: false
dist: bionic
compiler: g++-8
addons:
apt:
sources:
- ubuntu-toolchain-r-test # For newer GCC
- george-edison55-precise-backports # For cmake
packages:
- autoconf
- automake
- bash
- bison
- build-essential
- cmake
- ctags
- curl
- doxygen
- flex
- fontconfig
- g++-8
- gcc-8
- gdb
- git
- gperf
- iverilog
- libcairo2-dev
- libevent-dev
- libfontconfig1-dev
- liblist-moreutils-perl
- libncurses5-dev
- libx11-dev
- libxft-dev
- libxml++2.6-dev
- perl
- python
- texinfo
- time
- valgrind
- zip
- qt5-default
# - os: osx
# osx_image: xcode10.2 # we target latest MacOS Mojave
# sudo: true
# compiler: gcc-4.9 # Use clang instead of gcc in MacOS
# addons:
# homebrew:
# packages:
# - bison
# - cmake
# - ctags
# - flex
# - fontconfig
# - git
# - gcc@6
# - gcc@4.9
# - gawk
# - icarus-verilog
# - libxml++
# - qt5
before_install:
- openssl aes-256-cbc -K $encrypted_6f6cf68308be_key -iv $encrypted_6f6cf68308be_iv -in deploy_key.enc -out ./deploy_key -d
- eval "$(ssh-agent -s)"
- chmod 600 ./deploy_key
- cp $TRAVIS_BUILD_DIR/deploy_key ~/.ssh/id_rsa
- echo -e "Host *\n StrictHostKeyChecking no\n" >> ~/.ssh/config
- ssh u1249762@lab1-1.eng.utah.edu pwd
- ssh u1249762@lab1-1.eng.utah.edu "mkdir /var/tmp/travis_bc/$TRAVIS_JOB_ID"
- echo $TRAVIS_JOB_ID >> build_id.txt
- scp build_id.txt u1249762@lab1-1.eng.utah.edu:/var/tmp/travis_bc/$TRAVIS_JOB_ID/
- source .travis/common.sh
- source .travis/common.sh
install:
- DEPS_DIR="${HOME}/deps"
- mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR}
- |
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
CMAKE_URL="https://cmake.org/files/v3.12/cmake-3.12.4-Linux-x86_64.tar.gz"
mkdir -p cmake && travis_retry wget --no-clobber --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
export PATH=${DEPS_DIR}/cmake/bin:${PATH}
echo ${PATH}
else
brew install cmake || brew upgrade cmake
fi
- cmake --version
- cd -
- source .travis/install.sh
- DEPS_DIR="${HOME}/deps"
- mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR}
- |
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
CMAKE_URL="https://cmake.org/files/v3.12/cmake-3.12.4-Linux-x86_64.tar.gz"
mkdir -p cmake && travis_retry wget --no-clobber --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
export PATH=${DEPS_DIR}/cmake/bin:${PATH}
echo ${PATH}
else
brew install cmake || brew upgrade cmake
fi
- cmake --version
- cd -
- source .travis/install.sh
script:
- ".travis/script.sh"
- .travis/script.sh
#- .travis/regression.sh
after_failure:
- ".travis/after_failure.sh"
- .travis/after_failure.sh
after_success:
- ".travis/after_success.sh"
- .travis/after_success.sh
notifications:
slack:
secure: L8tzicFh+EKcK21GBA2m3rQ3jmnDdqiRXIZcb0iqYlhT0V5asYvCqwlpPDUDV1wmBXqPgRJBI/jitAJlKFWu74pLTVc6FscUIDYM7S0DJfHEcufLknZx88lMmmV0IsYLQe3/s89tWoudMf1bNBo/8YWzLDffqUQ7s/rTPD9SWLppb01X0Xm158oDlA0rWETs35nuNFgJxWcSyIyIvnRNE3dHjzmBETUR9mYDsUSYlcOI44FMD8rE6emicdkqdn1zVxScobrl4Dt2bPsMfKopgIKK1x+38AuaqQa7t5F5ICnF0WfxmQ6/TcRNwIij0fDu68w/fcU8SyV+Ex5aZBKYUU7PG7ELTOq+q1geDoTlbguvFSIT4EzqErc4hbJmcUn79BKLhdjshZtGihKatntJx2faXYNYGFjwmnPFRYpqsozydztgMjzv4prZ5yoh7jhoDiGj44QcpXlQ9otM17JdfqveowMLHBYzATsxIRG93irZfXG/E3S8FvXg8mYOIEn8UK7H6i8VWL3JHlw8RbpLdNLswZOUlpEaDAeTm5tvYcw7FGH2nlZ2e5aXLxN6dTovSSRztQHbWdJTGG0N+xldBXcCiChmok4nXGReIkMc+99nZjRsiCB0R16tCNb25/p7NAVkItfVe1qRTzdnhi1hdE7LPURK4kxoFRJ6sFVuYjw=

View File

@ -19,24 +19,19 @@ end_section "OpenFPGA.build"
start_section "OpenFPGA.TaskTun" "${GREEN}..Running_Regression..${NC}"
cd -
echo -e "Testing single-mode architectures";
python3 openfpga_flow/scripts/run_fpga_task.py single_mode
python3 openfpga_flow/scripts/run_fpga_task.py single_mode --remove_run_dir all
#python3 openfpga_flow/scripts/run_fpga_task.py s298
python3 openfpga_flow/scripts/run_fpga_task.py single_mode --debug --show_thread_logs
#python3 openfpga_flow/scripts/run_fpga_task.py s298
echo -e "Testing multi-mode architectures";
python3 openfpga_flow/scripts/run_fpga_task.py blif_vpr_flow --maxthreads 2
python3 openfpga_flow/scripts/run_fpga_task.py blif_vpr_flow --remove_run_dir all
python3 openfpga_flow/scripts/run_fpga_task.py multi_mode --maxthreads 4 --debug --show_thread_logs
echo -e "Testing compact routing techniques";
python3 openfpga_flow/scripts/run_fpga_task.py compact_routing
python3 openfpga_flow/scripts/run_fpga_task.py compact_routing --remove_run_dir all
python3 openfpga_flow/scripts/run_fpga_task.py compact_routing --debug --show_thread_logs
echo -e "Testing tileable architectures";
python3 openfpga_flow/scripts/run_fpga_task.py tileable_routing
python3 openfpga_flow/scripts/run_fpga_task.py tileable_routing --remove_run_dir all
python3 openfpga_flow/scripts/run_fpga_task.py tileable_routing --debug --show_thread_logs
echo -e "Testing Verilog generation with explicit port mapping ";
python3 openfpga_flow/scripts/run_fpga_task.py explicit_verilog
python3 openfpga_flow/scripts/run_fpga_task.py explicit_verilog --remove_run_dir all
python3 openfpga_flow/scripts/run_fpga_task.py explicit_verilog --debug --show_thread_logs
end_section "OpenFPGA.TaskTun"

View File

@ -182,6 +182,13 @@ set_target_properties(libace ace
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/ace2"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/ace2")
# Set output locations to be in the main source tree under the relevant folder
set_target_properties(libini
PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libs/external/libini"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libs/external/libini"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libs/external/libini")
# Set output locations to be in the main source tree under the relevant folder
set_target_properties(libvtrutil
PROPERTIES

View File

@ -7,6 +7,7 @@ files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS)
#Create the library
add_library(libini STATIC
${LIB_HEADERS})
${LIB_HEADERS})
target_include_directories(libini PUBLIC ${LIB_INCLUDE_DIRS})
set_target_properties(libini PROPERTIES PREFIX "" LINKER_LANGUAGE CXX)
set_target_properties(libini PROPERTIES PREFIX "" LINKER_LANGUAGE CXX)

View File

@ -0,0 +1,56 @@
//-----------------------------------------------------
// Design Name : dual_port_ram_32x512
// File Name : dpram.v
// Function : Dual port RAM 32x512
// Coder : Aurelien Alacchi
//-----------------------------------------------------
module dual_port_ram_32x512 (
input clk,
input wen,
input ren,
input[0:8] waddr,
input[0:8] raddr,
input[0:31] d_in,
output[0:31] d_out );
dual_port_sram_32x512 memory_0 (
.wclk (clk),
.wen (wen),
.waddr (waddr),
.data_in (d_in),
.rclk (clk),
.ren (ren),
.raddr (raddr),
.d_out (d_out) );
endmodule
module dual_port_sram_32x512 (
input wclk,
input wen,
input[0:8] waddr,
input[0:31] data_in,
input rclk,
input ren,
input[0:8] raddr,
output[0:31] d_out );
reg[0:31] ram[0:511];
reg[0:31] internal;
assign d_out = internal;
always @(posedge wclk) begin
if(wen) begin
ram[waddr] <= data_in;
end
end
always @(posedge rclk) begin
if(ren) begin
internal <= ram[raddr];
end
end
endmodule

View File

@ -76,9 +76,9 @@ endmodule //End Of Module static_dff
//-----------------------------------------------------
module sc_dff_compact (
/* Global ports go first */
input pReset, // Reset input
input reset, // Reset input
//input set, // set input
input prog_clk, // Clock Input
input clk, // Clock Input
/* Local ports follow */
input D, // Data Input
output Q, // Q output
@ -88,8 +88,8 @@ output Qb // Q output
reg q_reg;
//-------------Code Starts Here---------
always @ ( posedge prog_clk or posedge pReset /*or posedge set*/)
if (pReset) begin
always @ ( posedge clk or posedge reset /*or posedge set*/)
if (reset) begin
q_reg <= 1'b0;
//end else if (set) begin
// q_reg <= 1'b1;

View File

@ -0,0 +1,53 @@
//-----------------------------------------------------
// Design Name : MUX2
// File Name : mux2.v
// Function : Standard cell (static gate) implementation
// of 2-input multiplexers
// Coder : Xifan Tang
//-----------------------------------------------------
module MUX2(
input A, // Data input 0
input B, // Data input 1
input S0, // Select port
output Y // Data output
);
assign Y = S0 ? B : A;
// Note:
// MUX2 appears will appear in LUTs, routing multiplexers,
// being a component in combinational loops
// To help convergence in simulation
// i.e., to avoid the X (undetermined) signals,
// the following timing constraints and signal initialization
// has to be added!
`ifdef ENABLE_TIMING
// ------ BEGIN Pin-to-pin Timing constraints -----
specify
(A => Y) = (0.001, 0.001);
(B => Y) = (0.001, 0.001);
(S0 => Y) = (0.001, 0.001);
endspecify
// ------ END Pin-to-pin Timing constraints -----
`endif
`ifdef ENABLE_SIGNAL_INITIALIZATION
// ------ BEGIN driver initialization -----
initial begin
`ifdef ENABLE_FORMAL_VERIFICATION
$deposit(A, 1'b0);
$deposit(B, 1'b0);
$deposit(S0, 1'b0);
`else
$deposit(A, $random);
$deposit(B, $random);
$deposit(S0, $random);
`endif
end
// ------ END driver initialization -----
`endif
endmodule

View File

@ -321,12 +321,12 @@
<input_buffer exist="on" circuit_model_name="INV1X"/>
<output_buffer exist="on" circuit_model_name="INV1X"/>
<pass_gate_logic circuit_model_name="TGATEX1"/>
<port type="input" prefix="pReset" lib_name="pReset" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<port type="input" prefix="pReset" lib_name="reset" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<!-- <port type="input" prefix="pSet" size="1" is_global="true" default_val="0" is_set="true" is_prog="true"/> -->
<port type="input" prefix="D" lib_name="D" size="1"/>
<port type="output" prefix="Q" lib_name="Q" size="1"/>
<port type="output" prefix="Qb" lib_name="Qb" size="1"/>
<port type="clock" prefix="prog_clk" lib_name="prog_clk" size="1" is_global="true" default_val="0" is_prog="true"/>
<port type="clock" prefix="prog_clk" lib_name="clk" size="1" is_global="true" default_val="0" is_prog="true"/>
</circuit_model>
<circuit_model type="iopad" name="iopad" prefix="iopad" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/io.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/io.v">
<design_technology type="cmos"/>

View File

@ -379,12 +379,12 @@
<input_buffer exist="on" circuit_model_name="INV1X"/>
<output_buffer exist="on" circuit_model_name="INV1X"/>
<pass_gate_logic circuit_model_name="TGATEX1"/>
<port type="input" prefix="pReset" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<port type="input" prefix="pReset" lib_name="reset" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<!-- <port type="input" prefix="pSet" size="1" is_global="true" default_val="0" is_set="true" is_prog="true"/> -->
<port type="input" prefix="D" size="1"/>
<port type="output" prefix="Q" size="1"/>
<port type="output" prefix="Qb" size="1"/>
<port type="clock" prefix="prog_clk" size="1" is_global="true" default_val="0" is_prog="true"/>
<port type="clock" prefix="prog_clk" lib_name="clk" size="1" is_global="true" default_val="0" is_prog="true"/>
</circuit_model>
<circuit_model type="iopad" name="iopad" prefix="iopad" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/io.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/io.v">
<design_technology type="cmos"/>

View File

@ -146,7 +146,7 @@
<port name="Q"/>
</output_ports>
</model>
<model name="dpram">
<model name="dual_port_ram_32x512">
<input_ports>
<port name="wen"/> <!-- control -->
<port name="ren"/> <!-- control -->
@ -163,8 +163,8 @@
<!-- ODIN II specific config ends -->
<!-- Physical descriptions begin -->
<layout auto="1.0" tileable_routing="off"/>
<!--layout width="12" height="12" tileable_routing="off"/-->
<layout auto="1.0" tileable_routing="on"/>
<!--layout width="5" height="2" tileable_routing="on"/-->
<spice_settings>
<parameters>
<options sim_temp="25" post="off" captab="off" fast="on"/>
@ -344,14 +344,14 @@
<port type="output" prefix="out" size="1"/>
</circuit_model>
<!--DFF subckt ports should be defined as <D> <Q> <CLK> <RESET> <SET> -->
<circuit_model type="ff" name="static_dff" prefix="dff" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/ff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerlogNetlists/ff.v">
<circuit_model type="ff" name="static_dff" prefix="dff" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/ff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/ff.v">
<design_technology type="cmos"/>
<input_buffer exist="on" circuit_model_name="INV1X"/>
<output_buffer exist="on" circuit_model_name="INV1X"/>
<pass_gate_logic circuit_model_name="TGATEX1"/>
<port type="input" prefix="D" size="1"/>
<port type="input" prefix="Set" size="1" is_global="true" default_val="0" is_set="true"/>
<port type="input" prefix="Reset" size="1" is_global="true" default_val="0" is_reset="true"/>
<port type="input" prefix="set" size="1" is_global="true" default_val="0" is_set="true"/>
<port type="input" prefix="reset" size="1" is_global="true" default_val="0" is_reset="true"/>
<port type="output" prefix="Q" size="1"/>
<port type="clock" prefix="clk" size="1" is_global="true" default_val="0" />
</circuit_model>
@ -386,17 +386,17 @@
<port type="sram" prefix="mode" size="2" mode_select="true" circuit_model_name="sc_dff_compact" default_val="1"/>
</circuit_model>
<!--Scan-chain DFF subckt ports should be defined as <D> <Q> <Qb> <CLK> <RESET> <SET> -->
<circuit_model type="sff" name="sc_dff_compact" prefix="scff" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/ff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerlogNetlists/ff.v">
<circuit_model type="sff" name="sc_dff_compact" prefix="scff" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/ff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/ff.v">
<design_technology type="cmos"/>
<input_buffer exist="on" circuit_model_name="INV1X"/>
<output_buffer exist="on" circuit_model_name="INV1X"/>
<pass_gate_logic circuit_model_name="TGATEX1"/>
<port type="input" prefix="pReset" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<port type="input" prefix="pReset" lib_name="reset" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<!-- <port type="input" prefix="pSet" size="1" is_global="true" default_val="0" is_set="true" is_prog="true"/> -->
<port type="input" prefix="D" size="1"/>
<port type="output" prefix="Q" size="1"/>
<port type="output" prefix="Qb" size="1"/>
<port type="clock" prefix="prog_clk" size="1" is_global="true" default_val="0" is_prog="true"/>
<port type="clock" prefix="prog_clk" lib_name="clk" size="1" is_global="true" default_val="0" is_prog="true"/>
</circuit_model>
<circuit_model type="iopad" name="iopad" prefix="iopad" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/io.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/io.v">
<design_technology type="cmos"/>
@ -421,16 +421,16 @@
<port type="output" prefix="sumout" size="1"/>
<port type="output" prefix="cout" size="1"/>
</circuit_model>
<circuit_model type="hard_logic" name="dpram" prefix="dpram" dump_explicit_port_map="true" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/spram.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/memory_wrapper.v">
<circuit_model type="hard_logic" name="dual_port_ram_32x512" prefix="dual_port_ram_32x512" dump_explicit_port_map="true" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/spram.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/dpram.v">
<design_technology type="cmos"/>
<input_buffer exist="on" circuit_model_name="buf1"/>
<output_buffer exist="on" circuit_model_name="buf1"/>
<port type="input" prefix="waddr" size="11"/>
<port type="input" prefix="raddr" size="11"/>
<port type="input" prefix="d_in" size="64"/>
<port type="input" prefix="waddr" size="9"/>
<port type="input" prefix="raddr" size="9"/>
<port type="input" prefix="d_in" size="32"/>
<port type="input" prefix="wen" size="1"/>
<port type="input" prefix="ren" size="1"/>
<port type="output" prefix="d_out" size="64"/>
<port type="output" prefix="d_out" size="32"/>
<port type="clock" prefix="clk" size="1" is_global="true" default_val="0"/>
</circuit_model>
<circuit_model type="sram" name="sram6T" prefix="sram" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/sram.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/sram.v">
@ -613,31 +613,31 @@
<!-- SPRAM instanciation -->
<pb_type name="memory_dp" height="6" area="548000">
<pb_type name="memory_dp" height="2" area="548000">
<input name="waddr" num_pins="11" equivalent="false"/>
<input name="raddr" num_pins="11" equivalent="false"/>
<input name="d_in" num_pins="64" equivalent="false"/>
<input name="waddr" num_pins="9" equivalent="false"/>
<input name="raddr" num_pins="9" equivalent="false"/>
<input name="d_in" num_pins="32" equivalent="false"/>
<input name="wen" num_pins="1"/>
<input name="ren" num_pins="1"/>
<output name="d_out" num_pins="64" equivalent="false"/>
<output name="d_out" num_pins="32" equivalent="false"/>
<clock name="clk" num_pins="1"/>
<pb_type name="memory" num_pb="1">
<input name="waddr" num_pins="11"/>
<input name="raddr" num_pins="11"/>
<input name="d_in" num_pins="64"/>
<input name="waddr" num_pins="9"/>
<input name="raddr" num_pins="9"/>
<input name="d_in" num_pins="32"/>
<input name="wen" num_pins="1"/>
<input name="ren" num_pins="1"/>
<output name="d_out" num_pins="64"/>
<output name="d_out" num_pins="32"/>
<clock name="clk" num_pins="1"/>
<pb_type name="dpram" num_pb="1" blif_model=".subckt dpram" circuit_model_name="dpram">
<input name="waddr" num_pins="11" port_class="address"/>
<input name="raddr" num_pins="11" port_class="address"/>
<input name="d_in" num_pins="64" port_class="data_in"/>
<pb_type name="dpram" num_pb="1" blif_model=".subckt dual_port_ram_32x512" circuit_model_name="dual_port_ram_32x512">
<input name="waddr" num_pins="9" port_class="address"/>
<input name="raddr" num_pins="9" port_class="address"/>
<input name="d_in" num_pins="32" port_class="data_in"/>
<input name="wen" num_pins="1" port_class="write_en"/>
<input name="ren" num_pins="1" port_class="write_en"/>
<output name="d_out" num_pins="64" port_class="data_out"/>
<input name="ren" num_pins="1" port_class="read_en"/>
<output name="d_out" num_pins="32" port_class="data_out"/>
<clock name="clk" num_pins="1" port_class="clock"/>
</pb_type>
<interconnect>
@ -647,8 +647,8 @@
<direct name="address2" input="memory.raddr" output="dpram.raddr">
<delay_constant max="132e-12" in_port="memory.raddr" out_port="dpram.raddr"/>
</direct>
<direct name="data1" input="memory.d_in[63:0]" output="dpram.d_in">
<delay_constant max="132e-12" in_port="memory.d_in[63:0]" out_port="dpram.d_in"/>
<direct name="data1" input="memory.d_in[31:0]" output="dpram.d_in">
<delay_constant max="132e-12" in_port="memory.d_in[31:0]" out_port="dpram.d_in"/>
</direct>
<direct name="writeen1" input="memory.wen" output="dpram.wen">
<delay_constant max="132e-12" in_port="memory.wen" out_port="dpram.wen"/>
@ -656,8 +656,8 @@
<direct name="readen1" input="memory.ren" output="dpram.ren">
<delay_constant max="132e-12" in_port="memory.ren" out_port="dpram.ren"/>
</direct>
<direct name="dataout1" input="dpram.d_out" output="memory.d_out[63:0]">
<delay_constant max="40e-12" in_port="dpram.d_out" out_port="memory.d_out[63:0]"/>
<direct name="dataout1" input="dpram.d_out" output="memory.d_out[31:0]">
<delay_constant max="40e-12" in_port="dpram.d_out" out_port="memory.d_out[31:0]"/>
</direct>
<direct name="clk" input="memory.clk" output="dpram.clk">
</direct>
@ -674,13 +674,13 @@
<direct name="clk" input="memory_dp.clk" output="memory.clk"/>
</interconnect>
<fc default_in_type="frac" default_in_val="0.15" default_out_type="frac" default_out_val="0.10"/>
<pinlocations pattern="spread"/>
<!--pinlocations pattern="custom">
<!--pinlocations pattern="spread"/-->
<pinlocations pattern="custom">
<loc side="left">memory_dp.d_in</loc>
<loc side="top" offset="5">memory_dp.clk memory_dp.wen memory_dp.waddr</loc>
<loc side="top" offset="1">memory_dp.clk memory_dp.wen memory_dp.waddr</loc>
<loc side="right">memory_dp.d_out</loc>
<loc side="bottom">memory_dp.ren memory_dp.raddr</loc>
</pinlocations-->
</pinlocations>
<!-- Place this memory block every 8 columns from (and including) the second column -->
<gridlocations>

View File

@ -379,12 +379,12 @@
<input_buffer exist="on" circuit_model_name="INV1X"/>
<output_buffer exist="on" circuit_model_name="INV1X"/>
<pass_gate_logic circuit_model_name="TGATEX1"/>
<port type="input" prefix="pReset" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<port type="input" prefix="pReset" lib_name="reset" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<!-- <port type="input" prefix="pSet" size="1" is_global="true" default_val="0" is_set="true" is_prog="true"/> -->
<port type="input" prefix="D" size="1"/>
<port type="output" prefix="Q" size="1"/>
<port type="output" prefix="Qb" size="1"/>
<port type="clock" prefix="prog_clk" size="1" is_global="true" default_val="0" is_prog="true"/>
<port type="clock" prefix="prog_clk" lib_name="clk" size="1" is_global="true" default_val="0" is_prog="true"/>
</circuit_model>
<circuit_model type="iopad" name="iopad" prefix="iopad" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/io.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/io.v">
<design_technology type="cmos"/>

View File

@ -379,12 +379,12 @@
<input_buffer exist="on" circuit_model_name="INV1X"/>
<output_buffer exist="on" circuit_model_name="INV1X"/>
<pass_gate_logic circuit_model_name="TGATEX1"/>
<port type="input" prefix="pReset" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<port type="input" prefix="pReset" lib_name="reset" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<!-- <port type="input" prefix="pSet" size="1" is_global="true" default_val="0" is_set="true" is_prog="true"/> -->
<port type="input" prefix="D" size="1"/>
<port type="output" prefix="Q" size="1"/>
<port type="output" prefix="Qb" size="1"/>
<port type="clock" prefix="prog_clk" size="1" is_global="true" default_val="0" is_prog="true"/>
<port type="clock" prefix="prog_clk" lib_name="clk" size="1" is_global="true" default_val="0" is_prog="true"/>
</circuit_model>
<circuit_model type="iopad" name="iopad" prefix="iopad" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/io.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/io.v">
<design_technology type="cmos"/>

View File

@ -377,12 +377,12 @@
<input_buffer exist="on" circuit_model_name="INV1X"/>
<output_buffer exist="on" circuit_model_name="INV1X"/>
<pass_gate_logic circuit_model_name="TGATEX1"/>
<port type="input" prefix="pReset" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<port type="input" prefix="pReset" lib_name="reset" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<!-- <port type="input" prefix="pSet" size="1" is_global="true" default_val="0" is_set="true" is_prog="true"/> -->
<port type="input" prefix="D" size="1"/>
<port type="output" prefix="Q" size="1"/>
<port type="output" prefix="Qb" size="1"/>
<port type="clock" prefix="prog_clk" size="1" is_global="true" default_val="0" is_prog="true"/>
<port type="clock" prefix="prog_clk" lib_name="clk" size="1" is_global="true" default_val="0" is_prog="true"/>
</circuit_model>
<circuit_model type="iopad" name="iopad" prefix="iopad" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/io.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/io.v">
<design_technology type="cmos"/>

File diff suppressed because it is too large Load Diff

View File

@ -379,12 +379,12 @@
<input_buffer exist="on" circuit_model_name="INV1X"/>
<output_buffer exist="on" circuit_model_name="INV1X"/>
<pass_gate_logic circuit_model_name="TGATEX1"/>
<port type="input" prefix="pReset" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<port type="input" prefix="pReset" lib_name="reset" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<!-- <port type="input" prefix="pSet" size="1" is_global="true" default_val="0" is_set="true" is_prog="true"/> -->
<port type="input" prefix="D" size="1"/>
<port type="output" prefix="Q" size="1"/>
<port type="output" prefix="Qb" size="1"/>
<port type="clock" prefix="prog_clk" size="1" is_global="true" default_val="0" is_prog="true"/>
<port type="clock" prefix="prog_clk" lib_name="clk" size="1" is_global="true" default_val="0" is_prog="true"/>
</circuit_model>
<circuit_model type="iopad" name="iopad" prefix="iopad" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/io.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/io.v">
<design_technology type="cmos"/>

View File

@ -379,12 +379,12 @@
<input_buffer exist="on" circuit_model_name="INV1X"/>
<output_buffer exist="on" circuit_model_name="INV1X"/>
<pass_gate_logic circuit_model_name="TGATEX1"/>
<port type="input" prefix="pReset" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<port type="input" prefix="pReset" lib_name="reset" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<!-- <port type="input" prefix="pSet" size="1" is_global="true" default_val="0" is_set="true" is_prog="true"/> -->
<port type="input" prefix="D" size="1"/>
<port type="output" prefix="Q" size="1"/>
<port type="output" prefix="Qb" size="1"/>
<port type="clock" prefix="prog_clk" size="1" is_global="true" default_val="0" is_prog="true"/>
<port type="clock" prefix="prog_clk" lib_name="clk" size="1" is_global="true" default_val="0" is_prog="true"/>
</circuit_model>
<circuit_model type="iopad" name="iopad" prefix="iopad" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/io.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/io.v">
<design_technology type="cmos"/>

View File

@ -379,12 +379,12 @@
<input_buffer exist="on" circuit_model_name="INV1X"/>
<output_buffer exist="on" circuit_model_name="INV1X"/>
<pass_gate_logic circuit_model_name="TGATEX1"/>
<port type="input" prefix="pReset" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<port type="input" prefix="pReset" lib_name="reset" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<!-- <port type="input" prefix="pSet" size="1" is_global="true" default_val="0" is_set="true" is_prog="true"/> -->
<port type="input" prefix="D" size="1"/>
<port type="output" prefix="Q" size="1"/>
<port type="output" prefix="Qb" size="1"/>
<port type="clock" prefix="prog_clk" size="1" is_global="true" default_val="0" is_prog="true"/>
<port type="clock" prefix="prog_clk" lib_name="clk" size="1" is_global="true" default_val="0" is_prog="true"/>
</circuit_model>
<circuit_model type="iopad" name="iopad" prefix="iopad" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/io.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/io.v">
<design_technology type="cmos"/>

View File

@ -13,7 +13,6 @@ i_11_ 0.495600 0.504600
i_12_ 0.502800 0.507600
i_13_ 0.494600 0.500600
i_14_ 0.504800 0.502800
i_15_ 0.487600 0.495200
i_16_ 0.504000 0.505200
i_17_ 0.497400 0.512600
i_18_ 0.502200 0.502200

View File

@ -1,7 +1,7 @@
# Benchmark "apex2" written by ABC on Tue Mar 12 09:34:21 2019
.model apex2
.inputs i_0_ i_1_ i_2_ i_3_ i_4_ i_5_ i_6_ i_7_ i_8_ i_9_ i_10_ i_11_ i_12_ \
i_13_ i_14_ i_15_ i_16_ i_17_ i_18_ i_19_ i_20_ i_21_ i_22_ i_23_ i_24_ \
i_13_ i_14_ i_16_ i_17_ i_18_ i_19_ i_20_ i_21_ i_22_ i_23_ i_24_ \
i_25_ i_26_ i_27_ i_28_ i_29_ i_30_ i_31_ i_32_ i_33_ i_34_ i_35_ i_36_ \
i_37_ i_38_
.outputs o_0_ o_1_ o_2_

View File

@ -1,13 +1,12 @@
/* Generated by Yosys 0.8+133 (git sha1 2a2e0a4, gcc 7.3.0 -fPIC -Os) */
module apex2(i_0_, i_1_, i_2_, i_3_, i_4_, i_5_, i_6_, i_7_, i_8_, i_9_, i_10_, i_11_, i_12_, i_13_, i_14_, i_15_, i_16_, i_17_, i_18_, i_19_, i_20_, i_21_, i_22_, i_23_, i_24_, i_25_, i_26_, i_27_, i_28_, i_29_, i_30_, i_31_, i_32_, i_33_, i_34_, i_35_, i_36_, i_37_, i_38_, o_0_, o_1_, o_2_);
module apex2(i_0_, i_1_, i_2_, i_3_, i_4_, i_5_, i_6_, i_7_, i_8_, i_9_, i_10_, i_11_, i_12_, i_13_, i_14_, i_16_, i_17_, i_18_, i_19_, i_20_, i_21_, i_22_, i_23_, i_24_, i_25_, i_26_, i_27_, i_28_, i_29_, i_30_, i_31_, i_32_, i_33_, i_34_, i_35_, i_36_, i_37_, i_38_, o_0_, o_1_, o_2_);
input i_0_;
input i_10_;
input i_11_;
input i_12_;
input i_13_;
input i_14_;
input i_15_;
input i_16_;
input i_17_;
input i_18_;

View File

@ -0,0 +1,95 @@
clk 0.5 0.2
wen 0.5 0.2
wen_st0 0.5 0.2
wen_st1 0.5 0.2
ren 0.5 0.2
raddr_0_ 0.5 0.2
raddr_1_ 0.5 0.2
raddr_2_ 0.5 0.2
raddr_3_ 0.5 0.2
raddr_4_ 0.5 0.2
raddr_5_ 0.5 0.2
waddr_0_ 0.5 0.2
waddr_1_ 0.5 0.2
waddr_2_ 0.5 0.2
waddr_3_ 0.5 0.2
waddr_4_ 0.5 0.2
waddr_5_ 0.5 0.2
waddr_st0_0_ 0.5 0.2
waddr_st0_1_ 0.5 0.2
waddr_st0_2_ 0.5 0.2
waddr_st0_3_ 0.5 0.2
waddr_st0_4_ 0.5 0.2
waddr_st0_5_ 0.5 0.2
waddr_st1_0_ 0.5 0.2
waddr_st1_1_ 0.5 0.2
waddr_st1_2_ 0.5 0.2
waddr_st1_3_ 0.5 0.2
waddr_st1_4_ 0.5 0.2
waddr_st1_5_ 0.5 0.2
a_0_ 0.5 0.2
a_1_ 0.5 0.2
a_2_ 0.5 0.2
a_3_ 0.5 0.2
a_4_ 0.5 0.2
a_5_ 0.5 0.2
a_6_ 0.5 0.2
a_st0_0_ 0.5 0.2
a_st0_1_ 0.5 0.2
a_st0_2_ 0.5 0.2
a_st0_3_ 0.5 0.2
a_st0_4_ 0.5 0.2
a_st0_5_ 0.5 0.2
a_st0_6_ 0.5 0.2
a_st1_0_ 0.5 0.2
a_st1_1_ 0.5 0.2
a_st1_2_ 0.5 0.2
a_st1_3_ 0.5 0.2
a_st1_4_ 0.5 0.2
a_st1_5_ 0.5 0.2
a_st1_6_ 0.5 0.2
b_0_ 0.5 0.2
b_1_ 0.5 0.2
b_2_ 0.5 0.2
b_3_ 0.5 0.2
b_4_ 0.5 0.2
b_5_ 0.5 0.2
b_6_ 0.5 0.2
b_st0_0_ 0.5 0.2
b_st0_1_ 0.5 0.2
b_st0_2_ 0.5 0.2
b_st0_3_ 0.5 0.2
b_st0_4_ 0.5 0.2
b_st0_5_ 0.5 0.2
b_st0_6_ 0.5 0.2
b_st1_0_ 0.5 0.2
b_st1_1_ 0.5 0.2
b_st1_2_ 0.5 0.2
b_st1_3_ 0.5 0.2
b_st1_4_ 0.5 0.2
b_st1_5_ 0.5 0.2
b_st1_6_ 0.5 0.2
q_0_ 0.5 0.2
q_1_ 0.5 0.2
q_2_ 0.5 0.2
q_3_ 0.5 0.2
q_4_ 0.5 0.2
q_5_ 0.5 0.2
q_6_ 0.5 0.2
q_7_ 0.5 0.2
AplusB_0_ 0.5 0.2
AplusB_1_ 0.5 0.2
AplusB_2_ 0.5 0.2
AplusB_3_ 0.5 0.2
AplusB_4_ 0.5 0.2
AplusB_5_ 0.5 0.2
AplusB_6_ 0.5 0.2
AplusB_7_ 0.5 0.2
cint01 0.5 0.2
cint02 0.5 0.2
cint03 0.5 0.2
cint04 0.5 0.2
cint05 0.5 0.2
cint06 0.5 0.2
cint07 0.5 0.2
zero00 0 0

View File

@ -0,0 +1,126 @@
# Benchmark pipelined_32b_adder
.model pipelined_32b_adder
.inputs clk wen ren raddr_0_ raddr_1_ raddr_2_ raddr_3_ raddr_4_ raddr_5_ waddr_0_ waddr_1_ waddr_2_ waddr_3_ waddr_4_ waddr_5_ a_0_ a_1_ a_2_ a_3_ a_4_ a_5_ a_6_ b_0_ b_1_ b_2_ b_3_ b_4_ b_5_ b_6_
.outputs q_0_ q_1_ q_2_ q_3_ q_4_ q_5_ q_6_ q_7_
# Start pipeline
# Pipeline a
.subckt shift D=a_0_ clk=clk Q=a_st0_0_
.subckt shift D=a_st0_0_ clk=clk Q=a_st1_0_
.subckt shift D=a_1_ clk=clk Q=a_st0_1_
.subckt shift D=a_st0_1_ clk=clk Q=a_st1_1_
.subckt shift D=a_2_ clk=clk Q=a_st0_2_
.subckt shift D=a_st0_2_ clk=clk Q=a_st1_2_
.subckt shift D=a_3_ clk=clk Q=a_st0_3_
.subckt shift D=a_st0_3_ clk=clk Q=a_st1_3_
.subckt shift D=a_4_ clk=clk Q=a_st0_4_
.subckt shift D=a_st0_4_ clk=clk Q=a_st1_4_
.subckt shift D=a_5_ clk=clk Q=a_st0_5_
.subckt shift D=a_st0_5_ clk=clk Q=a_st1_5_
.subckt shift D=a_6_ clk=clk Q=a_st0_6_
.subckt shift D=a_st0_6_ clk=clk Q=a_st1_6_
# Pipeline b
.subckt shift D=b_0_ clk=clk Q=b_st0_0_
.subckt shift D=b_st0_0_ clk=clk Q=b_st1_0_
.subckt shift D=b_1_ clk=clk Q=b_st0_1_
.subckt shift D=b_st0_1_ clk=clk Q=b_st1_1_
.subckt shift D=b_2_ clk=clk Q=b_st0_2_
.subckt shift D=b_st0_2_ clk=clk Q=b_st1_2_
.subckt shift D=b_3_ clk=clk Q=b_st0_3_
.subckt shift D=b_st0_3_ clk=clk Q=b_st1_3_
.subckt shift D=b_4_ clk=clk Q=b_st0_4_
.subckt shift D=b_st0_4_ clk=clk Q=b_st1_4_
.subckt shift D=b_5_ clk=clk Q=b_st0_5_
.subckt shift D=b_st0_5_ clk=clk Q=b_st1_5_
.subckt shift D=b_6_ clk=clk Q=b_st0_6_
.subckt shift D=b_st0_6_ clk=clk Q=b_st1_6_
# Pipeline waddr
.subckt shift D=waddr_0_ clk=clk Q=waddr_st0_0_
.subckt shift D=waddr_st0_0_ clk=clk Q=waddr_st1_0_
.subckt shift D=waddr_1_ clk=clk Q=waddr_st0_1_
.subckt shift D=waddr_st0_1_ clk=clk Q=waddr_st1_1_
.subckt shift D=waddr_2_ clk=clk Q=waddr_st0_2_
.subckt shift D=waddr_st0_2_ clk=clk Q=waddr_st1_2_
.subckt shift D=waddr_3_ clk=clk Q=waddr_st0_3_
.subckt shift D=waddr_st0_3_ clk=clk Q=waddr_st1_3_
.subckt shift D=waddr_4_ clk=clk Q=waddr_st0_4_
.subckt shift D=waddr_st0_4_ clk=clk Q=waddr_st1_4_
.subckt shift D=waddr_5_ clk=clk Q=waddr_st0_5_
.subckt shift D=waddr_st0_5_ clk=clk Q=waddr_st1_5_
# Pipeline wen
.subckt shift D=wen clk=clk Q=wen_st0
.subckt shift D=wen_st0 clk=clk Q=wen_st1
# End pipeline
# Start adder
.subckt adder a=a_st1_0_ b=b_st1_0_ cin=zero00 cout=cint01 sumout=AplusB_0_
.subckt adder a=a_st1_1_ b=b_st1_1_ cin=cint01 cout=cint02 sumout=AplusB_1_
.subckt adder a=a_st1_2_ b=b_st1_2_ cin=cint02 cout=cint03 sumout=AplusB_2_
.subckt adder a=a_st1_3_ b=b_st1_3_ cin=cint03 cout=cint04 sumout=AplusB_3_
.subckt adder a=a_st1_4_ b=b_st1_4_ cin=cint04 cout=cint05 sumout=AplusB_4_
.subckt adder a=a_st1_5_ b=b_st1_5_ cin=cint05 cout=cint06 sumout=AplusB_5_
.subckt adder a=a_st1_6_ b=b_st1_6_ cin=cint06 cout=cint07 sumout=AplusB_6_
.subckt adder a=zero00 b=zero00 cin=cint07 cout=unconn sumout=AplusB_7_
# End adder
# Start DPRAM
.subckt dual_port_ram_32x512 clk=clk wen=wen_st1 ren=ren \
waddr[0]=waddr_st1_0_ waddr[1]=waddr_st1_1_ waddr[2]=waddr_st1_2_ waddr[3]=waddr_st1_3_ waddr[4]=waddr_st1_4_ \
waddr[5]=waddr_st1_5_ waddr[6]=zero00 waddr[7]=zero00 waddr[8]=zero00 \
raddr[0]=raddr_0_ raddr[1]=raddr_1_ raddr[2]=raddr_2_ raddr[3]=raddr_3_ raddr[4]=raddr_4_ raddr[5]=raddr_5_ \
raddr[6]=zero00 raddr[7]=zero00 raddr[8]=zero00 \
d_in[0]=AplusB_0_ d_in[1]=AplusB_1_ d_in[2]=AplusB_2_ d_in[3]=AplusB_3_ d_in[4]=AplusB_4_ d_in[5]=AplusB_5_ \
d_in[6]=AplusB_6_ d_in[7]=AplusB_7_ d_in[8]=zero00 d_in[9]=zero00 d_in[10]=zero00 d_in[11]=zero00 \
d_in[12]=zero00 d_in[13]=zero00 d_in[14]=zero00 d_in[15]=zero00 d_in[16]=zero00 d_in[17]=zero00 \
d_in[18]=zero00 d_in[19]=zero00 d_in[20]=zero00 d_in[21]=zero00 d_in[22]=zero00 d_in[23]=zero00 \
d_in[24]=zero00 d_in[25]=zero00 d_in[26]=zero00 d_in[27]=zero00 d_in[28]=zero00 d_in[29]=zero00 \
d_in[30]=zero00 d_in[31]=zero00 \
d_out[0]=q_0_ d_out[1]=q_1_ d_out[2]=q_2_ d_out[3]=q_3_ d_out[4]=q_4_ d_out[5]=q_5_ \
d_out[6]=q_6_ d_out[7]=q_7_ d_out[8]=unconn d_out[9]=unconn d_out[10]=unconn \
d_out[11]=unconn d_out[12]=unconn d_out[13]=unconn d_out[14]=unconn d_out[15]=unconn \
d_out[16]=unconn d_out[17]=unconn d_out[18]=unconn d_out[19]=unconn d_out[20]=unconn \
d_out[21]=unconn d_out[22]=unconn d_out[23]=unconn d_out[24]=unconn d_out[25]=unconn \
d_out[26]=unconn d_out[27]=unconn d_out[28]=unconn d_out[29]=unconn d_out[30]=unconn d_out[31]=unconn
# End DPRAM
# Start global variable
.names zero00
0
# End global variable
.end
# Start blackbox definition
.model dual_port_ram_32x512
.inputs clk ren wen waddr[0] waddr[1] waddr[2] waddr[3] waddr[4] waddr[5] \
waddr[6] waddr[7] waddr[8] raddr[0] raddr[1] raddr[2] \
raddr[3] raddr[4] raddr[5] raddr[6] raddr[7] raddr[8] \
d_in[0] d_in[1] d_in[2] d_in[3] d_in[4] d_in[5] d_in[6] d_in[7] d_in[8] \
d_in[9] d_in[10] d_in[11] d_in[12] d_in[13] d_in[14] d_in[15] d_in[16] \
d_in[17] d_in[18] d_in[19] d_in[20] d_in[21] d_in[22] d_in[23] d_in[24] \
d_in[25] d_in[26] d_in[27] d_in[28] d_in[29] d_in[30] d_in[31]
.outputs d_out[0] d_out[1] d_out[2] d_out[3] d_out[4] d_out[5] d_out[6] \
d_out[7] d_out[8] d_out[9] d_out[10] d_out[11] d_out[12] d_out[13] \
d_out[14] d_out[15] d_out[16] d_out[17] d_out[18] d_out[19] d_out[20] \
d_out[21] d_out[22] d_out[23] d_out[24] d_out[25] d_out[26] d_out[27] \
d_out[28] d_out[29] d_out[30] d_out[31]
.blackbox
.end
.model adder
.inputs a b cin
.outputs cout sumout
.blackbox
.end
.model shift
.inputs D clk
.outputs Q
.blackbox
.end
# End blackbox definition

View File

@ -0,0 +1,107 @@
//-----------------------------------------------------
// Design Name : pipelined_8bit_adder
// File Name : pipelined_8bit_adder.v
// Function : Pipelined 8-bit adders, whose sum and carry outputs
// are cached in a memory
// Coder : Aurelien Alacchi
//-----------------------------------------------------
`timescale 1 ns/ 1 ps
// To match the port definition in BLIF format, so that we can do verification
// Each input/output bus is expanded here.
// In future, we should be able to support buses in verification!
module pipelined_8bit_adder(
input clk,
input ren,
input wen,
input raddr_0_,
input raddr_1_,
input raddr_2_,
input raddr_3_,
input raddr_4_,
input raddr_5_,
input waddr_0_,
input waddr_1_,
input waddr_2_,
input waddr_3_,
input waddr_4_,
input waddr_5_,
input a_0_,
input a_1_,
input a_2_,
input a_3_,
input a_4_,
input a_5_,
input a_6_,
input b_0_,
input b_1_,
input b_2_,
input b_3_,
input b_4_,
input b_5_,
input b_6_,
output q_0_,
output q_1_,
output q_2_,
output q_3_,
output q_4_,
output q_5_,
output q_6_,
output q_7_);
wire [5:0] raddr;
wire [5:0] waddr;
wire [6:0] a;
wire [6:0] b;
wire [7:0] q;
assign raddr = { raddr_5_, raddr_4_, raddr_3_, raddr_2_, raddr_1_, raddr_0_ };
assign waddr = { waddr_5_, waddr_4_, waddr_3_, waddr_2_, waddr_1_, waddr_0_ };
assign a = { a_6_, a_5_, a_4_, a_3_, a_2_, a_1_, a_0_ };
assign b = { b_6_, b_5_, b_4_, b_3_, b_2_, b_1_, b_0_ };
assign q_7_ = q[7];
assign q_6_ = q[6];
assign q_5_ = q[5];
assign q_4_ = q[4];
assign q_3_ = q[3];
assign q_2_ = q[2];
assign q_1_ = q[1];
assign q_0_ = q[0];
reg[7:0] ram[63:0];
reg[6:0] a_st0;
reg[6:0] a_st1;
reg[6:0] b_st0;
reg[6:0] b_st1;
reg[8:0] waddr_st0;
reg[8:0] waddr_st1;
reg wen_st0;
reg wen_st1;
reg[7:0] q_int;
wire[7:0] AplusB;
assign AplusB = a_st1 + b_st1;
assign q = q_int;
always@(posedge clk) begin
waddr_st0 <= waddr;
waddr_st1 <= waddr_st0;
a_st0 <= a;
a_st1 <= a_st0;
b_st0 <= b;
b_st1 <= b_st0;
wen_st0 <= wen;
wen_st1 <= wen_st0;
if(wen_st1) begin
ram[waddr_st1] <= AplusB;
end
if(ren) begin
q_int <= ram[raddr];
end
end
endmodule

View File

@ -0,0 +1,267 @@
//-----------------------------------------------------
// Design Name : pipelined_8bit_adder_top_formal_verification_random_tb
// File Name : pipelined_8bit_adder.v
// Function : Testbench for pipelined 8-bit adders, whose sum and carry outputs
// are cached in a dual-port memory.
// This testbench will do a verification of FPGA implementation
// of the pipelined 8-bit adders against the reference
// (original) Verilog netlist
// To provide a practical testing, this testbench will :
// - Instantiate a pre-programmed FPGA and the proper
// benchmark
// - Load memories with random values
// - Randomly write and read from the memories
// - Watch for any difference between FPGA and Benchmark
// outputs, after memories are fully loaded
//
// PLEASE USE this testbench instead of the auto-generated test
// benches when performing verification!
// Coder : Aurelien Alacchi and Xifan Tang
//-----------------------------------------------------
`timescale 1 ns/ 100 ps
module pipelined_8bit_adder_top_formal_verification_random_tb();
reg clk;
reg[5:0] raddr;
reg[5:0] waddr;
reg ren;
reg wen;
reg[6:0] a;
reg[6:0] b;
wire[7:0] q_gfpga;
wire[7:0] q_bench;
reg[7:0] q_flag;
pipelined_8bit_adder_top_formal_verification DUT(
.clk_fm (clk),
.ren_fm (ren),
.wen_fm (wen),
.raddr_0__fm (raddr[0]),
.raddr_1__fm (raddr[1]),
.raddr_2__fm (raddr[2]),
.raddr_3__fm (raddr[3]),
.raddr_4__fm (raddr[4]),
.raddr_5__fm (raddr[5]),
.waddr_0__fm (waddr[0]),
.waddr_1__fm (waddr[1]),
.waddr_2__fm (waddr[2]),
.waddr_3__fm (waddr[3]),
.waddr_4__fm (waddr[4]),
.waddr_5__fm (waddr[5]),
.a_0__fm (a[0]),
.a_1__fm (a[1]),
.a_2__fm (a[2]),
.a_3__fm (a[3]),
.a_4__fm (a[4]),
.a_5__fm (a[5]),
.a_6__fm (a[6]),
.b_0__fm (b[0]),
.b_1__fm (b[1]),
.b_2__fm (b[2]),
.b_3__fm (b[3]),
.b_4__fm (b[4]),
.b_5__fm (b[5]),
.b_6__fm (b[6]),
.out_q_0__fm (q_gfpga[0]),
.out_q_1__fm (q_gfpga[1]),
.out_q_2__fm (q_gfpga[2]),
.out_q_3__fm (q_gfpga[3]),
.out_q_4__fm (q_gfpga[4]),
.out_q_5__fm (q_gfpga[5]),
.out_q_6__fm (q_gfpga[6]),
.out_q_7__fm (q_gfpga[7])
);
pipelined_8bit_adder ref0(
.clk (clk),
.ren (ren),
.wen (wen),
.raddr_0_ (raddr[0]),
.raddr_1_ (raddr[1]),
.raddr_2_ (raddr[2]),
.raddr_3_ (raddr[3]),
.raddr_4_ (raddr[4]),
.raddr_5_ (raddr[5]),
.waddr_0_ (waddr[0]),
.waddr_1_ (waddr[1]),
.waddr_2_ (waddr[2]),
.waddr_3_ (waddr[3]),
.waddr_4_ (waddr[4]),
.waddr_5_ (waddr[5]),
.a_0_ (a[0]),
.a_1_ (a[1]),
.a_2_ (a[2]),
.a_3_ (a[3]),
.a_4_ (a[4]),
.a_5_ (a[5]),
.a_6_ (a[6]),
.b_0_ (b[0]),
.b_1_ (b[1]),
.b_2_ (b[2]),
.b_3_ (b[3]),
.b_4_ (b[4]),
.b_5_ (b[5]),
.b_6_ (b[6]),
.q_0_ (q_bench[0]),
.q_1_ (q_bench[1]),
.q_2_ (q_bench[2]),
.q_3_ (q_bench[3]),
.q_4_ (q_bench[4]),
.q_5_ (q_bench[5]),
.q_6_ (q_bench[6]),
.q_7_ (q_bench[7])
);
integer nb_error = 0;
integer count = 0;
integer lim_max = 64 - 1;
integer write_complete = 0;
//----- Initialization
initial begin
clk <= 1'b0;
a <= 7'h00;
b <= 7'h00;
wen <= 1'b0;
ren <= 1'b0;
waddr <= 6'h00;
raddr <= 6'h00;
while(1) begin
#2.5
clk <= !clk;
end
end
//----- Input Stimulis
always@(negedge clk) begin
if(write_complete == 0) begin
wen <= 1'b1;
ren <= 1'b0;
count <= count + 1;
waddr <= waddr + 1;
if(count == lim_max) begin
write_complete = 1;
end
end else begin
wen <= $random;
ren <= $random;
waddr <= $random;
raddr <= $random;
end
a <= $random;
b <= $random;
end
always@(negedge clk) begin
if(!(q_gfpga[0] === q_bench[0]) && !(q_bench[0] === 1'bx)) begin
q_flag[0] <= 1'b1;
end else begin
q_flag[0] <= 1'b0;
end
if(!(q_gfpga[1] === q_bench[1]) && !(q_bench[1] === 1'bx)) begin
q_flag[1] <= 1'b1;
end else begin
q_flag[1] <= 1'b0;
end
if(!(q_gfpga[2] === q_bench[2]) && !(q_bench[2] === 1'bx)) begin
q_flag[2] <= 1'b1;
end else begin
q_flag[2] <= 1'b0;
end
if(!(q_gfpga[3] === q_bench[3]) && !(q_bench[3] === 1'bx)) begin
q_flag[3] <= 1'b1;
end else begin
q_flag[3] <= 1'b0;
end
if(!(q_gfpga[4] === q_bench[4]) && !(q_bench[4] === 1'bx)) begin
q_flag[4] <= 1'b1;
end else begin
q_flag[4] <= 1'b0;
end
if(!(q_gfpga[5] === q_bench[5]) && !(q_bench[5] === 1'bx)) begin
q_flag[5] <= 1'b1;
end else begin
q_flag[5] <= 1'b0;
end
if(!(q_gfpga[6] === q_bench[6]) && !(q_bench[6] === 1'bx)) begin
q_flag[6] <= 1'b1;
end else begin
q_flag[6] <= 1'b0;
end
if(!(q_gfpga[7] === q_bench[7]) && !(q_bench[7] === 1'bx)) begin
q_flag[7] <= 1'b1;
end else begin
q_flag[7] <= 1'b0;
end
end
always@(posedge q_flag[0]) begin
if(q_flag[0]) begin
nb_error = nb_error + 1;
$display("Mismatch on q_gfpga[0] at time = %t", $realtime);
end
end
always@(posedge q_flag[1]) begin
if(q_flag[1]) begin
nb_error = nb_error + 1;
$display("Mismatch on q_gfpga[1] at time = %t", $realtime);
end
end
always@(posedge q_flag[2]) begin
if(q_flag[2]) begin
nb_error = nb_error + 1;
$display("Mismatch on q_gfpga[2] at time = %t", $realtime);
end
end
always@(posedge q_flag[3]) begin
if(q_flag[3]) begin
nb_error = nb_error + 1;
$display("Mismatch on q_gfpga[3] at time = %t", $realtime);
end
end
always@(posedge q_flag[4]) begin
if(q_flag[4]) begin
nb_error = nb_error + 1;
$display("Mismatch on q_gfpga[4] at time = %t", $realtime);
end
end
always@(posedge q_flag[5]) begin
if(q_flag[5]) begin
nb_error = nb_error + 1;
$display("Mismatch on q_gfpga[5] at time = %t", $realtime);
end
end
always@(posedge q_flag[6]) begin
if(q_flag[6]) begin
nb_error = nb_error + 1;
$display("Mismatch on q_gfpga[6] at time = %t", $realtime);
end
end
always@(posedge q_flag[7]) begin
if(q_flag[7]) begin
nb_error = nb_error + 1;
$display("Mismatch on q_gfpga[7] at time = %t", $realtime);
end
end
initial begin
$dumpfile("pipelined_8bit_adder_formal.vcd");
$dumpvars(1, pipelined_8bit_adder_top_formal_verification_random_tb);
end
initial begin
$timeformat(-9, 2, "ns", 20);
$display("Simulation start");
#1500 // Can be changed by the user for his need
if(nb_error == 0) begin
$display("Simulation Succeed");
end else begin
$display("Simulation Failed with %d error(s)", nb_error);
end
$finish;
end
endmodule

View File

@ -0,0 +1,71 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# Script Name : regression.py
# Description : This script designed to run:
# openfpga_flow tasks
# run_{simulator}.py
# Args : python3 regression.py --help
# Author : Aurelien Alacchi
# Email : aurelien.alacchi@utah.edu
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
import os
import sys
import shutil
import time
from datetime import timedelta
import shlex
import argparse
from configparser import ConfigParser, ExtendedInterpolation
import logging
import glob
import subprocess
import threading
import csv
from string import Template
import pprint
from importlib import util
from collections import OrderedDict
modelsim="modelsim"
vcs="vcs"
formality="formality"
modelsim_file="simulation_deck_info.ini"
ini_list=""
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# Parse commandline arguments
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
parser = argparse.ArgumentParser()
parser.add_argument('tasks', nargs='+')
parser.add_argument('--maxthreads', type=int, default=2,
help="Number of fpga_flow threads to run default = 2," +
"Typically <= Number of processors on the system")
parser.add_argument('--simulator', type=str, default=modelsim,
help="Simulator to use. Set at \"" + modelsim + "\" by default. Can also be \"" + vcs + "\" or \"" + formality + "\"")
args = parser.parse_args()
args.tasks=str(args.tasks).strip('[]')
#print(args.tasks)
#print(args.maxthreads)
command="python3 openfpga_flow/scripts/run_fpga_task.py " + args.tasks + " --maxthreads " + str(args.maxthreads) + " --debug --show_thread_logs"
print(command)
os.system(command)
if(args.simulator == modelsim):
command="python3 openfpga_flow/scripts/run_modelsim.py"
os.system("grep \"INFO - Run directory :\" openfpga_flow/tasks/" + args.tasks + "/latest/*.log > paths_ini.txt")
arguments = " --skip_prompt --run_sim";
fp = open("paths_ini.txt")
line = fp.readline()
while line:
ini_list= ini_list + line + modelsim_file
line = fp.readline()
ini_list = ini_list.replace("INFO - Run directory :", "")
ini_list = ini_list.replace("\n", "/")
fp.close()
print(command + ini_list + arguments)
os.system(command + ini_list + arguments)

View File

@ -1,66 +0,0 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# Configuration file for running experiments
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
# Each job execute fpga_flow script on combination of architecture & benchmark
# timeout_each_job is timeout for each job
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
[GENERAL]
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
power_analysis = true
spice_output=false
verilog_output=true
timeout_each_job = 20*60
fpga_flow=vpr_blif
[ARCHITECTURES]
# arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_DPRAM_template.xml
arch1=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml
arch2=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_local_encoder_template.xml
arch3=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_behavioral_verilog_template.xml
arch4=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_non_lut_intermediate_buffer_template.xml
arch5=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_1IO_template.xml
#arch5=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tree_mux_template.xml
#arch4=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k8_N10_sram_chain_FC_template.xml
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.blif
[SYNTHESIS_PARAM]
bench0_top = test_modes
bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.act
bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.v
bench0_chan_width = 300
#[SCRIPT_PARAM_FIX_ROUTE_CHAN_WIDTH]
#fix_route_chan_width=300
#vpr_fpga_verilog_include_icarus_simulator=
#vpr_fpga_verilog_formal_verification_top_netlist=
#vpr_fpga_verilog_include_timing=
#vpr_fpga_verilog_include_signal_init=
#vpr_fpga_verilog_print_autocheck_top_testbench=
#vpr_fpga_bitstream_generator=
#vpr_fpga_verilog_print_user_defined_template=
#vpr_fpga_verilog_print_report_timing_tcl=
#vpr_fpga_verilog_print_sdc_pnr=
#vpr_fpga_verilog_print_sdc_analysis=
##vpr_fpga_x2p_compact_routing_hierarchy=
#end_flow_with_test=
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
min_route_chan_width=1.3
vpr_fpga_verilog_include_icarus_simulator=
vpr_fpga_verilog_formal_verification_top_netlist=
vpr_fpga_verilog_include_timing=
vpr_fpga_verilog_include_signal_init=
vpr_fpga_verilog_print_autocheck_top_testbench=
vpr_fpga_bitstream_generator=
vpr_fpga_verilog_print_user_defined_template=
vpr_fpga_verilog_print_report_timing_tcl=
vpr_fpga_verilog_print_sdc_pnr=
vpr_fpga_verilog_print_sdc_analysis=
#vpr_fpga_verilog_explicit_mapping=
#vpr_fpga_x2p_compact_routing_hierarchy=
end_flow_with_test=

View File

@ -0,0 +1,43 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# Configuration file for running experiments
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
# Each job execute fpga_flow script on combination of architecture & benchmark
# timeout_each_job is timeout for each job
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
[GENERAL]
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
power_analysis = true
spice_output=false
verilog_output=true
timeout_each_job = 20*60
fpga_flow=vpr_blif
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_DPRAM_template.xml
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.blif
[SYNTHESIS_PARAM]
bench0_top = pipelined_8bit_adder
bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.act
bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.v
bench0_chan_width = 100
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
min_route_chan_width=1.3
vpr_fpga_verilog_include_icarus_simulator=
vpr_fpga_verilog_formal_verification_top_netlist=
vpr_fpga_verilog_include_timing=
vpr_fpga_verilog_include_signal_init=
vpr_fpga_verilog_print_autocheck_top_testbench=
vpr_fpga_bitstream_generator=
#vpr_fpga_verilog_print_user_defined_template=
#vpr_fpga_verilog_print_report_timing_tcl=
#vpr_fpga_verilog_print_sdc_pnr=
#vpr_fpga_verilog_print_sdc_analysis=
vpr_fpga_verilog_explicit_mapping=
vpr_fpga_x2p_compact_routing_hierarchy=
end_flow_with_test=

View File

@ -15,15 +15,19 @@ timeout_each_job = 20*60
fpga_flow=vpr_blif
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml
#arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml
#arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k4_N4_sram_chain_FC_behavioral_verilog_template.xml
#arch1=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tileable_template.xml
arch1=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tileable_template.xml
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/alu4/alu4.blif
# Pass
#bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/alu4/alu4.blif
# Pass, but port does not match, i_15_ is dangling
#bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/apex2/apex2.blif
# Pass
#bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/apex4/apex4.blif
#bench3=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/bigkey/bigkey.blif
bench3=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/bigkey/bigkey.blif
# To be tested
#bench4=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/clma/clma.blif
#bench5=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/des/des.blif
#bench6=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/diffeq/diffeq.blif
@ -34,8 +38,10 @@ bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/alu4/alu4.blif
#bench11=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/frisc/frisc.blif
#bench12=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/misex3/misex3.blif
#bench13=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/pdc/pdc.blif
#bench14=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/s298/s298.blif # Pass
#bench15=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/s38417/s38417.blif # Multi-mode support fails to repack
# Pass
#bench14=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/s298/s298.blif
# Multi-mode support fails to repack
#bench15=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/s38417/s38417.blif
#bench16=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/s38584/s38584.blif
#bench17=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/seq/seq.blif
#bench18=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/spla/spla.blif
@ -147,10 +153,10 @@ vpr_fpga_verilog_include_signal_init=
vpr_fpga_verilog_print_autocheck_top_testbench=
vpr_fpga_bitstream_generator=
vpr_fpga_verilog_print_user_defined_template=
vpr_fpga_verilog_print_report_timing_tcl=
vpr_fpga_verilog_print_sdc_pnr=
vpr_fpga_verilog_print_sdc_analysis=
#vpr_fpga_verilog_print_report_timing_tcl=
#vpr_fpga_verilog_print_sdc_pnr=
#vpr_fpga_verilog_print_sdc_analysis=
vpr_fpga_verilog_explicit_mapping=
vpr_fpga_x2p_compact_routing_hierarchy=
end_flow_with_test=
#end_flow_with_test=

View File

@ -16,15 +16,21 @@ fpga_flow=vpr_blif
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml
arch1=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_local_encoder_template.xml
arch2=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_behavioral_verilog_template.xml
arch3=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_non_lut_intermediate_buffer_template.xml
arch4=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_1IO_template.xml
arch5=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tree_mux_template.xml
arch6=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_stdcell_mux2_template.xml
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k4_N4/K4N4_test_modes.blif
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.blif
[SYNTHESIS_PARAM]
bench0_top = K4n4_test
bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k4_N4/K4N4_test_modes.act
bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k4_N4/K4N4_test_modes.v
bench0_chan_width = 100
bench0_top = test_modes
bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.act
bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.v
bench0_chan_width = 300
#[SCRIPT_PARAM_FIX_ROUTE_CHAN_WIDTH]
#fix_route_chan_width=300
@ -38,10 +44,10 @@ bench0_chan_width = 100
#vpr_fpga_verilog_print_report_timing_tcl=
#vpr_fpga_verilog_print_sdc_pnr=
#vpr_fpga_verilog_print_sdc_analysis=
#vpr_fpga_x2p_compact_routing_hierarchy=
##vpr_fpga_x2p_compact_routing_hierarchy=
#end_flow_with_test=
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH_0]
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
min_route_chan_width=1.3
vpr_fpga_verilog_include_icarus_simulator=
vpr_fpga_verilog_formal_verification_top_netlist=
@ -56,3 +62,4 @@ vpr_fpga_verilog_print_sdc_analysis=
#vpr_fpga_verilog_explicit_mapping=
#vpr_fpga_x2p_compact_routing_hierarchy=
end_flow_with_test=

View File

@ -55,4 +55,5 @@ vpr_fpga_verilog_print_sdc_pnr=
vpr_fpga_verilog_print_sdc_analysis=
vpr_fpga_verilog_explicit_mapping=
vpr_fpga_x2p_compact_routing_hierarchy=
#vpr_fpga_verilog_print_simulation_ini=
end_flow_with_test=

View File

@ -410,7 +410,7 @@ size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) {
for (size_t iport = 0; iport < global_ports.size() - 1; ++iport) {
for (size_t jport = iport + 1; jport < global_ports.size(); ++jport) {
/* Bypass those do not share the same name */
if (0 != circuit_lib.port_lib_name(global_ports[iport]).compare(circuit_lib.port_lib_name(global_ports[jport]))) {
if (0 != circuit_lib.port_prefix(global_ports[iport]).compare(circuit_lib.port_prefix(global_ports[jport]))) {
continue;
}
@ -421,7 +421,7 @@ size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) {
if (circuit_lib.port_default_value(global_ports[iport]) != circuit_lib.port_default_value(global_ports[jport])) {
vpr_printf(TIO_MESSAGE_ERROR,
"Global ports %s from circuit model %s and %s share the same name but have different dfefault values(%lu and %lu)!\n",
circuit_lib.port_lib_name(global_ports[iport]).c_str(),
circuit_lib.port_prefix(global_ports[iport]).c_str(),
circuit_lib.model_name(iport_parent_model).c_str(),
circuit_lib.model_name(jport_parent_model).c_str(),
circuit_lib.port_default_value(global_ports[iport]),
@ -433,7 +433,7 @@ size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) {
if (circuit_lib.port_is_reset(global_ports[iport]) != circuit_lib.port_is_reset(global_ports[jport])) {
vpr_printf(TIO_MESSAGE_ERROR,
"Global ports %s from circuit model %s and %s share the same name but have different is_reset attributes!\n",
circuit_lib.port_lib_name(global_ports[iport]).c_str(),
circuit_lib.port_prefix(global_ports[iport]).c_str(),
circuit_lib.model_name(iport_parent_model).c_str(),
circuit_lib.model_name(jport_parent_model).c_str()
);
@ -442,7 +442,7 @@ size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) {
if (circuit_lib.port_is_set(global_ports[iport]) != circuit_lib.port_is_set(global_ports[jport])) {
vpr_printf(TIO_MESSAGE_ERROR,
"Global ports %s from circuit model %s and %s share the same name but have different is_set attributes!\n",
circuit_lib.port_lib_name(global_ports[iport]).c_str(),
circuit_lib.port_prefix(global_ports[iport]).c_str(),
circuit_lib.model_name(iport_parent_model).c_str(),
circuit_lib.model_name(jport_parent_model).c_str()
);
@ -451,7 +451,7 @@ size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) {
if (circuit_lib.port_is_config_enable(global_ports[iport]) != circuit_lib.port_is_config_enable(global_ports[jport])) {
vpr_printf(TIO_MESSAGE_ERROR,
"Global ports %s from circuit model %s and %s share the same name but have different is_config_enable attributes!\n",
circuit_lib.port_lib_name(global_ports[iport]).c_str(),
circuit_lib.port_prefix(global_ports[iport]).c_str(),
circuit_lib.model_name(iport_parent_model).c_str(),
circuit_lib.model_name(jport_parent_model).c_str()
);
@ -460,7 +460,7 @@ size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) {
if (circuit_lib.port_is_prog(global_ports[iport]) != circuit_lib.port_is_prog(global_ports[jport])) {
vpr_printf(TIO_MESSAGE_ERROR,
"Global ports %s from circuit model %s and %s share the same name but have different is_prog attributes!\n",
circuit_lib.port_lib_name(global_ports[iport]).c_str(),
circuit_lib.port_prefix(global_ports[iport]).c_str(),
circuit_lib.model_name(iport_parent_model).c_str(),
circuit_lib.model_name(jport_parent_model).c_str()
);
@ -579,14 +579,17 @@ void check_circuit_library(const CircuitLibrary& circuit_lib) {
num_err += check_required_default_circuit_model(circuit_lib, SPICE_MODEL_WIRE);
/* If we have any errors, exit */
vpr_printf(TIO_MESSAGE_INFO,
"Finished checking circuit library with %d errors!\n",
num_err);
if (0 < num_err) {
vpr_printf(TIO_MESSAGE_INFO,
"Finished checking circuit library with %d errors!\n",
num_err);
exit(1);
}
vpr_printf(TIO_MESSAGE_INFO,
"Checking circuit library passed.\n");
return;
}

View File

@ -226,7 +226,7 @@ std::vector<CircuitPortId> find_circuit_library_global_ports(const CircuitLibrar
/* Check if a same port with the same name has already been in the list */
bool add_to_list = true;
for (const auto& global_port : global_ports) {
if (0 == circuit_lib.port_lib_name(port).compare(circuit_lib.port_lib_name(global_port))) {
if (0 == circuit_lib.port_prefix(port).compare(circuit_lib.port_prefix(global_port))) {
/* Same name, skip list update */
add_to_list = false;
break;
@ -240,3 +240,26 @@ std::vector<CircuitPortId> find_circuit_library_global_ports(const CircuitLibrar
return global_ports;
}
/********************************************************************
* A generic function to find all the unique user-defined
* Verilog netlists in a circuit library
* Netlists with same names will be considered as one
*******************************************************************/
std::vector<std::string> find_circuit_library_unique_verilog_netlists(const CircuitLibrary& circuit_lib) {
std::vector<std::string> netlists;
for (const CircuitModelId& model : circuit_lib.models()) {
/* Skip empty netlist names */
if (true == circuit_lib.model_verilog_netlist(model).empty()) {
continue;
}
/* See if the netlist name is already in the list */
std::vector<std::string>::iterator it = std::find(netlists.begin(), netlists.end(), circuit_lib.model_verilog_netlist(model));
if (it == netlists.end()) {
netlists.push_back(circuit_lib.model_verilog_netlist(model));
}
}
return netlists;
}

View File

@ -29,4 +29,6 @@ size_t find_circuit_num_config_bits(const CircuitLibrary& circuit_lib,
std::vector<CircuitPortId> find_circuit_library_global_ports(const CircuitLibrary& circuit_lib);
std::vector<std::string> find_circuit_library_unique_verilog_netlists(const CircuitLibrary& circuit_lib);
#endif

View File

@ -65,14 +65,14 @@ if (ENABLE_VPR_GRAPHIC_CXX_FLAG)
libarchfpga
X11
libvtrutil
readline
libini)
libini
readline)
else ()
target_link_libraries(libvpr
libarchfpga
libvtrutil
readline
libini)
libini
readline)
endif()
#Create the executables

View File

@ -100,6 +100,8 @@ struct s_TokenPair OptionBaseTokenList[] = {
{ "fpga_verilog_report_timing_rpt_path", OT_FPGA_VERILOG_SYN_REPORT_TIMING_RPT_PATH }, /* Specify the simulator path for Verilog netlists */
{ "fpga_verilog_print_sdc_pnr", OT_FPGA_VERILOG_SYN_PRINT_SDC_PNR }, /* Specify the simulator path for Verilog netlists */
{ "fpga_verilog_print_sdc_analysis", OT_FPGA_VERILOG_SYN_PRINT_SDC_ANALYSIS }, /* Specify the simulator path for Verilog netlists */
{ "fpga_verilog_print_simulation_ini", OT_FPGA_VERILOG_SYN_PRINT_SIMULATION_INI }, /* Specify the simulator path for Verilog netlists */
{ "fpga_verilog_simulation_ini_file", OT_FPGA_VERILOG_SYN_SIMULATION_INI_FILE }, /* Specify the simulator path for Verilog netlists */
/* Xifan Tang: Bitstream generator */
{ "fpga_bitstream_generator", OT_FPGA_BITSTREAM_GENERATOR }, /* turn on bitstream generator, and specify the output file */
// { "fpga_bitstream_output_file", OT_FPGA_BITSTREAM_OUTPUT_FILE }, /* turn on bitstream generator, and specify the output file */ // AA: temporarily deprecated

View File

@ -117,6 +117,8 @@ enum e_OptionBaseToken {
OT_FPGA_VERILOG_SYN_REPORT_TIMING_RPT_PATH,
OT_FPGA_VERILOG_SYN_PRINT_SDC_PNR,
OT_FPGA_VERILOG_SYN_PRINT_SDC_ANALYSIS,
OT_FPGA_VERILOG_SYN_PRINT_SIMULATION_INI,
OT_FPGA_VERILOG_SYN_SIMULATION_INI_FILE,
/* Xifan Tang: Bitstream generator */
OT_FPGA_BITSTREAM_GENERATOR,
OT_FPGA_BITSTREAM_OUTPUT_FILE,

View File

@ -559,6 +559,10 @@ ProcessOption(INP char **Args, INOUTP t_options * Options) {
return Args;
case OT_FPGA_VERILOG_SYN_PRINT_SDC_ANALYSIS:
return Args;
case OT_FPGA_VERILOG_SYN_PRINT_SIMULATION_INI:
return Args;
case OT_FPGA_VERILOG_SYN_SIMULATION_INI_FILE:
return ReadString(Args, &Options->fpga_verilog_simulation_ini_path);
/* Xifan TANG: Bitstream generator */
case OT_FPGA_BITSTREAM_GENERATOR:
return Args;

View File

@ -107,6 +107,7 @@ struct s_options {
char* fpga_verilog_reference_benchmark_file;
char* fpga_verilog_modelsim_ini_path;
char* fpga_verilog_report_timing_path;
char* fpga_verilog_simulation_ini_path;
/* Xifan TANG: Bitstream generator */
char* fpga_bitstream_file;
};

View File

@ -1113,6 +1113,8 @@ static void SetupSynVerilogOpts(t_options Options,
syn_verilog_opts->print_sdc_pnr = FALSE;
syn_verilog_opts->print_sdc_analysis = FALSE;
syn_verilog_opts->include_icarus_simulator = FALSE;
syn_verilog_opts->print_simulation_ini = FALSE;
syn_verilog_opts->simulation_ini_path = NULL;
/* Turn on Syn_verilog options */
if (Options.Count[OT_FPGA_VERILOG_SYN]) {
@ -1183,6 +1185,14 @@ static void SetupSynVerilogOpts(t_options Options,
syn_verilog_opts->print_sdc_analysis = TRUE;
}
if (Options.Count[OT_FPGA_VERILOG_SYN_PRINT_SIMULATION_INI]) {
syn_verilog_opts->print_simulation_ini = TRUE;
if (Options.Count[OT_FPGA_VERILOG_SYN_SIMULATION_INI_FILE]) {
syn_verilog_opts->simulation_ini_path = my_strdup(Options.fpga_verilog_simulation_ini_path);
}
}
/* SynVerilog needs the input from spice modeling */
if (FALSE == arch->read_xml_spice) {
arch->read_xml_spice = syn_verilog_opts->dump_syn_verilog;

View File

@ -211,6 +211,8 @@ void vpr_print_usage(void) {
vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_report_timing_rpt_path <path_to_generate_reports>\n");
vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_print_sdc_pnr\n");
vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_print_sdc_analysis\n");
vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_print_simulation_ini\n");
vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_simulation_ini_file <ini_file_path>\n");
/* Xifan Tang: Bitstream generator */
vpr_printf(TIO_MESSAGE_INFO, "Bitstream Generator Options:\n");
vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_bitstream_generator\n");

View File

@ -1281,6 +1281,8 @@ struct s_syn_verilog_opts {
boolean print_report_timing_tcl;
boolean print_sdc_pnr;
boolean print_sdc_analysis;
boolean print_simulation_ini;
char* simulation_ini_path;
};
/* Xifan TANG: bitstream generator */

View File

@ -0,0 +1,624 @@
/********************************************************************
* This file includes functions that are used to write SDC commands
* to disable unused ports of grids, such as Configurable Logic Block
* (CLBs), heterogeneous blocks, etc.
*******************************************************************/
#include "vtr_assert.h"
#include "fpga_x2p_reserved_words.h"
#include "fpga_x2p_naming.h"
#include "fpga_x2p_utils.h"
#include "fpga_x2p_pbtypes_utils.h"
#include "sdc_writer_utils.h"
#include "analysis_sdc_writer_utils.h"
#include "analysis_sdc_grid_writer.h"
#include "globals.h"
/********************************************************************
* Recursively visit all the pb_types in the hierarchy
* and disable all the ports
*
* Note: it is a must to disable all the ports in all the child pb_types!
* This can prohibit timing analyzer to consider any FF-to-FF path or
* combinatinal path inside an unused grid, when finding critical paths!!!
*******************************************************************/
static
void rec_print_analysis_sdc_disable_unused_pb_graph_nodes(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& parent_module,
const std::string& hierarchy_name,
t_pb_graph_node* physical_pb_graph_node,
const e_side& border_side) {
t_pb_type* physical_pb_type = physical_pb_graph_node->pb_type;
/* Validate file stream */
check_file_handler(fp);
/* Disable all the ports of current module (parent_module)!
* Hierarchy name already includes the instance name of parent_module
*/
fp << "set_disable_timing ";
fp << hierarchy_name;
fp << "/*";
fp << std::endl;
/* Return if this is the primitive pb_type */
if (TRUE == is_primitive_pb_type(physical_pb_type)) {
return;
}
/* Go recursively */
int physical_mode_index = find_pb_type_physical_mode_index(*physical_pb_type);
/* Disable all the ports by iterating over its instance in the parent module */
for (int ichild = 0; ichild < physical_pb_type->modes[physical_mode_index].num_pb_type_children; ++ichild) {
/* Generate the name of the Verilog module for this child */
std::string child_module_name_prefix = generate_grid_block_prefix(std::string(GRID_MODULE_NAME_PREFIX), border_side);
std::string child_module_name = generate_physical_block_module_name(child_module_name_prefix, &(physical_pb_type->modes[physical_mode_index].pb_type_children[ichild]));
ModuleId child_module = module_manager.find_module(child_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(child_module));
/* Each child may exist multiple times in the hierarchy*/
for (int inst = 0; inst < physical_pb_type->modes[physical_mode_index].pb_type_children[ichild].num_pb; ++inst) {
std::string child_instance_name = module_manager.instance_name(parent_module, child_module, module_manager.child_module_instances(parent_module, child_module)[inst]);
/* Must have a valid instance name!!! */
VTR_ASSERT(false == child_instance_name.empty());
std::string updated_hierarchy_name = hierarchy_name + std::string("/") + child_instance_name + std::string("/");
rec_print_analysis_sdc_disable_unused_pb_graph_nodes(fp, module_manager, child_module, hierarchy_name,
&(physical_pb_graph_node->child_pb_graph_nodes[physical_mode_index][ichild][inst]),
border_side);
}
}
}
/********************************************************************
* Disable an unused pin of a pb_graph_node (parent_module)
*******************************************************************/
static
void disable_pb_graph_node_unused_pin(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& parent_module,
const std::string& hierarchy_name,
const t_pb_graph_pin& pb_graph_pin,
t_phy_pb* block_physical_pb) {
/* Validate file stream */
check_file_handler(fp);
int rr_node_index = pb_graph_pin.rr_node_index_physical_pb;
/* Identify if the net has been used or not */
if (false == is_rr_node_to_be_disable_for_analysis(&(block_physical_pb->rr_graph->rr_node[rr_node_index]))) {
/* Used pin; Nothing to do */
return;
}
/* Reach here, it means that this pin is not used. Disable timing analysis for the pin */
/* Find the module port by name */
std::string module_port_name = generate_pb_type_port_name(pb_graph_pin.port);
ModulePortId module_port = module_manager.find_module_port(parent_module, module_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(parent_module, module_port));
BasicPort port_to_disable = module_manager.module_port(parent_module, module_port);
port_to_disable.set_width(pb_graph_pin.pin_number, pb_graph_pin.pin_number);
fp << "set_disable_timing ";
fp << hierarchy_name;
fp << "/";
fp << generate_sdc_port(port_to_disable);
fp << std::endl;
}
/********************************************************************
* Disable unused input ports and output ports of this pb_graph_node (parent_module)
* This function will iterate over all the input pins, output pins
* of the physical_pb_graph_node, and check if they are mapped
* For unused pins, we will find the port in parent_module
* and then print SDC commands to disable them
*******************************************************************/
static
void disable_pb_graph_node_unused_pins(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& parent_module,
const std::string& hierarchy_name,
t_pb_graph_node* physical_pb_graph_node,
t_phy_pb* block_physical_pb) {
/* Disable unused input pins */
for (int iport = 0; iport < physical_pb_graph_node->num_input_ports; ++iport) {
for (int ipin = 0; ipin < physical_pb_graph_node->num_input_pins[iport]; ++ipin) {
disable_pb_graph_node_unused_pin(fp, module_manager, parent_module,
hierarchy_name,
physical_pb_graph_node->input_pins[iport][ipin],
block_physical_pb);
}
}
/* Disable unused output pins */
for (int iport = 0; iport < physical_pb_graph_node->num_output_ports; ++iport) {
for (int ipin = 0; ipin < physical_pb_graph_node->num_output_pins[iport]; ++ipin) {
disable_pb_graph_node_unused_pin(fp, module_manager, parent_module,
hierarchy_name,
physical_pb_graph_node->output_pins[iport][ipin],
block_physical_pb);
}
}
/* Disable unused clock pins */
for (int iport = 0; iport < physical_pb_graph_node->num_clock_ports; ++iport) {
for (int ipin = 0; ipin < physical_pb_graph_node->num_clock_pins[iport]; ++ipin) {
disable_pb_graph_node_unused_pin(fp, module_manager, parent_module,
hierarchy_name,
physical_pb_graph_node->clock_pins[iport][ipin],
block_physical_pb);
}
}
}
/********************************************************************
* Disable unused inputs of routing multiplexers of this pb_graph_node
* This function will first cache the nets for each input and output pins
* and store the results in a mux_name-to-net mapping
*******************************************************************/
static
void disable_pb_graph_node_unused_mux_inputs(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& parent_module,
const std::string& hierarchy_name,
t_pb_graph_node* physical_pb_graph_node,
t_phy_pb* block_physical_pb,
const e_side& border_side) {
t_pb_type* physical_pb_type = physical_pb_graph_node->pb_type;
int physical_mode_index = find_pb_type_physical_mode_index(*physical_pb_type);
std::map<std::string, int> mux_instance_to_net_map;
/* Cache the nets for each input pins of each child pb_graph_node */
for (int ichild = 0; ichild < physical_pb_type->modes[physical_mode_index].num_pb_type_children; ++ichild) {
for (int inst = 0; inst < physical_pb_type->modes[physical_mode_index].pb_type_children[ichild].num_pb; ++inst) {
t_pb_graph_node* child_pb_graph_node = &(physical_pb_graph_node->child_pb_graph_nodes[physical_mode_index][ichild][inst]);
/* Cache the nets for input pins of the child pb_graph_node */
for (int iport = 0; iport < child_pb_graph_node->num_input_ports; ++iport) {
for (int ipin = 0; ipin < child_pb_graph_node->num_input_pins[iport]; ++ipin) {
int rr_node_index = child_pb_graph_node->input_pins[iport][ipin].rr_node_index_physical_pb;
/* Generate the mux name */
std::string mux_instance_name = generate_pb_mux_instance_name(GRID_MUX_INSTANCE_PREFIX, &(child_pb_graph_node->input_pins[iport][ipin]), std::string(""));
/* Cache the net */
mux_instance_to_net_map[mux_instance_name] = block_physical_pb->rr_graph->rr_node[rr_node_index].vpack_net_num;
}
}
/* Cache the nets for clock pins of the child pb_graph_node */
for (int iport = 0; iport < child_pb_graph_node->num_clock_ports; ++iport) {
for (int ipin = 0; ipin < child_pb_graph_node->num_clock_pins[iport]; ++ipin) {
int rr_node_index = child_pb_graph_node->clock_pins[iport][ipin].rr_node_index_physical_pb;
/* Generate the mux name */
std::string mux_instance_name = generate_pb_mux_instance_name(GRID_MUX_INSTANCE_PREFIX, &(child_pb_graph_node->clock_pins[iport][ipin]), std::string(""));
/* Cache the net */
mux_instance_to_net_map[mux_instance_name] = block_physical_pb->rr_graph->rr_node[rr_node_index].vpack_net_num;
}
}
}
}
/* Cache the nets for each output pins of this pb_graph_node */
for (int iport = 0; iport < physical_pb_graph_node->num_output_ports; ++iport) {
for (int ipin = 0; ipin < physical_pb_graph_node->num_output_pins[iport]; ++ipin) {
int rr_node_index = physical_pb_graph_node->output_pins[iport][ipin].rr_node_index_physical_pb;
/* Generate the mux name */
std::string mux_instance_name = generate_pb_mux_instance_name(GRID_MUX_INSTANCE_PREFIX, &(physical_pb_graph_node->output_pins[iport][ipin]), std::string(""));
/* Cache the net */
mux_instance_to_net_map[mux_instance_name] = block_physical_pb->rr_graph->rr_node[rr_node_index].vpack_net_num;
}
}
/* Now disable unused inputs of routing multiplexers, by tracing from input pins of the parent_module */
for (int iport = 0; iport < physical_pb_graph_node->num_input_ports; ++iport) {
for (int ipin = 0; ipin < physical_pb_graph_node->num_input_pins[iport]; ++ipin) {
/* Find the module port by name */
std::string module_port_name = generate_pb_type_port_name(physical_pb_graph_node->input_pins[iport][ipin].port);
ModulePortId module_port = module_manager.find_module_port(parent_module, module_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(parent_module, module_port));
int rr_node_index = physical_pb_graph_node->input_pins[iport][ipin].rr_node_index_physical_pb;
t_rr_node* input_rr_node = &(block_physical_pb->rr_graph->rr_node[rr_node_index]);
disable_analysis_module_input_pin_net_sinks(fp, module_manager, parent_module,
hierarchy_name,
module_port, ipin,
input_rr_node,
mux_instance_to_net_map);
}
}
for (int iport = 0; iport < physical_pb_graph_node->num_clock_ports; ++iport) {
for (int ipin = 0; ipin < physical_pb_graph_node->num_clock_pins[iport]; ++ipin) {
/* Find the module port by name */
std::string module_port_name = generate_pb_type_port_name(physical_pb_graph_node->clock_pins[iport][ipin].port);
ModulePortId module_port = module_manager.find_module_port(parent_module, module_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(parent_module, module_port));
int rr_node_index = physical_pb_graph_node->clock_pins[iport][ipin].rr_node_index_physical_pb;
t_rr_node* input_rr_node = &(block_physical_pb->rr_graph->rr_node[rr_node_index]);
disable_analysis_module_input_pin_net_sinks(fp, module_manager, parent_module,
hierarchy_name,
module_port, ipin,
input_rr_node,
mux_instance_to_net_map);
}
}
/* Now disable unused inputs of routing multiplexers, by tracing from output pins of the child_module */
for (int ichild = 0; ichild < physical_pb_type->modes[physical_mode_index].num_pb_type_children; ++ichild) {
/* Generate the name of the Verilog module for this child */
std::string child_module_name_prefix = generate_grid_block_prefix(std::string(GRID_MODULE_NAME_PREFIX), border_side);
std::string child_module_name = generate_physical_block_module_name(child_module_name_prefix, &(physical_pb_type->modes[physical_mode_index].pb_type_children[ichild]));
ModuleId child_module = module_manager.find_module(child_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(child_module));
for (int inst = 0; inst < physical_pb_type->modes[physical_mode_index].pb_type_children[ichild].num_pb; ++inst) {
t_pb_graph_node* child_pb_graph_node = &(physical_pb_graph_node->child_pb_graph_nodes[physical_mode_index][ichild][inst]);
for (int iport = 0; iport < child_pb_graph_node->num_output_ports; ++iport) {
for (int ipin = 0; ipin < child_pb_graph_node->num_output_pins[iport]; ++ipin) {
/* Find the module port by name */
std::string module_port_name = generate_pb_type_port_name(child_pb_graph_node->output_pins[iport][ipin].port);
ModulePortId module_port = module_manager.find_module_port(child_module, module_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(child_module, module_port));
int rr_node_index = child_pb_graph_node->output_pins[iport][ipin].rr_node_index_physical_pb;
t_rr_node* output_rr_node = &(block_physical_pb->rr_graph->rr_node[rr_node_index]);
/* Corner case: if the rr node has no fan-out we will skip this pin */
if (0 == output_rr_node->num_edges) {
continue;
}
disable_analysis_module_output_pin_net_sinks(fp, module_manager, parent_module,
hierarchy_name,
child_module, inst,
module_port, ipin,
output_rr_node,
mux_instance_to_net_map);
}
}
}
}
}
/********************************************************************
* Recursively visit all the pb_types in the hierarchy
* and disable all the unused resources, including:
* 1. input ports
* 2. output ports
* 3. unused inputs of routing multiplexers
*
* As this function is executed in a recursive way.
* To avoid repeated disable timing for ports, during each run of this function,
* only the unused input ports, output ports of the parent module will be disabled.
* In addition, we will cache all the net ids mapped to the input ports of
* child modules, and the net ids mapped to the output ports of parent module.
* As such, we can trace from
* 1. the input ports of parent module to disable unused inputs of routing multiplexer
* which drives the inputs of child modules
*
* Parent_module
* +---------------------------------------------
* | MUX child_module
* | +-------------+ +--------
* input_pin0(netA) --->|-------->| Routing |------>|
* input_pin1(netB) --->|----x--->| Multiplexer | netA |
* | +-------------+ |
* | |
*
* 2. the output ports of child module to disable unused inputs of routing multiplexer
* which drives the outputs of parent modules
*
* Case 1:
* parent_module
* --------------------------------------+
* child_module |
* -------------+ |
* | +-------------+ |
* output_pin0 (netA) |--->| Routing |----->|---->
* output_pin1 (netB) |-x->| Multiplexer | netA |
* | +-------------+ |
*
* Case 2:
*
* Parent_module
* +---------------------------------------------
* |
* | +--------------------------------------------+
* | | MUX child_module |
* | | +-------------+ +-----------+ |
* | +--->| Routing |------>| | |
* input_pin0(netA) --->|----x--->| Multiplexer | netA | output_pin|-----+
* | +-------------+ | | netA
* | | |
*
*
* Note: it is a must to disable all the ports in all the child pb_types!
* This can prohibit timing analyzer to consider any FF-to-FF path or
* combinatinal path inside an unused grid, when finding critical paths!!!
*******************************************************************/
static
void rec_print_analysis_sdc_disable_pb_graph_node_unused_resources(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& parent_module,
const std::string& hierarchy_name,
t_pb_graph_node* physical_pb_graph_node,
t_phy_pb* block_physical_pb,
const e_side& border_side) {
t_pb_type* physical_pb_type = physical_pb_graph_node->pb_type;
/* Disable unused input ports and output ports of this pb_graph_node (parent_module) */
disable_pb_graph_node_unused_pins(fp, module_manager, parent_module,
hierarchy_name, physical_pb_graph_node, block_physical_pb);
/* Return if this is the primitive pb_type
* Note: this must return before we disable any unused inputs of routing multiplexer!
* This is due to that primitive pb_type does NOT contain any routing multiplexers inside!!!
*/
if (TRUE == is_primitive_pb_type(physical_pb_type)) {
return;
}
/* Disable unused inputs of routing multiplexers of this pb_graph_node */
disable_pb_graph_node_unused_mux_inputs(fp, module_manager, parent_module,
hierarchy_name, physical_pb_graph_node, block_physical_pb,
border_side);
int physical_mode_index = find_pb_type_physical_mode_index(*physical_pb_type);
/* Disable all the ports by iterating over its instance in the parent module */
for (int ichild = 0; ichild < physical_pb_type->modes[physical_mode_index].num_pb_type_children; ++ichild) {
/* Generate the name of the Verilog module for this child */
std::string child_module_name_prefix = generate_grid_block_prefix(std::string(GRID_MODULE_NAME_PREFIX), border_side);
std::string child_module_name = generate_physical_block_module_name(child_module_name_prefix, &(physical_pb_type->modes[physical_mode_index].pb_type_children[ichild]));
ModuleId child_module = module_manager.find_module(child_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(child_module));
/* Each child may exist multiple times in the hierarchy*/
for (int inst = 0; inst < physical_pb_type->modes[physical_mode_index].pb_type_children[ichild].num_pb; ++inst) {
std::string child_instance_name = module_manager.instance_name(parent_module, child_module, module_manager.child_module_instances(parent_module, child_module)[inst]);
/* Must have a valid instance name!!! */
VTR_ASSERT(false == child_instance_name.empty());
std::string updated_hierarchy_name = hierarchy_name + std::string("/") + child_instance_name + std::string("/");
rec_print_analysis_sdc_disable_pb_graph_node_unused_resources(fp, module_manager, child_module, hierarchy_name,
&(physical_pb_graph_node->child_pb_graph_nodes[physical_mode_index][ichild][inst]),
block_physical_pb, border_side);
}
}
}
/********************************************************************
* This function can work in two differnt modes:
* 1. For partially unused pb blocks
* ---------------------------------
* Disable the timing for only unused resources in a physical block
* We have to walk through pb_graph node, port by port and pin by pin.
* Identify which pins have not been used, and then disable the timing
* for these ports.
* Plus, for input ports, we will trace the routing multiplexers
* and disable the timing for unused inputs.
*
* 2. For fully unused pb_blocks
* -----------------------------
* Disable the timing for a fully unused grid!
* This is very straightforward!
* Just walk through each pb_type and disable all the ports using wildcards
*******************************************************************/
static
void print_analysis_sdc_disable_pb_block_unused_resources(std::fstream& fp,
t_type_ptr grid_type,
const vtr::Point<size_t>& grid_coordinate,
const ModuleManager& module_manager,
const std::string& grid_instance_name,
const size_t& grid_z,
const e_side& border_side,
t_phy_pb* block_physical_pb,
const bool& unused_block) {
/* Check code: if this is an IO block, the border side MUST be valid */
if (IO_TYPE == grid_type) {
VTR_ASSERT(NUM_SIDES != border_side);
}
/* If the block is partially unused, we should have a physical pb */
if (false == unused_block) {
VTR_ASSERT(NULL != block_physical_pb);
}
/* Find an unique name to the pb instance in this grid
* Note: this must be consistent with the instance name we used in build_grid_module()!!!
*/
/* TODO: validate that the instance name is used in module manager!!! */
std::string pb_module_name_prefix(GRID_MODULE_NAME_PREFIX);
std::string pb_module_name = generate_grid_physical_block_module_name(pb_module_name_prefix, grid_type->pb_graph_head->pb_type, border_side);
std::string pb_instance_name = generate_grid_physical_block_instance_name(pb_module_name_prefix, grid_type->pb_graph_head->pb_type, border_side, grid_z);
ModuleId pb_module = module_manager.find_module(pb_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(pb_module));
/* Print comments */
fp << "#######################################" << std::endl;
if (true == unused_block) {
fp << "# Disable Timing for unused grid[" << grid_coordinate.x() << "][" << grid_coordinate.y() << "][" << grid_z << "]" << std::endl;
} else {
VTR_ASSERT_SAFE(false == unused_block);
fp << "# Disable Timing for unused resources in grid[" << grid_coordinate.x() << "][" << grid_coordinate.y() << "][" << grid_z << "]" << std::endl;
}
fp << "#######################################" << std::endl;
std::string hierarchy_name = grid_instance_name + std::string("/") + pb_instance_name + std::string("/");
/* Go recursively through the pb_graph hierarchy, and disable all the ports level by level */
if (true == unused_block) {
rec_print_analysis_sdc_disable_unused_pb_graph_nodes(fp, module_manager, pb_module, hierarchy_name, grid_type->pb_graph_head, border_side);
} else {
VTR_ASSERT_SAFE(false == unused_block);
rec_print_analysis_sdc_disable_pb_graph_node_unused_resources(fp, module_manager, pb_module, hierarchy_name, grid_type->pb_graph_head, block_physical_pb, border_side);
}
}
/********************************************************************
* Disable the timing for a fully unused grid!
* This is very straightforward!
* Just walk through each pb_type and disable all the ports using wildcards
*******************************************************************/
static
void print_analysis_sdc_disable_unused_grid(std::fstream& fp,
const vtr::Point<size_t>& grid_coordinate,
const std::vector<std::vector<t_grid_tile>>& L_grids,
const std::vector<t_block>& L_blocks,
const ModuleManager& module_manager,
const e_side& border_side) {
/* Validate file stream */
check_file_handler(fp);
t_type_ptr grid_type = L_grids[grid_coordinate.x()][grid_coordinate.y()].type;
/* Bypass conditions for grids :
* 1. EMPTY type, which is by nature unused
* 2. Offset > 0, which has already been processed when offset = 0
*/
if ( (NULL == grid_type)
|| (EMPTY_TYPE == grid_type)
|| (0 < L_grids[grid_coordinate.x()][grid_coordinate.y()].offset) ) {
return;
}
/* Find an unique name to the grid instane
* Note: this must be consistent with the instance name we used in build_top_module()!!!
*/
/* TODO: validate that the instance name is used in module manager!!! */
std::string grid_module_name_prefix(GRID_MODULE_NAME_PREFIX);
std::string grid_module_name = generate_grid_block_module_name(grid_module_name_prefix, std::string(grid_type->name), IO_TYPE == grid_type, border_side);
std::string grid_instance_name = generate_grid_block_instance_name(grid_module_name_prefix, std::string(grid_type->name), IO_TYPE == grid_type, border_side, grid_coordinate);
ModuleId grid_module = module_manager.find_module(grid_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(grid_module));
/* Now we need to find the usage of this grid */
std::vector<bool> grid_usage(grid_type->capacity, false);
/* Print comments */
fp << "#######################################" << std::endl;
fp << "# Disable Timing for grid[" << grid_coordinate.x() << "][" << grid_coordinate.y() << "]" << std::endl;
fp << "#######################################" << std::endl;
/* For used grid, find the unused rr_node in the local rr_graph
* and then disable each port which is not used
* as well as the unused inputs of routing multiplexers!
*/
for (int iblk = 0; iblk < L_grids[grid_coordinate.x()][grid_coordinate.y()].usage; ++iblk) {
int blk_id = L_grids[grid_coordinate.x()][grid_coordinate.y()].blocks[iblk];
VTR_ASSERT( (OPEN < L_blocks[blk_id].z) && (L_blocks[blk_id].z < grid_type->capacity) );
/* Mark the grid_usage */
grid_usage[L_blocks[blk_id].z] = true;
/* TODO:
verilog_generate_sdc_disable_one_unused_block(fp, &(L_blocks[blk_id]));
*/
t_phy_pb* block_phy_pb = (t_phy_pb*) L_blocks[blk_id].phy_pb;
print_analysis_sdc_disable_pb_block_unused_resources(fp, grid_type, grid_coordinate, module_manager, grid_instance_name, iblk, border_side, block_phy_pb, false);
}
/* For unused grid, disable all the pins in the physical_pb_type */
for (int iblk = 0; iblk < grid_type->capacity; ++iblk) {
/* Bypass used blocks */
if (true == grid_usage[iblk]) {
continue;
}
print_analysis_sdc_disable_pb_block_unused_resources(fp, grid_type, grid_coordinate, module_manager, grid_instance_name, iblk, border_side, NULL, true);
}
}
/********************************************************************
* Top-level function writes SDC commands to disable unused ports
* of grids, such as Configurable Logic Block (CLBs), heterogeneous blocks, etc.
*
* This function will iterate over all the grids available in the FPGA fabric
* It will disable the timing analysis for
* 1. Grids, which are totally not used (no logic has been mapped to)
* 2. Unused part of grids, including the ports, inputs of routing multiplexers
*
* Note that it is a must to disable the unused inputs of routing multiplexers
* because it will cause unexpected paths in timing analysis
* For example:
* +---------------------+
* inputA (net0) ------->| |
* | Routing multiplexer |----> output (net0)
* inputB (net1) ------->| |
* +---------------------+
*
* During timing analysis, the path from inputA to output should be considered
* while the path from inputB to output should NOT be considered!!!
*
*******************************************************************/
void print_analysis_sdc_disable_unused_grids(std::fstream& fp,
const vtr::Point<size_t>& device_size,
const std::vector<std::vector<t_grid_tile>>& L_grids,
const std::vector<t_block>& L_blocks,
const ModuleManager& module_manager) {
/* Process unused core grids */
for (size_t ix = 1; ix < device_size.x() - 1; ++ix) {
for (size_t iy = 1; iy < device_size.y() - 1; ++iy) {
/* We should not meet any I/O grid */
VTR_ASSERT(IO_TYPE != L_grids[ix][iy].type);
print_analysis_sdc_disable_unused_grid(fp, vtr::Point<size_t>(ix, iy),
L_grids, L_blocks, module_manager, NUM_SIDES);
}
}
/* Instanciate I/O grids */
/* Create the coordinate range for each side of FPGA fabric */
std::vector<e_side> io_sides{TOP, RIGHT, BOTTOM, LEFT};
std::map<e_side, std::vector<vtr::Point<size_t>>> io_coordinates;
/* TOP side*/
for (size_t ix = 1; ix < device_size.x() - 1; ++ix) {
io_coordinates[TOP].push_back(vtr::Point<size_t>(ix, device_size.y() - 1));
}
/* RIGHT side */
for (size_t iy = 1; iy < device_size.y() - 1; ++iy) {
io_coordinates[RIGHT].push_back(vtr::Point<size_t>(device_size.x() - 1, iy));
}
/* BOTTOM side*/
for (size_t ix = 1; ix < device_size.x() - 1; ++ix) {
io_coordinates[BOTTOM].push_back(vtr::Point<size_t>(ix, 0));
}
/* LEFT side */
for (size_t iy = 1; iy < device_size.y() - 1; ++iy) {
io_coordinates[LEFT].push_back(vtr::Point<size_t>(0, iy));
}
/* Add instances of I/O grids to top_module */
for (const e_side& io_side : io_sides) {
for (const vtr::Point<size_t>& io_coordinate : io_coordinates[io_side]) {
/* We should not meet any I/O grid */
VTR_ASSERT(IO_TYPE == L_grids[io_coordinate.x()][io_coordinate.y()].type);
print_analysis_sdc_disable_unused_grid(fp, io_coordinate,
L_grids, L_blocks, module_manager, io_side);
}
}
}

View File

@ -0,0 +1,16 @@
#ifndef ANALYSIS_SDC_GRID_WRITER_H
#define ANALYSIS_SDC_GRID_WRITER_H
#include <fstream>
#include <vector>
#include "vtr_geometry.h"
#include "vpr_types.h"
#include "module_manager.h"
void print_analysis_sdc_disable_unused_grids(std::fstream& fp,
const vtr::Point<size_t>& device_size,
const std::vector<std::vector<t_grid_tile>>& L_grids,
const std::vector<t_block>& L_blocks,
const ModuleManager& module_manager);
#endif

View File

@ -0,0 +1,549 @@
/********************************************************************
* This file includes functions that are used to output a SDC file
* that constrain routing modules of a FPGA fabric (P&Red netlist)
* using a benchmark
*******************************************************************/
#include <map>
#include "vtr_assert.h"
#include "device_port.h"
#include "fpga_x2p_reserved_words.h"
#include "fpga_x2p_naming.h"
#include "fpga_x2p_utils.h"
#include "fpga_x2p_types.h"
#include "sdc_writer_utils.h"
#include "analysis_sdc_writer_utils.h"
#include "analysis_sdc_routing_writer.h"
#include "globals.h"
/********************************************************************
* This function will disable
* 1. all the unused port (unmapped by a benchmark) of a connection block
* 2. all the unused inputs (unmapped by a benchmark) of routing multiplexers
* in a connection block
*******************************************************************/
static
void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp,
const std::vector<std::vector<t_grid_tile>>& grids,
const ModuleManager& module_manager,
const DeviceRRGSB& L_device_rr_gsb,
const RRGSB& rr_gsb,
const t_rr_type& cb_type,
const bool& compact_routing_hierarchy) {
/* Validate file stream */
check_file_handler(fp);
vtr::Point<size_t> gsb_coordinate(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
std::string cb_instance_name = generate_connection_block_module_name(cb_type, gsb_coordinate);
/* If we use the compact routing hierarchy, we need to find the module name !*/
vtr::Point<size_t> cb_coordinate(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
if (true == compact_routing_hierarchy) {
DeviceCoordinator cb_coord(rr_gsb.get_x(), rr_gsb.get_y());
/* Note: use GSB coordinate when inquire for unique modules!!! */
const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, cb_coord);
cb_coordinate.set_x(unique_mirror.get_cb_x(cb_type));
cb_coordinate.set_y(unique_mirror.get_cb_y(cb_type));
}
std::string cb_module_name = generate_connection_block_module_name(cb_type, cb_coordinate);
ModuleId cb_module = module_manager.find_module(cb_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(cb_module));
/* Print comments */
fp << "##################################################" << std::endl;
fp << "# Disable timing for Connection block " << cb_module_name << std::endl;
fp << "##################################################" << std::endl;
/* Disable all the input port (routing tracks), which are not used by benchmark */
for (size_t itrack = 0; itrack < rr_gsb.get_cb_chan_width(cb_type); ++itrack) {
t_rr_node* chan_node = rr_gsb.get_chan_node(rr_gsb.get_cb_chan_side(cb_type), itrack);
/* Check if this node is used by benchmark */
if (false == is_rr_node_to_be_disable_for_analysis(chan_node)) {
continue;
}
/* Disable both input of the routing track if it is not used! */
vtr::Point<size_t> port_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
if (true == compact_routing_hierarchy) {
/* Note: use GSB coordinate when inquire for unique modules!!! */
DeviceCoordinator cb_coord(rr_gsb.get_x(), rr_gsb.get_y());
const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, cb_coord);
port_coord.set_x(unique_mirror.get_cb_x(cb_type));
port_coord.set_y(unique_mirror.get_cb_y(cb_type));
}
std::string port_name = generate_routing_track_port_name(cb_type,
port_coord, itrack,
IN_PORT);
/* Ensure we have this port in the module! */
ModulePortId module_port = module_manager.find_module_port(cb_module, port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, module_port));
fp << "set_disable_timing ";
fp << cb_instance_name << "/";
fp << generate_sdc_port(module_manager.module_port(cb_module, module_port));
fp << std::endl;
}
/* Disable all the output port (routing tracks), which are not used by benchmark */
for (size_t itrack = 0; itrack < rr_gsb.get_cb_chan_width(cb_type); ++itrack) {
t_rr_node* chan_node = rr_gsb.get_chan_node(rr_gsb.get_cb_chan_side(cb_type), itrack);
/* Check if this node is used by benchmark */
if (false == is_rr_node_to_be_disable_for_analysis(chan_node)) {
continue;
}
/* Disable both input of the routing track if it is not used! */
vtr::Point<size_t> port_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
if (true == compact_routing_hierarchy) {
/* Note: use GSB coordinate when inquire for unique modules!!! */
DeviceCoordinator cb_coord(rr_gsb.get_x(), rr_gsb.get_y());
const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, cb_coord);
port_coord.set_x(unique_mirror.get_cb_x(cb_type));
port_coord.set_y(unique_mirror.get_cb_y(cb_type));
}
std::string port_name = generate_routing_track_port_name(cb_type,
port_coord, itrack,
OUT_PORT);
/* Ensure we have this port in the module! */
ModulePortId module_port = module_manager.find_module_port(cb_module, port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, module_port));
fp << "set_disable_timing ";
fp << cb_instance_name << "/";
fp << generate_sdc_port(module_manager.module_port(cb_module, module_port));
fp << std::endl;
}
/* Build a map between mux_instance name and net_num */
std::map<std::string, int> mux_instance_to_net_map;
/* Disable all the output port (grid input pins), which are not used by benchmark */
std::vector<enum e_side> cb_sides = rr_gsb.get_cb_ipin_sides(cb_type);
for (size_t side = 0; side < cb_sides.size(); ++side) {
enum e_side cb_ipin_side = cb_sides[side];
for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(cb_ipin_side); ++inode) {
t_rr_node* ipin_node = rr_gsb.get_ipin_node(cb_ipin_side, inode);
/* Find the MUX instance that drives the IPIN! */
std::string mux_instance_name = generate_cb_mux_instance_name(CONNECTION_BLOCK_MUX_INSTANCE_PREFIX, rr_gsb.get_ipin_node_grid_side(cb_ipin_side, inode), inode, std::string(""));
mux_instance_to_net_map[mux_instance_name] = ipin_node->vpack_net_num;
if (false == is_rr_node_to_be_disable_for_analysis(ipin_node)) {
continue;
}
if (0 == ipin_node->fan_in) {
continue;
}
vtr::Point<size_t> port_coord(ipin_node->xlow, ipin_node->ylow);
std::string port_name = generate_grid_side_port_name(grids,
port_coord,
rr_gsb.get_ipin_node_grid_side(cb_ipin_side, inode),
ipin_node->ptc_num);
/* Find the port in unique mirror! */
if (true == compact_routing_hierarchy) {
/* Note: use GSB coordinate when inquire for unique modules!!! */
DeviceCoordinator cb_coord(rr_gsb.get_x(), rr_gsb.get_y());
const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, cb_coord);
t_rr_node* unique_mirror_ipin_node = unique_mirror.get_ipin_node(cb_ipin_side, inode);
port_coord.set_x(unique_mirror_ipin_node->xlow);
port_coord.set_y(unique_mirror_ipin_node->ylow);
port_name = generate_grid_side_port_name(grids,
port_coord,
unique_mirror.get_ipin_node_grid_side(cb_ipin_side, inode),
unique_mirror_ipin_node->ptc_num);
}
/* Ensure we have this port in the module! */
ModulePortId module_port = module_manager.find_module_port(cb_module, port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, module_port));
fp << "set_disable_timing ";
fp << cb_instance_name << "/";
fp << generate_sdc_port(module_manager.module_port(cb_module, module_port));
fp << std::endl;
}
}
/* Disable all the unused inputs of routing multiplexers, which are not used by benchmark
* Here, we start from each input of the Connection Blocks, and traverse forward to the sink
* port of the module net whose source is the input
* We will find the instance name which is the parent of the sink port, and search the
* net id through the instance_name_to_net_map
* The the net id does not match the net id of this input, we will disable the sink port!
*
* cb_module
* +-----------------------
* | MUX instance A
* | +-----------
* input_port--->|--+---x-->| sink port (disable!)
* | | +----------
* | | MUX instance B
* | | +----------
* | +------>| sink port (do not disable!)
*/
for (size_t itrack = 0; itrack < rr_gsb.get_cb_chan_width(cb_type); ++itrack) {
t_rr_node* chan_node = rr_gsb.get_chan_node(rr_gsb.get_cb_chan_side(cb_type), itrack);
/* Disable both input of the routing track if it is not used! */
vtr::Point<size_t> port_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
if (true == compact_routing_hierarchy) {
/* Note: use GSB coordinate when inquire for unique modules!!! */
DeviceCoordinator cb_coord(rr_gsb.get_x(), rr_gsb.get_y());
const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, cb_coord);
port_coord.set_x(unique_mirror.get_cb_x(cb_type));
port_coord.set_y(unique_mirror.get_cb_y(cb_type));
}
std::string port_name = generate_routing_track_port_name(cb_type,
port_coord, itrack,
OUT_PORT);
/* Ensure we have this port in the module! */
ModulePortId module_port = module_manager.find_module_port(cb_module, port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, module_port));
disable_analysis_module_input_port_net_sinks(fp,
module_manager, cb_module,
cb_instance_name,
module_port,
chan_node,
mux_instance_to_net_map);
}
}
/********************************************************************
* Iterate over all the connection blocks in a device
* and disable unused ports for each of them
*******************************************************************/
static
void print_analysis_sdc_disable_unused_cb_ports(std::fstream& fp,
const std::vector<std::vector<t_grid_tile>>& grids,
const ModuleManager& module_manager,
const DeviceRRGSB& L_device_rr_gsb,
const t_rr_type& cb_type,
const bool& compact_routing_hierarchy) {
/* Build unique X-direction connection block modules */
DeviceCoordinator cb_range = L_device_rr_gsb.get_gsb_range();
for (size_t ix = 0; ix < cb_range.get_x(); ++ix) {
for (size_t iy = 0; iy < cb_range.get_y(); ++iy) {
/* Check if the connection block exists in the device!
* Some of them do NOT exist due to heterogeneous blocks (height > 1)
* We will skip those modules
*/
const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy);
if (false == rr_gsb.is_cb_exist(cb_type)) {
continue;
}
print_analysis_sdc_disable_cb_unused_resources(fp, grids,
module_manager,
L_device_rr_gsb,
rr_gsb,
cb_type,
compact_routing_hierarchy);
}
}
}
/********************************************************************
* Iterate over all the connection blocks in a device
* and disable unused ports for each of them
*******************************************************************/
void print_analysis_sdc_disable_unused_cbs(std::fstream& fp,
const std::vector<std::vector<t_grid_tile>>& grids,
const ModuleManager& module_manager,
const DeviceRRGSB& L_device_rr_gsb,
const bool& compact_routing_hierarchy) {
print_analysis_sdc_disable_unused_cb_ports(fp, grids, module_manager,
L_device_rr_gsb,
CHANX, compact_routing_hierarchy);
print_analysis_sdc_disable_unused_cb_ports(fp, grids, module_manager,
L_device_rr_gsb,
CHANY, compact_routing_hierarchy);
}
/********************************************************************
* This function will disable
* 1. all the unused port (unmapped by a benchmark) of a switch block
* 2. all the unused inputs (unmapped by a benchmark) of routing multiplexers
* in a switch block
*******************************************************************/
static
void print_analysis_sdc_disable_sb_unused_resources(std::fstream& fp,
const std::vector<std::vector<t_grid_tile>>& grids,
const ModuleManager& module_manager,
const DeviceRRGSB& L_device_rr_gsb,
const RRGSB& rr_gsb,
const bool& compact_routing_hierarchy) {
/* Validate file stream */
check_file_handler(fp);
vtr::Point<size_t> gsb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
std::string sb_instance_name = generate_switch_block_module_name(gsb_coordinate);
/* If we use the compact routing hierarchy, we need to find the module name !*/
vtr::Point<size_t> sb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
if (true == compact_routing_hierarchy) {
DeviceCoordinator sb_coord(rr_gsb.get_x(), rr_gsb.get_y());
/* Note: use GSB coordinate when inquire for unique modules!!! */
const RRGSB& unique_mirror = L_device_rr_gsb.get_sb_unique_module(sb_coord);
sb_coordinate.set_x(unique_mirror.get_sb_x());
sb_coordinate.set_y(unique_mirror.get_sb_y());
}
std::string sb_module_name = generate_switch_block_module_name(sb_coordinate);
ModuleId sb_module = module_manager.find_module(sb_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(sb_module));
/* Print comments */
fp << "##################################################" << std::endl;
fp << "# Disable timing for Switch block " << sb_module_name << std::endl;
fp << "##################################################" << std::endl;
/* Build a map between mux_instance name and net_num */
std::map<std::string, int> mux_instance_to_net_map;
/* Disable all the input/output port (routing tracks), which are not used by benchmark */
for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) {
Side side_manager(side);
DeviceCoordinator port_coordinate = rr_gsb.get_side_block_coordinator(side_manager.get_side());
for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) {
t_rr_node* chan_node = rr_gsb.get_chan_node(side_manager.get_side(), itrack);
vtr::Point<size_t> port_coord(port_coordinate.get_x(), port_coordinate.get_y());
std::string port_name = generate_routing_track_port_name(rr_gsb.get_chan_node(side_manager.get_side(), itrack)->type,
port_coord, itrack,
rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack));
if (true == compact_routing_hierarchy) {
/* Note: use GSB coordinate when inquire for unique modules!!! */
DeviceCoordinator sb_coord(rr_gsb.get_x(), rr_gsb.get_y());
const RRGSB& unique_mirror = L_device_rr_gsb.get_sb_unique_module(sb_coord);
DeviceCoordinator unique_port_coordinate = unique_mirror.get_side_block_coordinator(side_manager.get_side());
port_coord.set_x(unique_port_coordinate.get_x());
port_coord.set_y(unique_port_coordinate.get_y());
port_name = generate_routing_track_port_name(unique_mirror.get_chan_node(side_manager.get_side(), itrack)->type,
port_coord, itrack,
unique_mirror.get_chan_node_direction(side_manager.get_side(), itrack));
}
/* Ensure we have this port in the module! */
ModulePortId module_port = module_manager.find_module_port(sb_module, port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, module_port));
/* Cache the net name for routing tracks which are outputs of the switch block */
if (OUT_PORT == rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) {
/* Generate the name of mux instance related to this output node */
std::string mux_instance_name = generate_sb_memory_instance_name(SWITCH_BLOCK_MUX_INSTANCE_PREFIX, side_manager.get_side(), itrack, std::string(""));
mux_instance_to_net_map[mux_instance_name] = chan_node->vpack_net_num;
}
/* Check if this node is used by benchmark */
if (false == is_rr_node_to_be_disable_for_analysis(chan_node)) {
continue;
}
fp << "set_disable_timing ";
fp << sb_instance_name << "/";
fp << generate_sdc_port(module_manager.module_port(sb_module, module_port));
fp << std::endl;
}
}
/* Disable all the input port (grid output pins), which are not used by benchmark */
for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) {
Side side_manager(side);
for (size_t inode = 0; inode < rr_gsb.get_num_opin_nodes(side_manager.get_side()); ++inode) {
t_rr_node* opin_node = rr_gsb.get_opin_node(side_manager.get_side(), inode);
vtr::Point<size_t> port_coord(rr_gsb.get_opin_node(side_manager.get_side(), inode)->xlow,
rr_gsb.get_opin_node(side_manager.get_side(), inode)->ylow);
std::string port_name = generate_grid_side_port_name(grids, port_coord,
rr_gsb.get_opin_node_grid_side(side_manager.get_side(), inode),
opin_node->ptc_num);
if (true == compact_routing_hierarchy) {
/* Note: use GSB coordinate when inquire for unique modules!!! */
DeviceCoordinator sb_coord(rr_gsb.get_x(), rr_gsb.get_y());
const RRGSB& unique_mirror = L_device_rr_gsb.get_sb_unique_module(sb_coord);
port_coord.set_x(unique_mirror.get_opin_node(side_manager.get_side(), inode)->xlow);
port_coord.set_y(unique_mirror.get_opin_node(side_manager.get_side(), inode)->ylow);
port_name = generate_grid_side_port_name(grids, port_coord,
unique_mirror.get_opin_node_grid_side(side_manager.get_side(), inode),
unique_mirror.get_opin_node(side_manager.get_side(), inode)->ptc_num);
}
/* Ensure we have this port in the module! */
ModulePortId module_port = module_manager.find_module_port(sb_module, port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, module_port));
/* Check if this node is used by benchmark */
if (false == is_rr_node_to_be_disable_for_analysis(opin_node)) {
continue;
}
fp << "set_disable_timing ";
fp << sb_instance_name << "/";
fp << generate_sdc_port(module_manager.module_port(sb_module, module_port));
fp << std::endl;
}
}
/* Disable all the unused inputs of routing multiplexers, which are not used by benchmark
* Here, we start from each input of the Switch Blocks, and traverse forward to the sink
* port of the module net whose source is the input
* We will find the instance name which is the parent of the sink port, and search the
* net id through the instance_name_to_net_map
* The the net id does not match the net id of this input, we will disable the sink port!
*
* sb_module
* +-----------------------
* | MUX instance A
* | +-----------
* input_port--->|--+---x-->| sink port (disable! net_id = Y)
* (net_id = X) | | +----------
* | | MUX instance B
* | | +----------
* | +------>| sink port (do not disable! net_id = X)
*
* Because the input ports of a SB module come from
* 1. Grid output pins
* 2. routing tracks
* We will walk through these ports and do conditionally disable_timing
*/
/* Iterate over input ports coming from grid output pins */
for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) {
Side side_manager(side);
for (size_t inode = 0; inode < rr_gsb.get_num_opin_nodes(side_manager.get_side()); ++inode) {
t_rr_node* opin_node = rr_gsb.get_opin_node(side_manager.get_side(), inode);
vtr::Point<size_t> port_coord(rr_gsb.get_opin_node(side_manager.get_side(), inode)->xlow,
rr_gsb.get_opin_node(side_manager.get_side(), inode)->ylow);
std::string port_name = generate_grid_side_port_name(grids, port_coord,
rr_gsb.get_opin_node_grid_side(side_manager.get_side(), inode),
opin_node->ptc_num);
if (true == compact_routing_hierarchy) {
/* Note: use GSB coordinate when inquire for unique modules!!! */
DeviceCoordinator sb_coord(rr_gsb.get_x(), rr_gsb.get_y());
const RRGSB& unique_mirror = L_device_rr_gsb.get_sb_unique_module(sb_coord);
port_coord.set_x(unique_mirror.get_opin_node(side_manager.get_side(), inode)->xlow);
port_coord.set_y(unique_mirror.get_opin_node(side_manager.get_side(), inode)->ylow);
port_name = generate_grid_side_port_name(grids, port_coord,
unique_mirror.get_opin_node_grid_side(side_manager.get_side(), inode),
unique_mirror.get_opin_node(side_manager.get_side(), inode)->ptc_num);
}
/* Ensure we have this port in the module! */
ModulePortId module_port = module_manager.find_module_port(sb_module, port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, module_port));
disable_analysis_module_input_port_net_sinks(fp, module_manager,
sb_module,
sb_instance_name,
module_port,
opin_node,
mux_instance_to_net_map);
}
}
/* Iterate over input ports coming from routing tracks */
for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) {
Side side_manager(side);
DeviceCoordinator port_coordinate = rr_gsb.get_side_block_coordinator(side_manager.get_side());
for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) {
/* Skip output ports, they have already been disabled or not */
if (OUT_PORT == rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) {
continue;
}
t_rr_node* chan_node = rr_gsb.get_chan_node(side_manager.get_side(), itrack);
vtr::Point<size_t> port_coord(port_coordinate.get_x(), port_coordinate.get_y());
std::string port_name = generate_routing_track_port_name(rr_gsb.get_chan_node(side_manager.get_side(), itrack)->type,
port_coord, itrack,
rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack));
if (true == compact_routing_hierarchy) {
/* Note: use GSB coordinate when inquire for unique modules!!! */
DeviceCoordinator sb_coord(rr_gsb.get_x(), rr_gsb.get_y());
const RRGSB& unique_mirror = L_device_rr_gsb.get_sb_unique_module(sb_coord);
DeviceCoordinator unique_port_coordinate = unique_mirror.get_side_block_coordinator(side_manager.get_side());
port_coord.set_x(unique_port_coordinate.get_x());
port_coord.set_y(unique_port_coordinate.get_y());
port_name = generate_routing_track_port_name(unique_mirror.get_chan_node(side_manager.get_side(), itrack)->type,
port_coord, itrack,
unique_mirror.get_chan_node_direction(side_manager.get_side(), itrack));
}
/* Ensure we have this port in the module! */
ModulePortId module_port = module_manager.find_module_port(sb_module, port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, module_port));
disable_analysis_module_input_port_net_sinks(fp, module_manager,
sb_module,
sb_instance_name,
module_port,
chan_node,
mux_instance_to_net_map);
}
}
}
/********************************************************************
* Iterate over all the connection blocks in a device
* and disable unused ports for each of them
*******************************************************************/
void print_analysis_sdc_disable_unused_sbs(std::fstream& fp,
const std::vector<std::vector<t_grid_tile>>& grids,
const ModuleManager& module_manager,
const DeviceRRGSB& L_device_rr_gsb,
const bool& compact_routing_hierarchy) {
/* Build unique X-direction connection block modules */
DeviceCoordinator sb_range = L_device_rr_gsb.get_gsb_range();
for (size_t ix = 0; ix < sb_range.get_x(); ++ix) {
for (size_t iy = 0; iy < sb_range.get_y(); ++iy) {
/* Check if the connection block exists in the device!
* Some of them do NOT exist due to heterogeneous blocks (height > 1)
* We will skip those modules
*/
const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy);
print_analysis_sdc_disable_sb_unused_resources(fp, grids,
module_manager,
L_device_rr_gsb,
rr_gsb,
compact_routing_hierarchy);
}
}
}

View File

@ -0,0 +1,22 @@
#ifndef ANALYSIS_SDC_ROUTING_WRITER_H
#define ANALYSIS_SDC_ROUTING_WRITER_H
#include <fstream>
#include <vector>
#include "module_manager.h"
#include "rr_blocks.h"
#include "vpr_types.h"
void print_analysis_sdc_disable_unused_cbs(std::fstream& fp,
const std::vector<std::vector<t_grid_tile>>& grids,
const ModuleManager& module_manager,
const DeviceRRGSB& L_device_rr_gsb,
const bool& compact_routing_hierarchy);
void print_analysis_sdc_disable_unused_sbs(std::fstream& fp,
const std::vector<std::vector<t_grid_tile>>& grids,
const ModuleManager& module_manager,
const DeviceRRGSB& L_device_rr_gsb,
const bool& compact_routing_hierarchy);
#endif

View File

@ -0,0 +1,271 @@
/********************************************************************
* This file includes functions that are used to output a SDC file
* that constrain a FPGA fabric (P&Red netlist) using a benchmark
*******************************************************************/
#include <ctime>
#include <fstream>
#include <iomanip>
#include "vtr_assert.h"
#include "device_port.h"
#include "util.h"
#include "mux_utils.h"
#include "fpga_x2p_naming.h"
#include "fpga_x2p_utils.h"
#include "fpga_x2p_benchmark_utils.h"
#include "sdc_writer_naming.h"
#include "sdc_writer_utils.h"
#include "sdc_memory_utils.h"
#include "analysis_sdc_grid_writer.h"
#include "analysis_sdc_routing_writer.h"
#include "analysis_sdc_writer.h"
/********************************************************************
* Generate SDC constaints for inputs and outputs
* We consider the top module in formal verification purpose here
* which is easier
*******************************************************************/
static
void print_analysis_sdc_io_delays(std::fstream& fp,
const std::vector<t_logical_block>& L_logical_blocks,
const vtr::Point<size_t>& device_size,
const std::vector<std::vector<t_grid_tile>>& L_grids,
const std::vector<t_block>& L_blocks,
const ModuleManager& module_manager,
const ModuleId& top_module,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const float& critical_path_delay) {
/* Validate the file stream */
check_file_handler(fp);
/* Print comments */
fp << "##################################################" << std::endl;
fp << "# Create clock " << std::endl;
fp << "##################################################" << std::endl;
/* Get clock port from the global port */
std::vector<BasicPort> operating_clock_ports;
for (const CircuitPortId& clock_port : global_ports) {
if (SPICE_MODEL_PORT_CLOCK != circuit_lib.port_type(clock_port)) {
continue;
}
/* We only constrain operating clock here! */
if (true == circuit_lib.port_is_prog(clock_port)) {
continue;
}
/* Find the module port and Update the operating port list */
ModulePortId module_port = module_manager.find_module_port(top_module, circuit_lib.port_prefix(clock_port));
operating_clock_ports.push_back(module_manager.module_port(top_module, module_port));
}
for (const BasicPort& operating_clock_port : operating_clock_ports) {
/* Reach here, it means a clock port and we need print constraints */
fp << "create_clock ";
fp << generate_sdc_port(operating_clock_port);
fp << " -period " << std::setprecision(10) << critical_path_delay;
fp << " -waveform {0 " << std::setprecision(10) << critical_path_delay / 2 << "}";
fp << std::endl;
/* Add an empty line as a splitter */
fp << std::endl;
}
/* There should be only one operating clock!
* TODO: this should be changed when developing multi-clock support!!!
*/
VTR_ASSERT(1 == operating_clock_ports.size());
/* In this function, we support only 1 type of I/Os */
VTR_ASSERT(1 == module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT).size());
BasicPort module_io_port = module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT)[0];
/* Keep tracking which I/Os have been used */
std::vector<bool> io_used(module_io_port.get_width(), false);
/* Print comments */
fp << "##################################################" << std::endl;
fp << "# Create input and output delays for used I/Os " << std::endl;
fp << "##################################################" << std::endl;
for (const t_logical_block& io_lb : L_logical_blocks) {
/* We only care I/O logical blocks !*/
if ( (VPACK_INPAD != io_lb.type) && (VPACK_OUTPAD != io_lb.type) ) {
continue;
}
/* clock net or constant generator should be disabled in timing analysis */
if (TRUE == io_lb.is_clock) {
continue;
}
/* Find the index of the mapped GPIO in top-level FPGA fabric */
size_t io_index = find_benchmark_io_index(io_lb, device_size, L_grids, L_blocks);
/* Ensure that IO index is in range */
BasicPort module_mapped_io_port = module_io_port;
/* Set the port pin index */
VTR_ASSERT(io_index < module_mapped_io_port.get_width());
module_mapped_io_port.set_width(io_index, io_index);
/* For input I/O, we set an input delay constraint correlated to the operating clock
* For output I/O, we set an output delay constraint correlated to the operating clock
*/
if (VPACK_INPAD == io_lb.type) {
print_sdc_set_port_input_delay(fp, module_mapped_io_port,
operating_clock_ports[0], critical_path_delay);
} else {
VTR_ASSERT(VPACK_OUTPAD == io_lb.type);
print_sdc_set_port_output_delay(fp, module_mapped_io_port,
operating_clock_ports[0], critical_path_delay);
}
/* Mark this I/O has been used/wired */
io_used[io_index] = true;
}
/* Add an empty line as a splitter */
fp << std::endl;
/* Print comments */
fp << "##################################################" << std::endl;
fp << "# Disable timing for unused I/Os " << std::endl;
fp << "##################################################" << std::endl;
/* Wire the unused iopads to a constant */
for (size_t io_index = 0; io_index < io_used.size(); ++io_index) {
/* Bypass used iopads */
if (true == io_used[io_index]) {
continue;
}
/* Wire to a contant */
BasicPort module_unused_io_port = module_io_port;
/* Set the port pin index */
module_unused_io_port.set_width(io_index, io_index);
print_sdc_disable_port_timing(fp, module_unused_io_port);
}
/* Add an empty line as a splitter */
fp << std::endl;
}
/********************************************************************
* Disable the timing for all the global port except the operating clock ports
*******************************************************************/
static
void print_analysis_sdc_disable_global_ports(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports) {
/* Validate file stream */
check_file_handler(fp);
/* Print comments */
fp << "##################################################" << std::endl;
fp << "# Disable timing for global ports " << std::endl;
fp << "##################################################" << std::endl;
for (const CircuitPortId& global_port : global_ports) {
/* Skip operating clock here! */
if ( (SPICE_MODEL_PORT_CLOCK == circuit_lib.port_type(global_port))
&& (false == circuit_lib.port_is_prog(global_port)) ) {
continue;
}
ModulePortId module_port = module_manager.find_module_port(top_module, circuit_lib.port_prefix(global_port));
BasicPort port_to_disable = module_manager.module_port(top_module, module_port);
print_sdc_disable_port_timing(fp, port_to_disable);
}
}
/********************************************************************
* Top-level function outputs a SDC file
* that constrain a FPGA fabric (P&Red netlist) using a benchmark
*******************************************************************/
void print_analysis_sdc(const std::string& sdc_dir,
const float& critical_path_delay,
const DeviceRRGSB& L_device_rr_gsb,
const std::vector<t_logical_block>& L_logical_blocks,
const vtr::Point<size_t>& device_size,
const std::vector<std::vector<t_grid_tile>>& L_grids,
const std::vector<t_block>& L_blocks,
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const bool& compact_routing_hierarchy) {
/* Create the file name for Verilog netlist */
std::string sdc_fname(sdc_dir + std::string(SDC_ANALYSIS_FILE_NAME));
vpr_printf(TIO_MESSAGE_INFO,
"Generating SDC for Timing/Power analysis on the mapped FPGA: %s ...",
sdc_fname.c_str());
/* Start time count */
clock_t t_start = clock();
/* Create the file stream */
std::fstream fp;
fp.open(sdc_fname, std::fstream::out | std::fstream::trunc);
/* Validate file stream */
check_file_handler(fp);
/* Generate the descriptions*/
print_sdc_file_header(fp, std::string("Constrain for Timing/Power analysis on the mapped FPGA"));
/* Find the top_module */
ModuleId top_module = module_manager.find_module(generate_fpga_top_module_name());
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
/* Create clock and set I/O ports with input/output delays */
print_analysis_sdc_io_delays(fp,
L_logical_blocks, device_size, L_grids, L_blocks,
module_manager, top_module,
circuit_lib, global_ports,
critical_path_delay);
/* Disable the timing for global ports */
print_analysis_sdc_disable_global_ports(fp,
module_manager, top_module,
circuit_lib, global_ports);
/* Disable the timing for configuration cells */
rec_print_pnr_sdc_disable_configurable_memory_module_output(fp,
module_manager, top_module,
format_dir_path(module_manager.module_name(top_module)));
/* Disable timing for unused routing resources in connection blocks */
print_analysis_sdc_disable_unused_cbs(fp, L_grids,
module_manager,
L_device_rr_gsb,
compact_routing_hierarchy);
/* Disable timing for unused routing resources in switch blocks */
print_analysis_sdc_disable_unused_sbs(fp, L_grids,
module_manager,
L_device_rr_gsb,
compact_routing_hierarchy);
/* Disable timing for unused routing resources in grids (programmable blocks) */
print_analysis_sdc_disable_unused_grids(fp, device_size, L_grids, L_blocks, module_manager);
/* Close file handler */
fp.close();
/* End time count */
clock_t t_end = clock();
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
vpr_printf(TIO_MESSAGE_INFO,
"took %g seconds\n",
run_time_sec);
}

View File

@ -0,0 +1,22 @@
#ifndef ANALYSIS_SDC_WRITER_H
#define ANALYSIS_SDC_WRITER_H
#include <string>
#include "vpr_types.h"
#include "rr_blocks.h"
#include "module_manager.h"
#include "bitstream_manager.h"
void print_analysis_sdc(const std::string& sdc_dir,
const float& critical_path_delay,
const DeviceRRGSB& L_device_rr_gsb,
const std::vector<t_logical_block>& L_logical_blocks,
const vtr::Point<size_t>& device_size,
const std::vector<std::vector<t_grid_tile>>& L_grids,
const std::vector<t_block>& L_blocks,
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const bool& compact_routing_hierarchy);
#endif

View File

@ -0,0 +1,235 @@
/********************************************************************
* This file includes most utilized functions
* that are used to output a SDC file
* in order to constrain a FPGA fabric (P&Red netlist) mapped to a benchmark
*******************************************************************/
#include "vtr_assert.h"
#include "fpga_x2p_utils.h"
#include "sdc_writer_utils.h"
#include "analysis_sdc_writer_utils.h"
#include "globals.h"
/********************************************************************
* Identify if a node should be disabled during analysis SDC generation
*******************************************************************/
bool is_rr_node_to_be_disable_for_analysis(t_rr_node* cur_rr_node) {
/* Conditions to enable timing analysis for a node
* 1st condition: it have a valid vpack_net_number
* 2nd condition: it is not an parasitic net
* 3rd condition: it is not a global net
*/
if ( (OPEN != cur_rr_node->vpack_net_num)
&& (FALSE == cur_rr_node->is_parasitic_net)
&& (FALSE == vpack_net[cur_rr_node->vpack_net_num].is_global)
&& (FALSE == vpack_net[cur_rr_node->vpack_net_num].is_const_gen) ){
return false;
}
return true;
}
/********************************************************************
* Disable all the unused inputs of routing multiplexers, which are not used by benchmark
* Here, we start from each input of a routing module, and traverse forward to the sink
* port of the module net whose source is the input
* We will find the instance name which is the parent of the sink port, and search the
* net id through the instance_name_to_net_map
* The the net id does not match the net id of this input, we will disable the sink port!
*
* parent_module
* +-----------------------
* | MUX instance A
* | +-----------
* input_port--->|--+---x-->| sink port (disable! net_id = Y)
* (net_id = X) | | +----------
* | | MUX instance B
* | | +----------
* | +------>| sink port (do not disable! net_id = X)
*
*******************************************************************/
void disable_analysis_module_input_pin_net_sinks(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& parent_module,
const std::string& parent_instance_name,
const ModulePortId& module_input_port,
const size_t& module_input_pin,
t_rr_node* input_rr_node,
const std::map<std::string, int> mux_instance_to_net_map) {
/* Validate file stream */
check_file_handler(fp);
/* Find the module net which sources from this port! */
ModuleNetId module_net = module_manager.module_instance_port_net(parent_module, parent_module, 0, module_input_port, module_input_pin);
VTR_ASSERT(true == module_manager.valid_module_net_id(parent_module, module_net));
/* Touch each sink of the net! */
for (const ModuleNetSinkId& sink_id : module_manager.module_net_sinks(parent_module, module_net)) {
ModuleId sink_module = module_manager.net_sink_modules(parent_module, module_net)[sink_id];
size_t sink_instance = module_manager.net_sink_instances(parent_module, module_net)[sink_id];
/* Skip when sink module is the parent module,
* the output ports of parent modules have been disabled/enabled already!
*/
if (sink_module == parent_module) {
continue;
}
std::string sink_instance_name = module_manager.instance_name(parent_module, sink_module, sink_instance);
bool disable_timing = false;
/* Check if this node is used by benchmark */
if (true == is_rr_node_to_be_disable_for_analysis(input_rr_node)) {
/* Disable all the sinks! */
disable_timing = true;
} else {
std::map<std::string, int>::const_iterator it = mux_instance_to_net_map.find(sink_instance_name);
if (it != mux_instance_to_net_map.end()) {
/* See if the net id matches. If does not match, we should disable! */
if (input_rr_node->vpack_net_num != mux_instance_to_net_map.at(sink_instance_name)) {
disable_timing = true;
}
}
}
/* Time to write SDC command to disable timing or not */
if (false == disable_timing) {
continue;
}
BasicPort sink_port = module_manager.module_port(sink_module, module_manager.net_sink_ports(parent_module, module_net)[sink_id]);
sink_port.set_width(module_manager.net_sink_pins(parent_module, module_net)[sink_id],
module_manager.net_sink_pins(parent_module, module_net)[sink_id]);
/* Get the input id that is used! Disable the unused inputs! */
fp << "set_disable_timing ";
fp << parent_instance_name << "/";
fp << sink_instance_name << "/";
fp << generate_sdc_port(sink_port);
fp << std::endl;
}
}
/********************************************************************
* Disable all the unused inputs of routing multiplexers, which are not used by benchmark
* Here, we start from each input of a routing module, and traverse forward to the sink
* port of the module net whose source is the input
* We will find the instance name which is the parent of the sink port, and search the
* net id through the instance_name_to_net_map
* The the net id does not match the net id of this input, we will disable the sink port!
*
* parent_module
* +-----------------------
* | MUX instance A
* | +-----------
* input_port--->|--+---x-->| sink port (disable! net_id = Y)
* (net_id = X) | | +----------
* | | MUX instance B
* | | +----------
* | +------>| sink port (do not disable! net_id = X)
*
*******************************************************************/
void disable_analysis_module_input_port_net_sinks(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& parent_module,
const std::string& parent_instance_name,
const ModulePortId& module_input_port,
t_rr_node* input_rr_node,
const std::map<std::string, int> mux_instance_to_net_map) {
/* Validate file stream */
check_file_handler(fp);
/* Find the module net which sources from this port! */
for (const size_t& pin : module_manager.module_port(parent_module, module_input_port).pins()) {
disable_analysis_module_input_pin_net_sinks(fp, module_manager, parent_module,
parent_instance_name,
module_input_port, pin,
input_rr_node,
mux_instance_to_net_map);
}
}
/********************************************************************
* Disable all the unused inputs of routing multiplexers, which are not used by benchmark
* Here, we start from each output of a child module, and traverse forward to the sink
* port of the module net whose source is the input
* We will find the instance name which is the parent of the sink port, and search the
* net id through the instance_name_to_net_map
* The the net id does not match the net id of this input, we will disable the sink port!
*
* Parent_module
* +---------------------------------------------
* |
* | +--------------------------------------------+
* | | MUX child_module |
* | | +-------------+ +-----------+ |
* | +--->| Routing |------>| | |
* input_pin0(netA) --->|----x--->| Multiplexer | netA | output_pin|-----+
* | +-------------+ | | netA
* | | |
*
*
*******************************************************************/
void disable_analysis_module_output_pin_net_sinks(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& parent_module,
const std::string& parent_instance_name,
const ModuleId& child_module,
const size_t& child_instance,
const ModulePortId& child_module_port,
const size_t& child_module_pin,
t_rr_node* output_rr_node,
const std::map<std::string, int> mux_instance_to_net_map) {
/* Validate file stream */
check_file_handler(fp);
/* Find the module net which sources from this port! */
ModuleNetId module_net = module_manager.module_instance_port_net(parent_module, child_module, child_instance, child_module_port, child_module_pin);
VTR_ASSERT(true == module_manager.valid_module_net_id(parent_module, module_net));
/* Touch each sink of the net! */
for (const ModuleNetSinkId& sink_id : module_manager.module_net_sinks(parent_module, module_net)) {
ModuleId sink_module = module_manager.net_sink_modules(parent_module, module_net)[sink_id];
size_t sink_instance = module_manager.net_sink_instances(parent_module, module_net)[sink_id];
/* Skip when sink module is the parent module,
* the output ports of parent modules have been disabled/enabled already!
*/
if (sink_module == parent_module) {
continue;
}
std::string sink_instance_name = module_manager.instance_name(parent_module, sink_module, sink_instance);
bool disable_timing = false;
/* Check if this node is used by benchmark */
if (true == is_rr_node_to_be_disable_for_analysis(output_rr_node)) {
/* Disable all the sinks! */
disable_timing = true;
} else {
std::map<std::string, int>::const_iterator it = mux_instance_to_net_map.find(sink_instance_name);
if (it != mux_instance_to_net_map.end()) {
/* See if the net id matches. If does not match, we should disable! */
if (output_rr_node->vpack_net_num != mux_instance_to_net_map.at(sink_instance_name)) {
disable_timing = true;
}
}
}
/* Time to write SDC command to disable timing or not */
if (false == disable_timing) {
continue;
}
BasicPort sink_port = module_manager.module_port(sink_module, module_manager.net_sink_ports(parent_module, module_net)[sink_id]);
sink_port.set_width(module_manager.net_sink_pins(parent_module, module_net)[sink_id],
module_manager.net_sink_pins(parent_module, module_net)[sink_id]);
/* Get the input id that is used! Disable the unused inputs! */
fp << "set_disable_timing ";
fp << parent_instance_name << "/";
fp << sink_instance_name << "/";
fp << generate_sdc_port(sink_port);
fp << std::endl;
}
}

View File

@ -0,0 +1,40 @@
#ifndef ANALYSIS_SDC_WRITER_UTILS_H
#define ANALYSIS_SDC_WRITER_UTILS_H
#include <fstream>
#include <string>
#include <map>
#include "module_manager.h"
#include "vpr_types.h"
bool is_rr_node_to_be_disable_for_analysis(t_rr_node* cur_rr_node);
void disable_analysis_module_input_pin_net_sinks(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& parent_module,
const std::string& parent_instance_name,
const ModulePortId& module_input_port,
const size_t& module_input_pin,
t_rr_node* input_rr_node,
const std::map<std::string, int> mux_instance_to_net_map);
void disable_analysis_module_input_port_net_sinks(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& parent_module,
const std::string& parent_instance_name,
const ModulePortId& module_input_port,
t_rr_node* input_rr_node,
const std::map<std::string, int> mux_instance_to_net_map) ;
void disable_analysis_module_output_pin_net_sinks(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& parent_module,
const std::string& parent_instance_name,
const ModuleId& child_module,
const size_t& child_instance,
const ModulePortId& child_module_port,
const size_t& child_module_pin,
t_rr_node* output_rr_node,
const std::map<std::string, int> mux_instance_to_net_map);
#endif

View File

@ -0,0 +1,361 @@
/********************************************************************
* This file includes functions that print SDC (Synopsys Design Constraint)
* files in physical design tools, i.e., Place & Route (PnR) tools
* The SDC files are used to constrain the physical design for each grid
* (CLBs, heterogeneous blocks etc.)
*
* Note that this is different from the SDC to constrain VPR Place&Route
* engine! These SDCs are designed for PnR to generate FPGA layouts!!!
*******************************************************************/
#include <ctime>
#include <fstream>
#include "vtr_assert.h"
#include "device_port.h"
#include "util.h"
#include "mux_utils.h"
#include "fpga_x2p_reserved_words.h"
#include "fpga_x2p_naming.h"
#include "fpga_x2p_utils.h"
#include "fpga_x2p_pbtypes_utils.h"
#include "sdc_writer_naming.h"
#include "sdc_writer_utils.h"
#include "pnr_sdc_grid_writer.h"
#include "globals.h"
/********************************************************************
* Print pin-to-pin timing constraints for a given interconnection
* at an output port of a pb_graph node
*******************************************************************/
static
void print_pnr_sdc_constrain_pb_pin_interc_timing(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& parent_module,
const e_side& border_side,
t_pb_graph_pin* des_pb_graph_pin,
t_mode* physical_mode) {
/* Validate file stream */
check_file_handler(fp);
/* 1. identify pin interconnection type,
* 2. Identify the number of fan-in (Consider interconnection edges of only selected mode)
* 3. Print SDC timing constraints
*/
int fan_in = 0;
t_interconnect* cur_interc = NULL;
find_interc_fan_in_des_pb_graph_pin(des_pb_graph_pin, physical_mode, &cur_interc, &fan_in);
if ((NULL == cur_interc) || (0 == fan_in)) {
/* No interconnection matched */
return;
}
/* Print pin-to-pin SDC contraint here */
/* For more than one mode defined, the direct interc has more than one input_edge ,
* We need to find which edge is connected the pin we want
*/
for (int iedge = 0; iedge < des_pb_graph_pin->num_input_edges; iedge++) {
if (cur_interc != des_pb_graph_pin->input_edges[iedge]->interconnect) {
continue;
}
/* Source pin, node, pb_type*/
t_pb_graph_pin* src_pb_graph_pin = des_pb_graph_pin->input_edges[iedge]->input_pins[0];
t_pb_graph_node* src_pb_graph_node = src_pb_graph_pin->parent_node;
/* Des pin, node, pb_type */
t_pb_graph_node* des_pb_graph_node = des_pb_graph_pin->parent_node;
/* Find the src module in module manager */
std::string src_module_name_prefix = generate_grid_block_prefix(std::string(GRID_MODULE_NAME_PREFIX), border_side);
std::string src_module_name = generate_physical_block_module_name(src_module_name_prefix, src_pb_graph_pin->parent_node->pb_type);
ModuleId src_module = module_manager.find_module(src_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(src_module));
ModulePortId src_module_port_id = module_manager.find_module_port(src_module, generate_pb_type_port_name(src_pb_graph_pin->port));
VTR_ASSERT(true == module_manager.valid_module_port_id(src_module, src_module_port_id));
/* Generate the name of the des instance name
* If des module is not the parent module, it is a child module.
* We should find the instance id
*/
std::string src_instance_name = src_module_name;
if (parent_module != src_module) {
src_instance_name = module_manager.module_name(parent_module) + std::string("/");
/* Instance id is actually the placement index */
size_t instance_id = src_pb_graph_node->placement_index;
if (true == module_manager.instance_name(parent_module, src_module, instance_id).empty()) {
src_instance_name += src_module_name;
src_instance_name += "_";
src_instance_name += std::to_string(instance_id);
src_instance_name += "_";
} else {
src_instance_name += module_manager.instance_name(parent_module, src_module, instance_id);
}
}
/* Generate src port information */
BasicPort src_port = module_manager.module_port(src_module, src_module_port_id);
src_port.set_width(src_pb_graph_pin->pin_number, src_pb_graph_pin->pin_number);
/* Find the des module in module manager */
std::string des_module_name_prefix = generate_grid_block_prefix(std::string(GRID_MODULE_NAME_PREFIX), border_side);
std::string des_module_name = generate_physical_block_module_name(des_module_name_prefix, des_pb_graph_pin->parent_node->pb_type);
ModuleId des_module = module_manager.find_module(des_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(des_module));
ModulePortId des_module_port_id = module_manager.find_module_port(des_module, generate_pb_type_port_name(des_pb_graph_pin->port));
VTR_ASSERT(true == module_manager.valid_module_port_id(des_module, des_module_port_id));
/* Generate the name of the des instance name
* If des module is not the parent module, it is a child module.
* We should find the instance id
*/
std::string des_instance_name = des_module_name;
if (parent_module != des_module) {
des_instance_name = module_manager.module_name(parent_module) + std::string("/");
/* Instance id is actually the placement index */
size_t instance_id = des_pb_graph_node->placement_index;
if (true == module_manager.instance_name(parent_module, des_module, instance_id).empty()) {
des_instance_name += des_module_name;
des_instance_name += "_";
des_instance_name += std::to_string(instance_id);
des_instance_name += "_";
} else {
des_instance_name += module_manager.instance_name(parent_module, des_module, instance_id);
}
}
/* Generate des port information */
BasicPort des_port = module_manager.module_port(des_module, des_module_port_id);
des_port.set_width(des_pb_graph_pin->pin_number, des_pb_graph_pin->pin_number);
/* Print a SDC timing constraint */
print_pnr_sdc_constrain_max_delay(fp,
src_instance_name,
generate_sdc_port(src_port),
des_instance_name,
generate_sdc_port(des_port),
des_pb_graph_pin->input_edges[iedge]->delay_max);
}
}
/********************************************************************
* Print port-to-port timing constraints which source from
* an output port of a pb_graph node
*******************************************************************/
static
void print_pnr_sdc_constrain_pb_interc_timing(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& parent_module,
const e_side& border_side,
t_pb_graph_node* des_pb_graph_node,
const e_spice_pb_port_type& pb_port_type,
t_mode* physical_mode) {
/* Validate file stream */
check_file_handler(fp);
switch (pb_port_type) {
case SPICE_PB_PORT_INPUT: {
for (int iport = 0; iport < des_pb_graph_node->num_input_ports; ++iport) {
for (int ipin = 0; ipin < des_pb_graph_node->num_input_pins[iport]; ++ipin) {
/* If this is a idle block, we set 0 to the selected edge*/
/* Get the selected edge of current pin*/
print_pnr_sdc_constrain_pb_pin_interc_timing(fp, module_manager, parent_module, border_side,
&(des_pb_graph_node->input_pins[iport][ipin]),
physical_mode);
}
}
break;
}
case SPICE_PB_PORT_OUTPUT: {
for (int iport = 0; iport < des_pb_graph_node->num_output_ports; ++iport) {
for (int ipin = 0; ipin < des_pb_graph_node->num_output_pins[iport]; ++ipin) {
print_pnr_sdc_constrain_pb_pin_interc_timing(fp, module_manager, parent_module, border_side,
&(des_pb_graph_node->output_pins[iport][ipin]),
physical_mode);
}
}
break;
}
case SPICE_PB_PORT_CLOCK: {
/* Do NOT constrain clock here, it should be handled by Clock Tree Synthesis */
break;
}
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d]) Invalid pb port type!\n",
__FILE__, __LINE__);
exit(1);
}
}
/********************************************************************
* This function will generate a SDC file for each pb_type,
* constraining the pin-to-pin timing between
* 1. input port of parent_pb_graph_node and input port of child_pb_graph_nodes
* 2. output port of parent_pb_graph_node and output port of child_pb_graph_nodes
* 3. output port of child_pb_graph_node and input port of child_pb_graph_nodes
*******************************************************************/
static
void print_pnr_sdc_constrain_pb_graph_node_timing(const std::string& sdc_dir,
const ModuleManager& module_manager,
t_pb_graph_node* parent_pb_graph_node,
const int& physical_mode_index,
const e_side& border_side) {
/* Get the pb_type definition related to the node */
t_pb_type* physical_pb_type = parent_pb_graph_node->pb_type;
std::string pb_module_name_prefix = generate_grid_block_prefix(std::string(GRID_MODULE_NAME_PREFIX), border_side);
std::string pb_module_name = generate_physical_block_module_name(pb_module_name_prefix, physical_pb_type);
/* Find the pb module in module manager */
ModuleId pb_module = module_manager.find_module(pb_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(pb_module));
/* Create the file name for SDC */
std::string sdc_fname(sdc_dir + pb_module_name + std::string(SDC_FILE_NAME_POSTFIX));
/* Create the file stream */
std::fstream fp;
fp.open(sdc_fname, std::fstream::out | std::fstream::trunc);
check_file_handler(fp);
/* Generate the descriptions*/
print_sdc_file_header(fp, std::string("Timing constraints for Grid " + pb_module_name + " in PnR"));
t_mode* physical_mode = &(parent_pb_graph_node->pb_type->modes[physical_mode_index]);
/* We check output_pins of cur_pb_graph_node and its the input_edges
* Built the interconnections between outputs of cur_pb_graph_node and outputs of child_pb_graph_node
* child_pb_graph_node.output_pins -----------------> cur_pb_graph_node.outpins
* /|\
* |
* input_pins, edges, output_pins
*/
print_pnr_sdc_constrain_pb_interc_timing(fp, module_manager, pb_module, border_side,
parent_pb_graph_node,
SPICE_PB_PORT_OUTPUT,
physical_mode);
/* We check input_pins of child_pb_graph_node and its the input_edges
* Built the interconnections between inputs of cur_pb_graph_node and inputs of child_pb_graph_node
* cur_pb_graph_node.input_pins -----------------> child_pb_graph_node.input_pins
* /|\
* |
* input_pins, edges, output_pins
*/
for (int ipb = 0; ipb < physical_mode->num_pb_type_children; ++ipb) {
for (int jpb = 0; jpb < physical_mode->pb_type_children[ipb].num_pb; ++jpb) {
t_pb_graph_node* child_pb_graph_node = &(parent_pb_graph_node->child_pb_graph_nodes[physical_mode_index][ipb][jpb]);
/* For each child_pb_graph_node input pins*/
print_pnr_sdc_constrain_pb_interc_timing(fp, module_manager, pb_module, border_side,
child_pb_graph_node,
SPICE_PB_PORT_INPUT,
physical_mode);
/* Do NOT constrain clock here, it should be handled by Clock Tree Synthesis */
}
}
/* Close file handler */
fp.close();
}
/********************************************************************
* Recursively print SDC timing constraints for a pb_type
* This function will generate a SDC file for each pb_type,
* constraining the pin-to-pin timing
*******************************************************************/
static
void rec_print_pnr_sdc_constrain_pb_graph_timing(const std::string& sdc_dir,
const ModuleManager& module_manager,
t_pb_graph_node* parent_pb_graph_node,
const e_side& border_side) {
/* Validate pb_graph node */
if (NULL == parent_pb_graph_node) {
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d]) Invalid parent_pb_graph_node.\n",
__FILE__, __LINE__);
exit(1);
}
/* Get the pb_type */
t_pb_type* parent_pb_type = parent_pb_graph_node->pb_type;
/* No need to constrain the primitive node */
if (TRUE == is_primitive_pb_type(parent_pb_type)) {
return;
}
/* Note we only go through the graph through the physical modes.
* which we build the modules
*/
int physical_mode_index = find_pb_type_physical_mode_index((*parent_pb_type));
/* Write a SDC file for this pb_type */
print_pnr_sdc_constrain_pb_graph_node_timing(sdc_dir, module_manager,
parent_pb_graph_node, physical_mode_index,
border_side);
/* Go recursively to the lower level in the pb_graph
* Note that we assume a full hierarchical P&R, we will only visit pb_graph_node of unique pb_type
*/
for (int ipb = 0; ipb < parent_pb_type->modes[physical_mode_index].num_pb_type_children; ++ipb) {
rec_print_pnr_sdc_constrain_pb_graph_timing(sdc_dir, module_manager,
&(parent_pb_graph_node->child_pb_graph_nodes[physical_mode_index][ipb][0]),
border_side);
}
}
/********************************************************************
* Top-level function to print timing constraints for pb_types
*******************************************************************/
void print_pnr_sdc_constrain_grid_timing(const std::string& sdc_dir,
const ModuleManager& module_manager) {
vpr_printf(TIO_MESSAGE_INFO,
"Generating SDC for constraining grid timing for P&R flow...");
/* Start time count */
clock_t t_start = clock();
for (int itype = 0; itype < num_types; itype++) {
/* Bypass EMPTY types */
if (EMPTY_TYPE == &type_descriptors[itype]) {
continue;
}
/* For IO_TYPE, we have four types of I/Os */
if (IO_TYPE == &type_descriptors[itype]) {
/* Special for I/O block, generate one module for each border side */
for (int iside = 0; iside < NUM_SIDES; iside++) {
Side side_manager(iside);
rec_print_pnr_sdc_constrain_pb_graph_timing(sdc_dir, module_manager,
type_descriptors[itype].pb_graph_head,
side_manager.get_side());
}
} else if (FILL_TYPE == &type_descriptors[itype]) {
/* For CLB */
rec_print_pnr_sdc_constrain_pb_graph_timing(sdc_dir, module_manager,
type_descriptors[itype].pb_graph_head,
NUM_SIDES);
} else {
/* For heterogenenous blocks */
rec_print_pnr_sdc_constrain_pb_graph_timing(sdc_dir, module_manager,
type_descriptors[itype].pb_graph_head,
NUM_SIDES);
}
}
/* End time count */
clock_t t_end = clock();
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
vpr_printf(TIO_MESSAGE_INFO,
"took %g seconds\n",
run_time_sec);
}

View File

@ -0,0 +1,11 @@
#ifndef PNR_SDC_GRID_WRITER_H
#define PNR_SDC_GRID_WRITER_H
#include <string>
#include <vector>
#include "vpr_types.h"
void print_pnr_sdc_constrain_grid_timing(const std::string& sdc_dir,
const ModuleManager& module_manager);
#endif

View File

@ -0,0 +1,452 @@
/********************************************************************
* This file includes functions that print SDC (Synopsys Design Constraint)
* files in physical design tools, i.e., Place & Route (PnR) tools
* The SDC files are used to constrain the physical design for each routing modules
* in FPGA fabric, such as Switch Blocks (SBs) and Connection Blocks (CBs)
*
* Note that this is different from the SDC to constrain VPR Place&Route
* engine! These SDCs are designed for PnR to generate FPGA layouts!!!
*******************************************************************/
#include <ctime>
#include <fstream>
#include "vtr_assert.h"
#include "device_port.h"
#include "util.h"
#include "mux_utils.h"
#include "fpga_x2p_naming.h"
#include "fpga_x2p_utils.h"
#include "build_routing_module_utils.h"
#include "sdc_writer_naming.h"
#include "sdc_writer_utils.h"
#include "pnr_sdc_routing_writer.h"
/********************************************************************
* Find the timing constraints between the inputs and outputs of a routing
* multiplexer in a Switch Block
*******************************************************************/
static
float find_pnr_sdc_switch_tmax(const t_switch_inf& switch_inf) {
return switch_inf.R * switch_inf.Cout + switch_inf.Tdel;
}
/********************************************************************
* Set timing constraints between the inputs and outputs of a routing
* multiplexer in a Switch Block
*******************************************************************/
static
void print_pnr_sdc_constrain_sb_mux_timing(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& sb_module,
const RRGSB& rr_gsb,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_switch_inf>& switches,
const e_side& output_node_side,
t_rr_node* output_rr_node) {
/* Validate file stream */
check_file_handler(fp);
VTR_ASSERT( ( CHANX == output_rr_node->type )
|| ( CHANY == output_rr_node->type ));
/* Find the module port corresponding to the output rr_node */
ModulePortId module_output_port = find_switch_block_module_chan_port(module_manager,
sb_module,
rr_gsb,
output_node_side,
output_rr_node,
OUT_PORT);
/* Find the module port corresponding to the fan-in rr_nodes of the output rr_node */
std::vector<t_rr_node*> input_rr_nodes;
for (int iedge = 0; iedge < output_rr_node->num_drive_rr_nodes; iedge++) {
input_rr_nodes.push_back(output_rr_node->drive_rr_nodes[iedge]);
}
std::vector<ModulePortId> module_input_ports = find_switch_block_module_input_ports(module_manager,
sb_module,
rr_gsb,
grids,
input_rr_nodes);
/* Find timing constraints for each path (edge) */
std::map<ModulePortId, float> switch_delays;
for (int iedge = 0; iedge < output_rr_node->num_drive_rr_nodes; iedge++) {
/* Get the switch delay */
int switch_id = output_rr_node->drive_switches[iedge];
switch_delays[module_input_ports[iedge]] = find_pnr_sdc_switch_tmax(switches[switch_id]);
}
/* Find the starting points */
for (const ModulePortId& module_input_port : module_input_ports) {
/* Constrain a path */
print_pnr_sdc_constrain_module_port2port_timing(fp,
module_manager,
sb_module, module_input_port,
sb_module, module_output_port,
switch_delays[module_input_port]);
}
}
/********************************************************************
* Set timing constraints between the inputs and outputs of SBs,
* which are connected by routing multiplexers with the given delays
* specified in architectural XML file
*
* To enable block by block timing constraining, we generate the SDC
* file for each unique SB module
*******************************************************************/
static
void print_pnr_sdc_constrain_sb_timing(const std::string& sdc_dir,
const ModuleManager& module_manager,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_switch_inf>& switches,
const RRGSB& rr_gsb) {
/* Create the file name for Verilog netlist */
vtr::Point<size_t> gsb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
std::string sdc_fname(sdc_dir + generate_switch_block_module_name(gsb_coordinate) + std::string(SDC_FILE_NAME_POSTFIX));
/* Create the file stream */
std::fstream fp;
fp.open(sdc_fname, std::fstream::out | std::fstream::trunc);
/* Validate file stream */
check_file_handler(fp);
std::string sb_module_name = generate_switch_block_module_name(gsb_coordinate);
ModuleId sb_module = module_manager.find_module(sb_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(sb_module));
/* Generate the descriptions*/
print_sdc_file_header(fp, std::string("Constrain timing of Switch Block " + sb_module_name + " for PnR"));
for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) {
Side side_manager(side);
for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) {
t_rr_node* chan_rr_node = rr_gsb.get_chan_node(side_manager.get_side(), itrack);
/* We only care the output port and it should indicate a SB mux */
if (OUT_PORT != rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) {
continue;
}
/* Constrain thru wires */
if (false != rr_gsb.is_sb_node_passing_wire(side_manager.get_side(), itrack)) {
continue;
}
/* This is a MUX, constrain all the paths from an input to an output */
print_pnr_sdc_constrain_sb_mux_timing(fp,
module_manager, sb_module,
rr_gsb,
grids, switches,
side_manager.get_side(),
chan_rr_node);
}
}
/* Close file handler */
fp.close();
}
/********************************************************************
* Print SDC timing constraints for Switch blocks
* This function is designed for flatten routing hierarchy
*******************************************************************/
void print_pnr_sdc_flatten_routing_constrain_sb_timing(const std::string& sdc_dir,
const ModuleManager& module_manager,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_switch_inf>& switches,
const DeviceRRGSB& L_device_rr_gsb) {
vpr_printf(TIO_MESSAGE_INFO,
"Generating SDC for constrain Switch Block timing for P&R flow...");
/* Start time count */
clock_t t_start = clock();
/* Get the range of SB array */
DeviceCoordinator sb_range = L_device_rr_gsb.get_gsb_range();
/* Go for each SB */
for (size_t ix = 0; ix < sb_range.get_x(); ++ix) {
for (size_t iy = 0; iy < sb_range.get_y(); ++iy) {
const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy);
print_pnr_sdc_constrain_sb_timing(sdc_dir,
module_manager,
grids, switches,
rr_gsb);
}
}
/* End time count */
clock_t t_end = clock();
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
vpr_printf(TIO_MESSAGE_INFO,
"took %g seconds\n",
run_time_sec);
}
/********************************************************************
* Print SDC timing constraints for Switch blocks
* This function is designed for compact routing hierarchy
*******************************************************************/
void print_pnr_sdc_compact_routing_constrain_sb_timing(const std::string& sdc_dir,
const ModuleManager& module_manager,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_switch_inf>& switches,
const DeviceRRGSB& L_device_rr_gsb) {
vpr_printf(TIO_MESSAGE_INFO,
"Generating SDC for constrain Switch Block timing for P&R flow...");
/* Start time count */
clock_t t_start = clock();
for (size_t isb = 0; isb < L_device_rr_gsb.get_num_sb_unique_module(); ++isb) {
const RRGSB& rr_gsb = L_device_rr_gsb.get_sb_unique_module(isb);
print_pnr_sdc_constrain_sb_timing(sdc_dir,
module_manager,
grids, switches,
rr_gsb);
}
/* End time count */
clock_t t_end = clock();
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
vpr_printf(TIO_MESSAGE_INFO,
"took %g seconds\n",
run_time_sec);
}
/********************************************************************
* Set timing constraints between the inputs and outputs of a routing
* multiplexer in a Connection Block
*******************************************************************/
static
void print_pnr_sdc_constrain_cb_mux_timing(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& cb_module,
const RRGSB& rr_gsb,
const t_rr_type& cb_type,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_switch_inf>& switches,
t_rr_node* output_rr_node) {
/* Validate file stream */
check_file_handler(fp);
VTR_ASSERT(IPIN == output_rr_node->type);
/* We have OPINs since we may have direct connections:
* These connections should be handled by other functions in the compact_netlist.c
* So we just return here for OPINs
*/
if ( (1 == output_rr_node->num_drive_rr_nodes)
&& (OPIN == output_rr_node->drive_rr_nodes[0]->type) ) {
return;
}
/* Find the module port corresponding to the output rr_node */
ModulePortId module_output_port = find_connection_block_module_ipin_port(module_manager,
cb_module,
rr_gsb,
grids, output_rr_node);
/* Find the module port corresponding to the fan-in rr_nodes of the output rr_node */
std::vector<t_rr_node*> input_rr_nodes;
for (int iedge = 0; iedge < output_rr_node->num_drive_rr_nodes; iedge++) {
/* Skip OPINs which should be handled in direct connection */
input_rr_nodes.push_back(output_rr_node->drive_rr_nodes[iedge]);
}
std::vector<ModulePortId> module_input_ports = find_connection_block_module_input_ports(module_manager,
cb_module,
rr_gsb,
cb_type,
input_rr_nodes);
/* Find timing constraints for each path (edge) */
std::map<ModulePortId, float> switch_delays;
for (int iedge = 0; iedge < output_rr_node->num_drive_rr_nodes; iedge++) {
/* Get the switch delay */
int switch_id = output_rr_node->drive_switches[iedge];
switch_delays[module_input_ports[iedge]] = find_pnr_sdc_switch_tmax(switches[switch_id]);
}
/* Find the starting points */
for (const ModulePortId& module_input_port : module_input_ports) {
/* Constrain a path */
print_pnr_sdc_constrain_module_port2port_timing(fp,
module_manager,
cb_module, module_input_port,
cb_module, module_output_port,
switch_delays[module_input_port]);
}
}
/********************************************************************
* Print SDC timing constraints for a Connection block
* This function is designed for compact routing hierarchy
*******************************************************************/
static
void print_pnr_sdc_constrain_cb_timing(const std::string& sdc_dir,
const ModuleManager& module_manager,
const RRGSB& rr_gsb,
const t_rr_type& cb_type,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_switch_inf>& switches) {
/* Create the netlist */
vtr::Point<size_t> gsb_coordinate(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
/* Find the module name and create a SDC file for it */
std::string sdc_fname(sdc_dir + generate_connection_block_module_name(cb_type, gsb_coordinate) + std::string(SDC_FILE_NAME_POSTFIX));
/* Create the file stream */
std::fstream fp;
fp.open(sdc_fname, std::fstream::out | std::fstream::trunc);
/* Validate file stream */
check_file_handler(fp);
std::string cb_module_name = generate_connection_block_module_name(cb_type, gsb_coordinate);
ModuleId cb_module = module_manager.find_module(cb_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(cb_module));
/* Generate the descriptions*/
print_sdc_file_header(fp, std::string("Constrain timing of Connection Block " + cb_module_name + " for PnR"));
std::vector<enum e_side> cb_sides = rr_gsb.get_cb_ipin_sides(cb_type);
for (size_t side = 0; side < cb_sides.size(); ++side) {
enum e_side cb_ipin_side = cb_sides[side];
Side side_manager(cb_ipin_side);
for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(cb_ipin_side); ++inode) {
t_rr_node* ipin_rr_node = rr_gsb.get_ipin_node(cb_ipin_side, inode);
print_pnr_sdc_constrain_cb_mux_timing(fp,
module_manager, cb_module,
rr_gsb, cb_type,
grids, switches,
ipin_rr_node);
}
}
/* Close file handler */
fp.close();
}
/********************************************************************
* Iterate over all the connection blocks in a device
* and print SDC file for each of them
*******************************************************************/
static
void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_dir,
const ModuleManager& module_manager,
const DeviceRRGSB& L_device_rr_gsb,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_switch_inf>& switches,
const t_rr_type& cb_type) {
/* Build unique X-direction connection block modules */
DeviceCoordinator cb_range = L_device_rr_gsb.get_gsb_range();
for (size_t ix = 0; ix < cb_range.get_x(); ++ix) {
for (size_t iy = 0; iy < cb_range.get_y(); ++iy) {
/* Check if the connection block exists in the device!
* Some of them do NOT exist due to heterogeneous blocks (height > 1)
* We will skip those modules
*/
const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy);
if (false == rr_gsb.is_cb_exist(cb_type)) {
continue;
}
print_pnr_sdc_constrain_cb_timing(sdc_dir,
module_manager,
rr_gsb,
cb_type,
grids, switches);
}
}
}
/********************************************************************
* Iterate over all the connection blocks in a device
* and print SDC file for each of them
*******************************************************************/
void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_dir,
const ModuleManager& module_manager,
const DeviceRRGSB& L_device_rr_gsb,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_switch_inf>& switches) {
vpr_printf(TIO_MESSAGE_INFO,
"Generating SDC for constrain Connection Block timing for P&R flow...");
/* Start time count */
clock_t t_start = clock();
print_pnr_sdc_flatten_routing_constrain_cb_timing(sdc_dir, module_manager,
L_device_rr_gsb,
grids,
switches,
CHANX);
print_pnr_sdc_flatten_routing_constrain_cb_timing(sdc_dir, module_manager,
L_device_rr_gsb,
grids,
switches,
CHANY);
/* End time count */
clock_t t_end = clock();
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
vpr_printf(TIO_MESSAGE_INFO,
"took %g seconds\n",
run_time_sec);
}
/********************************************************************
* Print SDC timing constraints for Connection blocks
* This function is designed for compact routing hierarchy
*******************************************************************/
void print_pnr_sdc_compact_routing_constrain_cb_timing(const std::string& sdc_dir,
const ModuleManager& module_manager,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_switch_inf>& switches,
const DeviceRRGSB& L_device_rr_gsb) {
vpr_printf(TIO_MESSAGE_INFO,
"Generating SDC for constrain Connection Block timing for P&R flow...");
/* Start time count */
clock_t t_start = clock();
/* Print SDC for unique X-direction connection block modules */
for (size_t icb = 0; icb < L_device_rr_gsb.get_num_cb_unique_module(CHANX); ++icb) {
const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(CHANX, icb);
print_pnr_sdc_constrain_cb_timing(sdc_dir,
module_manager,
unique_mirror,
CHANX,
grids, switches);
}
/* Print SDC for unique Y-direction connection block modules */
for (size_t icb = 0; icb < L_device_rr_gsb.get_num_cb_unique_module(CHANY); ++icb) {
const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(CHANY, icb);
print_pnr_sdc_constrain_cb_timing(sdc_dir,
module_manager,
unique_mirror,
CHANY,
grids, switches);
}
/* End time count */
clock_t t_end = clock();
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
vpr_printf(TIO_MESSAGE_INFO,
"took %g seconds\n",
run_time_sec);
}

View File

@ -0,0 +1,34 @@
#ifndef PNR_SDC_ROUTING_WRITER_H
#define PNR_SDC_ROUTING_WRITER_H
#include <string>
#include <vector>
#include "module_manager.h"
#include "rr_blocks.h"
#include "vpr_types.h"
void print_pnr_sdc_flatten_routing_constrain_sb_timing(const std::string& sdc_dir,
const ModuleManager& module_manager,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_switch_inf>& switches,
const DeviceRRGSB& L_device_rr_gsb);
void print_pnr_sdc_compact_routing_constrain_sb_timing(const std::string& sdc_dir,
const ModuleManager& module_manager,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_switch_inf>& switches,
const DeviceRRGSB& L_device_rr_gsb);
void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_dir,
const ModuleManager& module_manager,
const DeviceRRGSB& L_device_rr_gsb,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_switch_inf>& switches);
void print_pnr_sdc_compact_routing_constrain_cb_timing(const std::string& sdc_dir,
const ModuleManager& module_manager,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_switch_inf>& switches,
const DeviceRRGSB& L_device_rr_gsb);
#endif

View File

@ -0,0 +1,473 @@
/********************************************************************
* This file includes functions that print SDC (Synopsys Design Constraint)
* files in physical design tools, i.e., Place & Route (PnR) tools
* The SDC files are used to constrain the physical design for each module
* in FPGA fabric, such as Configurable Logic Blocks (CLBs),
* Heterogeneous blocks, Switch Blocks (SBs) and Connection Blocks (CBs)
*
* Note that this is different from the SDC to constrain VPR Place&Route
* engine! These SDCs are designed for PnR to generate FPGA layouts!!!
*******************************************************************/
#include <ctime>
#include <fstream>
#include <iomanip>
#include "vtr_assert.h"
#include "device_port.h"
#include "util.h"
#include "mux_utils.h"
#include "fpga_x2p_naming.h"
#include "fpga_x2p_utils.h"
#include "sdc_writer_naming.h"
#include "sdc_writer_utils.h"
#include "sdc_memory_utils.h"
#include "pnr_sdc_routing_writer.h"
#include "pnr_sdc_grid_writer.h"
#include "pnr_sdc_writer.h"
/********************************************************************
* Local variables
*******************************************************************/
constexpr float SDC_FIXED_PROG_CLOCK_PERIOD = 100;
constexpr float SDC_FIXED_CLOCK_PERIOD = 10;
/********************************************************************
* Print a SDC file to constrain the global ports of FPGA fabric
* in particular clock ports
*
* For programming clock, we give a fixed period, while for operating
* clock, we constrain with critical path delay
*******************************************************************/
static
void print_pnr_sdc_global_ports(const std::string& sdc_dir,
const float& critical_path_delay,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports) {
/* Create the file name for Verilog netlist */
std::string sdc_fname(sdc_dir + std::string(SDC_GLOBAL_PORTS_FILE_NAME));
vpr_printf(TIO_MESSAGE_INFO,
"Generating SDC for constraining clocks for P&R flow: %s ...",
sdc_fname.c_str());
/* Start time count */
clock_t t_start = clock();
/* Create the file stream */
std::fstream fp;
fp.open(sdc_fname, std::fstream::out | std::fstream::trunc);
check_file_handler(fp);
/* Generate the descriptions*/
print_sdc_file_header(fp, std::string("Clock contraints for PnR"));
/* Get clock port from the global port */
for (const CircuitPortId& clock_port : global_ports) {
if (SPICE_MODEL_PORT_CLOCK != circuit_lib.port_type(clock_port)) {
continue;
}
/* Reach here, it means a clock port and we need print constraints */
float clock_period = critical_path_delay;
/* For programming clock, we give a fixed period */
if (true == circuit_lib.port_is_prog(clock_port)) {
clock_period = SDC_FIXED_PROG_CLOCK_PERIOD;
/* Print comments */
fp << "##################################################" << std::endl;
fp << "# Create programmable clock " << std::endl;
fp << "##################################################" << std::endl;
} else {
/* Print comments */
fp << "##################################################" << std::endl;
fp << "# Create clock " << std::endl;
fp << "##################################################" << std::endl;
}
for (const size_t& pin : circuit_lib.pins(clock_port)) {
BasicPort port_to_constrain(circuit_lib.port_prefix(clock_port), pin, pin);
fp << "create_clock ";
fp << generate_sdc_port(port_to_constrain) << "-period ";
fp << std::setprecision(10) << clock_period;
fp << " -waveform {0 ";
fp << std::setprecision(10) << clock_period / 2;
fp << "}" << std::endl;
fp << std::endl;
}
}
/* For non-clock port from the global port: give a fixed period */
for (const CircuitPortId& global_port : global_ports) {
if (SPICE_MODEL_PORT_CLOCK == circuit_lib.port_type(global_port)) {
continue;
}
/* Print comments */
fp << "##################################################" << std::endl;
fp << "# Constrain other global ports " << std::endl;
fp << "##################################################" << std::endl;
/* Reach here, it means a non-clock global port and we need print constraints */
float clock_period = SDC_FIXED_CLOCK_PERIOD;
for (const size_t& pin : circuit_lib.pins(global_port)) {
BasicPort port_to_constrain(circuit_lib.port_prefix(global_port), pin, pin);
fp << "create_clock ";
fp << generate_sdc_port(port_to_constrain) << "-period ";
fp << std::setprecision(10) << clock_period;
fp << " -waveform {0 ";
fp << std::setprecision(10) << clock_period / 2;
fp << "} ";
fp << "[list [get_ports { " << generate_sdc_port(port_to_constrain) << "}]]" << std::endl;
fp << "set_drive 0 " << generate_sdc_port(port_to_constrain) << std::endl;
fp << std::endl;
}
}
/* Close file handler */
fp.close();
/* End time count */
clock_t t_end = clock();
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
vpr_printf(TIO_MESSAGE_INFO,
"took %g seconds\n",
run_time_sec);
}
/********************************************************************
* Break combinational loops in FPGA fabric, which mainly come from
* configurable memory cells.
* To handle this, we disable the outputs of memory cells
*******************************************************************/
static
void print_pnr_sdc_constrain_configurable_memory_outputs(const std::string& sdc_dir,
const ModuleManager& module_manager,
const ModuleId& top_module) {
/* Create the file name for Verilog netlist */
std::string sdc_fname(sdc_dir + std::string(SDC_DISABLE_CONFIG_MEM_OUTPUTS_FILE_NAME));
vpr_printf(TIO_MESSAGE_INFO,
"Generating SDC for disable configurable memory outputs for P&R flow: %s ...",
sdc_fname.c_str());
/* Start time count */
clock_t t_start = clock();
/* Create the file stream */
std::fstream fp;
fp.open(sdc_fname, std::fstream::out | std::fstream::trunc);
check_file_handler(fp);
/* Generate the descriptions*/
print_sdc_file_header(fp, std::string("Disable configurable memory outputs for PnR"));
/* Go recursively in the module manager, starting from the top-level module: instance id of the top-level module is 0 by default */
rec_print_pnr_sdc_disable_configurable_memory_module_output(fp, module_manager, top_module,
format_dir_path(module_manager.module_name(top_module)));
/* Close file handler */
fp.close();
/* End time count */
clock_t t_end = clock();
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
vpr_printf(TIO_MESSAGE_INFO,
"took %g seconds\n",
run_time_sec);
}
/********************************************************************
* Break combinational loops in FPGA fabric, which mainly come from
* loops of multiplexers.
* To handle this, we disable the timing at outputs of routing multiplexers
*******************************************************************/
static
void print_sdc_disable_routing_multiplexer_outputs(const std::string& sdc_dir,
const MuxLibrary& mux_lib,
const CircuitLibrary& circuit_lib,
const ModuleManager& module_manager) {
/* Create the file name for Verilog netlist */
std::string sdc_fname(sdc_dir + std::string(SDC_DISABLE_MUX_OUTPUTS_FILE_NAME));
vpr_printf(TIO_MESSAGE_INFO,
"Generating SDC for disable routing multiplexer outputs for P&R flow: %s ...",
sdc_fname.c_str());
/* Start time count */
clock_t t_start = clock();
/* Create the file stream */
std::fstream fp;
fp.open(sdc_fname, std::fstream::out | std::fstream::trunc);
check_file_handler(fp);
/* Generate the descriptions*/
print_sdc_file_header(fp, std::string("Disable routing multiplexer outputs for PnR"));
/* Iterate over the MUX modules */
for (const MuxId& mux_id : mux_lib.muxes()) {
const CircuitModelId& mux_model = mux_lib.mux_circuit_model(mux_id);
/* Skip LUTs, we only care about multiplexers here */
if (SPICE_MODEL_MUX != circuit_lib.model_type(mux_model)) {
continue;
}
const MuxGraph& mux_graph = mux_lib.mux_graph(mux_id);
std::string mux_module_name = generate_mux_subckt_name(circuit_lib, mux_model,
find_mux_num_datapath_inputs(circuit_lib, mux_model, mux_graph.num_inputs()),
std::string(""));
/* Find the module name in module manager */
ModuleId mux_module = module_manager.find_module(mux_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(mux_module));
/* Disable the timing for the output ports */
for (const BasicPort& output_port : module_manager.module_ports_by_type(mux_module, ModuleManager::MODULE_OUTPUT_PORT)) {
fp << "set_disable_timing [get_pins -filter \"name =~ " << output_port.get_name() << "*\" ";
fp << "-of [get_cells -hier -filter \"ref_lib_cell_name == " << mux_module_name << "\"]]" << std::endl;
fp << std::endl;
}
}
/* Close file handler */
fp.close();
/* End time count */
clock_t t_end = clock();
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
vpr_printf(TIO_MESSAGE_INFO,
"took %g seconds\n",
run_time_sec);
}
/********************************************************************
* Break combinational loops in FPGA fabric, which mainly come from
* loops of multiplexers.
* To handle this, we disable the timing at outputs of Switch blocks
* This function is designed for flatten routing hierarchy
*******************************************************************/
static
void print_pnr_sdc_flatten_routing_disable_switch_block_outputs(const std::string& sdc_dir,
const ModuleManager& module_manager,
const DeviceRRGSB& L_device_rr_gsb) {
/* Create the file name for Verilog netlist */
std::string sdc_fname(sdc_dir + std::string(SDC_DISABLE_SB_OUTPUTS_FILE_NAME));
vpr_printf(TIO_MESSAGE_INFO,
"Generating SDC for disable Switch Block outputs for P&R flow: %s ...",
sdc_fname.c_str());
/* Start time count */
clock_t t_start = clock();
/* Create the file stream */
std::fstream fp;
fp.open(sdc_fname, std::fstream::out | std::fstream::trunc);
check_file_handler(fp);
/* Generate the descriptions*/
print_sdc_file_header(fp, std::string("Disable Switch Block outputs for PnR"));
/* Get the range of SB array */
DeviceCoordinator sb_range = L_device_rr_gsb.get_gsb_range();
/* Go for each SB */
for (size_t ix = 0; ix < sb_range.get_x(); ++ix) {
for (size_t iy = 0; iy < sb_range.get_y(); ++iy) {
const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy);
vtr::Point<size_t> gsb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
std::string sb_instance_name = generate_switch_block_module_name(gsb_coordinate);
ModuleId sb_module = module_manager.find_module(sb_instance_name);
VTR_ASSERT(true == module_manager.valid_module_id(sb_module));
/* Disable the outputs of the module */
for (const BasicPort& output_port : module_manager.module_ports_by_type(sb_module, ModuleManager::MODULE_OUTPUT_PORT)) {
fp << "set_disable_timing " << sb_instance_name << "/" << output_port.get_name() << std::endl;
fp << std::endl;
}
}
}
/* Close file handler */
fp.close();
/* End time count */
clock_t t_end = clock();
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
vpr_printf(TIO_MESSAGE_INFO,
"took %g seconds\n",
run_time_sec);
}
/********************************************************************
* Break combinational loops in FPGA fabric, which mainly come from
* loops of multiplexers.
* To handle this, we disable the timing at outputs of Switch blocks
* This function is designed for compact routing hierarchy
*******************************************************************/
static
void print_pnr_sdc_compact_routing_disable_switch_block_outputs(const std::string& sdc_dir,
const ModuleManager& module_manager,
const ModuleId& top_module,
const DeviceRRGSB& L_device_rr_gsb) {
/* Create the file name for Verilog netlist */
std::string sdc_fname(sdc_dir + std::string(SDC_DISABLE_SB_OUTPUTS_FILE_NAME));
vpr_printf(TIO_MESSAGE_INFO,
"Generating SDC for disable Switch Block outputs for P&R flow: %s ...",
sdc_fname.c_str());
/* Start time count */
clock_t t_start = clock();
/* Create the file stream */
std::fstream fp;
fp.open(sdc_fname, std::fstream::out | std::fstream::trunc);
check_file_handler(fp);
/* Generate the descriptions*/
print_sdc_file_header(fp, std::string("Disable Switch Block outputs for PnR"));
/* Build unique switch block modules */
for (size_t isb = 0; isb < L_device_rr_gsb.get_num_sb_unique_module(); ++isb) {
const RRGSB& rr_gsb = L_device_rr_gsb.get_sb_unique_module(isb);
vtr::Point<size_t> gsb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
std::string sb_module_name = generate_switch_block_module_name(gsb_coordinate);
ModuleId sb_module = module_manager.find_module(sb_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(sb_module));
/* Find all the instances in the top-level module */
for (const size_t& instance_id : module_manager.child_module_instances(top_module, sb_module)) {
std::string sb_instance_name = module_manager.instance_name(top_module, sb_module, instance_id);
/* Disable the outputs of the module */
for (const BasicPort& output_port : module_manager.module_ports_by_type(sb_module, ModuleManager::MODULE_OUTPUT_PORT)) {
fp << "set_disable_timing " << sb_instance_name << "/" << output_port.get_name() << std::endl;
fp << std::endl;
}
}
}
/* Close file handler */
fp.close();
/* End time count */
clock_t t_end = clock();
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
vpr_printf(TIO_MESSAGE_INFO,
"took %g seconds\n",
run_time_sec);
}
/********************************************************************
* Top-level function to print a number of SDC files in different purpose
* This function will generate files upon the options provided by users
* 1. Design constraints for CLBs
* 2. Design constraints for Switch Blocks
* 3. Design constraints for Connection Blocks
* 4. Design constraints for breaking the combinational loops in FPGA fabric
*******************************************************************/
void print_pnr_sdc(const SdcOption& sdc_options,
const float& critical_path_delay,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_switch_inf>& switches,
const DeviceRRGSB& L_device_rr_gsb,
const ModuleManager& module_manager,
const MuxLibrary& mux_lib,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const bool& compact_routing_hierarchy) {
/* Constrain global ports */
if (true == sdc_options.constrain_global_port()) {
print_pnr_sdc_global_ports(sdc_options.sdc_dir(), critical_path_delay, circuit_lib, global_ports);
}
std::string top_module_name = generate_fpga_top_module_name();
ModuleId top_module = module_manager.find_module(top_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
/* Output Design Constraints to disable outputs of memory cells */
if (true == sdc_options.constrain_configurable_memory_outputs()) {
print_pnr_sdc_constrain_configurable_memory_outputs(sdc_options.sdc_dir(), module_manager, top_module);
}
/* Break loops from Multiplexer Output */
if (true == sdc_options.constrain_routing_multiplexer_outputs()) {
print_sdc_disable_routing_multiplexer_outputs(sdc_options.sdc_dir(),
mux_lib, circuit_lib,
module_manager);
}
/* Break loops from any SB output */
if (true == sdc_options.constrain_switch_block_outputs()) {
if (true == compact_routing_hierarchy) {
print_pnr_sdc_compact_routing_disable_switch_block_outputs(sdc_options.sdc_dir(),
module_manager, top_module,
L_device_rr_gsb);
} else {
VTR_ASSERT_SAFE (false == compact_routing_hierarchy);
print_pnr_sdc_flatten_routing_disable_switch_block_outputs(sdc_options.sdc_dir(),
module_manager,
L_device_rr_gsb);
}
}
/* Output routing constraints for Switch Blocks */
if (true == sdc_options.constrain_sb()) {
if (true == compact_routing_hierarchy) {
print_pnr_sdc_compact_routing_constrain_sb_timing(sdc_options.sdc_dir(),
module_manager,
grids, switches,
L_device_rr_gsb);
} else {
VTR_ASSERT_SAFE (false == compact_routing_hierarchy);
print_pnr_sdc_flatten_routing_constrain_sb_timing(sdc_options.sdc_dir(),
module_manager,
grids, switches,
L_device_rr_gsb);
}
}
/* Output routing constraints for Connection Blocks */
if (true == sdc_options.constrain_cb()) {
if (true == compact_routing_hierarchy) {
print_pnr_sdc_compact_routing_constrain_cb_timing(sdc_options.sdc_dir(),
module_manager,
grids,
switches,
L_device_rr_gsb);
} else {
VTR_ASSERT_SAFE (false == compact_routing_hierarchy);
print_pnr_sdc_flatten_routing_constrain_cb_timing(sdc_options.sdc_dir(),
module_manager,
L_device_rr_gsb,
grids,
switches);
}
}
/* Output Timing constraints for Programmable blocks */
if (true == sdc_options.constrain_grid()) {
print_pnr_sdc_constrain_grid_timing(sdc_options.sdc_dir(),
module_manager);
}
}

View File

@ -0,0 +1,24 @@
#ifndef PNR_SDC_WRITER_H
#define PNR_SDC_WRITER_H
#include <string>
#include "vtr_geometry.h"
#include "vpr_types.h"
#include "rr_blocks.h"
#include "module_manager.h"
#include "mux_library.h"
#include "circuit_library.h"
#include "sdc_option.h"
void print_pnr_sdc(const SdcOption& sdc_options,
const float& critical_path_delay,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_switch_inf>& switches,
const DeviceRRGSB& L_device_rr_gsb,
const ModuleManager& module_manager,
const MuxLibrary& mux_lib,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const bool& compact_routing_hierarchy);
#endif

View File

@ -0,0 +1,59 @@
/********************************************************************
* Useful APIs for SDC generator
*******************************************************************/
#include <ctime>
#include "pnr_sdc_writer.h"
#include "analysis_sdc_writer.h"
#include "sdc_api.h"
/********************************************************************
* Top-level function to launch SDC generator
*******************************************************************/
void fpga_sdc_generator(const SdcOption& sdc_options,
const float& critical_path_delay,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_switch_inf>& rr_switches,
const DeviceRRGSB& L_device_rr_gsb,
const std::vector<t_logical_block>& L_logical_blocks,
const vtr::Point<size_t>& device_size,
const std::vector<std::vector<t_grid_tile>>& L_grids,
const std::vector<t_block>& L_blocks,
const ModuleManager& module_manager,
const MuxLibrary& mux_lib,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const bool& compact_routing_hierarchy) {
vpr_printf(TIO_MESSAGE_INFO,
"SDC generator starts...\n");
/* Start time count */
clock_t t_start = clock();
if (true == sdc_options.generate_sdc_pnr()) {
print_pnr_sdc(sdc_options, critical_path_delay,
grids, rr_switches, L_device_rr_gsb,
module_manager, mux_lib,
circuit_lib, global_ports,
compact_routing_hierarchy);
}
if (true == sdc_options.generate_sdc_analysis()) {
print_analysis_sdc(sdc_options.sdc_dir(),
critical_path_delay,
L_device_rr_gsb,
L_logical_blocks, device_size, L_grids,
L_blocks,
module_manager,
circuit_lib, global_ports,
compact_routing_hierarchy);
}
/* End time count */
clock_t t_end = clock();
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
vpr_printf(TIO_MESSAGE_INFO,
"SDC generation took %g seconds\n",
run_time_sec);
}

View File

@ -0,0 +1,25 @@
#ifndef SDC_API_H
#define SDC_API_H
#include <vector>
#include "sdc_option.h"
#include "circuit_library.h"
#include "mux_library.h"
#include "module_manager.h"
void fpga_sdc_generator(const SdcOption& sdc_options,
const float& critical_path_delay,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_switch_inf>& rr_switches,
const DeviceRRGSB& L_device_rr_gsb,
const std::vector<t_logical_block>& L_logical_blocks,
const vtr::Point<size_t>& device_size,
const std::vector<std::vector<t_grid_tile>>& L_grids,
const std::vector<t_block>& L_blocks,
const ModuleManager& module_manager,
const MuxLibrary& mux_lib,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const bool& compact_routing_hierarchy);
#endif

View File

@ -0,0 +1,62 @@
/********************************************************************
* Most utilized function used to constrain memory cells in FPGA
* fabric using SDC commands
*******************************************************************/
#include "fpga_x2p_utils.h"
#include "sdc_writer_utils.h"
#include "sdc_memory_utils.h"
/********************************************************************
* Print SDC commands to disable outputs of all the configurable memory modules
* in a given module
* This function will be executed in a recursive way,
* using a Depth-First Search (DFS) strategy
* It will iterate over all the configurable children under each module
* and print a SDC command to disable its outputs
*******************************************************************/
void rec_print_pnr_sdc_disable_configurable_memory_module_output(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& parent_module,
const std::string& parent_module_path) {
/* For each configurable child, we will go one level down in priority */
for (size_t child_index = 0; child_index < module_manager.configurable_children(parent_module).size(); ++child_index) {
std::string child_module_path = parent_module_path;
ModuleId child_module_id = module_manager.configurable_children(parent_module)[child_index];
size_t child_instance_id = module_manager.configurable_child_instances(parent_module)[child_index];
if (true == module_manager.instance_name(parent_module, child_module_id, child_instance_id).empty()) {
/* Give a default name <module_name>_<instance_id>_ */
child_module_path += module_manager.module_name(child_module_id);
child_module_path += "_";
child_module_path += std::to_string(child_instance_id);
child_module_path += "_";
} else {
child_module_path += module_manager.instance_name(parent_module, child_module_id, child_instance_id);
}
child_module_path = format_dir_path(child_module_path);
rec_print_pnr_sdc_disable_configurable_memory_module_output(fp, module_manager,
child_module_id,
child_module_path);
}
/* If there is no configurable children any more, this is a leaf module, print a SDC command for disable timing */
if (0 < module_manager.configurable_children(parent_module).size()) {
return;
}
/* Validate file stream */
check_file_handler(fp);
/* Disable timing for each output port of this module */
for (const BasicPort& output_port : module_manager.module_ports_by_type(parent_module, ModuleManager::MODULE_OUTPUT_PORT)) {
for (const size_t& pin : output_port.pins()) {
BasicPort output_pin(output_port.get_name(), pin, pin);
fp << "set_disable_timing ";
fp << parent_module_path << generate_sdc_port(output_pin);
fp << std::endl;
}
}
}

View File

@ -0,0 +1,13 @@
#ifndef SDC_MEMORY_UTILS_H
#define SDC_MEMORY_UTILS_H
#include <fstream>
#include <string>
#include "module_manager.h"
void rec_print_pnr_sdc_disable_configurable_memory_module_output(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& parent_module,
const std::string& parent_module_path);
#endif

View File

@ -0,0 +1,121 @@
/********************************************************************
* Member functions for a data structure which includes all the options for the SDC generator
********************************************************************/
#include "sdc_option.h"
/********************************************************************
* Public Constructors
********************************************************************/
SdcOption::SdcOption(const std::string& sdc_dir) {
sdc_dir_ = sdc_dir;
constrain_global_port_ = false;
constrain_grid_ = false;
constrain_sb_ = false;
constrain_cb_ = false;
constrain_configurable_memory_outputs_ = false;
constrain_routing_multiplexer_outputs_ = false;
constrain_switch_block_outputs_ = false;
}
/********************************************************************
* Public accessors
********************************************************************/
std::string SdcOption::sdc_dir() const {
return sdc_dir_;
}
bool SdcOption::generate_sdc() const {
return generate_sdc_pnr() && generate_sdc_analysis_;
}
bool SdcOption::generate_sdc_pnr() const {
return constrain_global_port_
|| constrain_grid_
|| constrain_sb_
|| constrain_cb_
|| constrain_configurable_memory_outputs_
|| constrain_routing_multiplexer_outputs_
|| constrain_switch_block_outputs_;
}
bool SdcOption::generate_sdc_analysis() const {
return generate_sdc_analysis_;
}
bool SdcOption::constrain_global_port() const {
return constrain_global_port_;
}
bool SdcOption::constrain_grid() const {
return constrain_grid_;
}
bool SdcOption::constrain_sb() const {
return constrain_sb_;
}
bool SdcOption::constrain_cb() const {
return constrain_cb_;
}
bool SdcOption::constrain_configurable_memory_outputs() const {
return constrain_configurable_memory_outputs_;
}
bool SdcOption::constrain_routing_multiplexer_outputs() const {
return constrain_routing_multiplexer_outputs_;
}
bool SdcOption::constrain_switch_block_outputs() const {
return constrain_switch_block_outputs_;
}
/********************************************************************
* Public mutators
********************************************************************/
void SdcOption::set_sdc_dir(const std::string& sdc_dir) {
sdc_dir_ = sdc_dir;
}
void SdcOption::set_generate_sdc_pnr(const bool& generate_sdc_pnr) {
constrain_global_port_ = generate_sdc_pnr;
constrain_grid_ = generate_sdc_pnr;
constrain_sb_ = generate_sdc_pnr;
constrain_cb_ = generate_sdc_pnr;
constrain_configurable_memory_outputs_ = generate_sdc_pnr;
constrain_routing_multiplexer_outputs_ = generate_sdc_pnr;
constrain_switch_block_outputs_ = generate_sdc_pnr;
}
void SdcOption::set_generate_sdc_analysis(const bool& generate_sdc_analysis) {
generate_sdc_analysis_ = generate_sdc_analysis;
}
void SdcOption::set_constrain_global_port(const bool& constrain_global_port) {
constrain_global_port_ = constrain_global_port;
}
void SdcOption::set_constrain_grid(const bool& constrain_grid) {
constrain_grid_ = constrain_grid;
}
void SdcOption::set_constrain_sb(const bool& constrain_sb) {
constrain_sb_ = constrain_sb;
}
void SdcOption::set_constrain_cb(const bool& constrain_cb) {
constrain_cb_ = constrain_cb;
}
void SdcOption::set_constrain_configurable_memory_outputs(const bool& constrain_config_mem_outputs) {
constrain_configurable_memory_outputs_ = constrain_config_mem_outputs;
}
void SdcOption::set_constrain_routing_multiplexer_outputs(const bool& constrain_routing_mux_outputs) {
constrain_routing_multiplexer_outputs_ = constrain_routing_mux_outputs;
}
void SdcOption::set_constrain_switch_block_outputs(const bool& constrain_sb_outputs) {
constrain_switch_block_outputs_ = constrain_sb_outputs;
}

View File

@ -0,0 +1,48 @@
#ifndef SDC_OPTION_H
#define SDC_OPTION_H
/********************************************************************
* A data structure to include all the options for the SDC generator
********************************************************************/
#include <string>
class SdcOption {
public: /* Public Constructors */
SdcOption(const std::string& sdc_dir);
public: /* Public accessors */
std::string sdc_dir() const;
bool generate_sdc() const;
bool generate_sdc_pnr() const;
bool generate_sdc_analysis() const;
bool constrain_global_port() const;
bool constrain_grid() const;
bool constrain_sb() const;
bool constrain_cb() const;
bool constrain_configurable_memory_outputs() const;
bool constrain_routing_multiplexer_outputs() const;
bool constrain_switch_block_outputs() const;
public: /* Public mutators */
void set_sdc_dir(const std::string& sdc_dir);
void set_generate_sdc_pnr(const bool& generate_sdc_pnr);
void set_generate_sdc_analysis(const bool& generate_sdc_analysis);
void set_constrain_global_port(const bool& constrain_global_port);
void set_constrain_grid(const bool& constrain_grid);
void set_constrain_sb(const bool& constrain_sb);
void set_constrain_cb(const bool& constrain_cb);
void set_constrain_configurable_memory_outputs(const bool& constrain_config_mem_outputs);
void set_constrain_routing_multiplexer_outputs(const bool& constrain_routing_mux_outputs);
void set_constrain_switch_block_outputs(const bool& constrain_sb_outputs);
private: /* Internal data */
std::string sdc_dir_;
bool constrain_global_port_;
bool constrain_grid_;
bool constrain_sb_;
bool constrain_cb_;
bool constrain_configurable_memory_outputs_;
bool constrain_routing_multiplexer_outputs_;
bool constrain_switch_block_outputs_;
bool generate_sdc_analysis_;
};
#endif

View File

@ -0,0 +1,15 @@
#ifndef SDC_WRITER_NAMING_H
#define SDC_WRITER_NAMING_H
constexpr char* SDC_FILE_NAME_POSTFIX = ".sdc";
constexpr char* SDC_GLOBAL_PORTS_FILE_NAME = "global_ports.sdc";
constexpr char* SDC_BENCHMARK_ANALYSIS_FILE_NAME= "fpga_top_analysis.sdc";
constexpr char* SDC_DISABLE_CONFIG_MEM_OUTPUTS_FILE_NAME = "disable_configurable_memory_outputs.sdc";
constexpr char* SDC_DISABLE_MUX_OUTPUTS_FILE_NAME = "disable_routing_multiplexer_outputs.sdc";
constexpr char* SDC_DISABLE_SB_OUTPUTS_FILE_NAME = "disable_sb_outputs.sdc";
constexpr char* SDC_CB_FILE_NAME = "cb.sdc";
constexpr char* SDC_ANALYSIS_FILE_NAME = "fpga_top_analysis.sdc";
#endif

View File

@ -0,0 +1,172 @@
/********************************************************************
* This file include most utilized functions to be used in SDC writers
*******************************************************************/
#include <chrono>
#include <ctime>
#include <iomanip>
#include "fpga_x2p_utils.h"
#include "sdc_writer_utils.h"
/********************************************************************
* Write a head (description) in SDC file
*******************************************************************/
void print_sdc_file_header(std::fstream& fp,
const std::string& usage) {
check_file_handler(fp);
auto end = std::chrono::system_clock::now();
std::time_t end_time = std::chrono::system_clock::to_time_t(end);
fp << "#############################################" << std::endl;
fp << "#\tSynopsys Design Constraints (SDC)" << std::endl;
fp << "#\tFor FPGA fabric " << std::endl;
fp << "#\tDescription: " << usage << std::endl;
fp << "#\tAuthor: Xifan TANG " << std::endl;
fp << "#\tOrganization: University of Utah " << std::endl;
fp << "#\tDate: " << std::ctime(&end_time);
fp << "#############################################" << std::endl;
fp << std::endl;
}
/********************************************************************
* Write a port in SDC format
*******************************************************************/
std::string generate_sdc_port(const BasicPort& port) {
std::string sdc_line;
std::string size_str = "[" + std::to_string(port.get_lsb()) + ":" + std::to_string(port.get_msb()) + "]";
/* Only connection require a format of <port_name>[<lsb>:<msb>]
* others require a format of <port_type> [<lsb>:<msb>] <port_name>
*/
/* When LSB == MSB, we can use a simplified format <port_type>[<lsb>]*/
if ( 1 == port.get_width()) {
size_str = "[" + std::to_string(port.get_lsb()) + "]";
}
sdc_line = port.get_name() + size_str;
return sdc_line;
}
/********************************************************************
* Constrain a path between two ports of a module with a given maximum timing value
*******************************************************************/
void print_pnr_sdc_constrain_max_delay(std::fstream& fp,
const std::string& src_instance_name,
const std::string& src_port_name,
const std::string& des_instance_name,
const std::string& des_port_name,
const float& delay) {
/* Validate file stream */
check_file_handler(fp);
fp << "set_max_delay";
fp << " -from ";
fp << src_instance_name << "/";
fp << src_port_name;
fp << " -to ";
fp << des_instance_name << "/";
fp << des_port_name;
fp << " " << std::setprecision(10) << delay;
fp << std::endl;
}
/********************************************************************
* Constrain a path between two ports of a module with a given timing value
* Note: this function uses set_max_delay !!!
*******************************************************************/
void print_pnr_sdc_constrain_module_port2port_timing(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& input_parent_module_id,
const ModulePortId& module_input_port_id,
const ModuleId& output_parent_module_id,
const ModulePortId& module_output_port_id,
const float& tmax) {
print_pnr_sdc_constrain_max_delay(fp,
module_manager.module_name(input_parent_module_id),
generate_sdc_port(module_manager.module_port(input_parent_module_id, module_input_port_id)),
module_manager.module_name(output_parent_module_id),
generate_sdc_port(module_manager.module_port(output_parent_module_id, module_output_port_id)),
tmax);
}
/********************************************************************
* Disable timing for a port
*******************************************************************/
void print_sdc_disable_port_timing(std::fstream& fp,
const BasicPort& port) {
/* Validate file stream */
check_file_handler(fp);
fp << "set_disable_timing ";
fp << generate_sdc_port(port);
fp << std::endl;
}
/********************************************************************
* Set the input delay for a port in SDC format
* Note that the input delay will be bounded by a clock port
*******************************************************************/
void print_sdc_set_port_input_delay(std::fstream& fp,
const BasicPort& port,
const BasicPort& clock_port,
const float& delay) {
/* Validate file stream */
check_file_handler(fp);
fp << "set_input_delay ";
fp << "-clock ";
fp << generate_sdc_port(clock_port);
fp << " -max ";
fp << std::setprecision(10) << delay;
fp << " ";
fp << generate_sdc_port(port);
fp << std::endl;
}
/********************************************************************
* Set the output delay for a port in SDC format
* Note that the output delay will be bounded by a clock port
*******************************************************************/
void print_sdc_set_port_output_delay(std::fstream& fp,
const BasicPort& port,
const BasicPort& clock_port,
const float& delay) {
/* Validate file stream */
check_file_handler(fp);
fp << "set_output_delay ";
fp << "-clock ";
fp << generate_sdc_port(clock_port);
fp << " -max ";
fp << std::setprecision(10) << delay;
fp << " ";
fp << generate_sdc_port(port);
fp << std::endl;
}

View File

@ -0,0 +1,42 @@
#ifndef SDC_WRITER_UTILS_H
#define SDC_WRITER_UTILS_H
#include <fstream>
#include <string>
#include "device_port.h"
#include "module_manager.h"
void print_sdc_file_header(std::fstream& fp,
const std::string& usage);
std::string generate_sdc_port(const BasicPort& port);
void print_pnr_sdc_constrain_max_delay(std::fstream& fp,
const std::string& src_instance_name,
const std::string& src_port_name,
const std::string& des_instance_name,
const std::string& des_port_name,
const float& delay);
void print_pnr_sdc_constrain_module_port2port_timing(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& input_parent_module_id,
const ModulePortId& module_input_port_id,
const ModuleId& output_parent_module_id,
const ModulePortId& module_output_port_id,
const float& tmax);
void print_sdc_disable_port_timing(std::fstream& fp,
const BasicPort& port);
void print_sdc_set_port_input_delay(std::fstream& fp,
const BasicPort& port,
const BasicPort& clock_port,
const float& delay);
void print_sdc_set_port_output_delay(std::fstream& fp,
const BasicPort& port,
const BasicPort& clock_port,
const float& delay);
#endif

View File

@ -24,9 +24,11 @@
/* Include spice support headers*/
#include "linkedlist.h"
#include "circuit_library_utils.h"
#include "fpga_x2p_utils.h"
#include "fpga_x2p_backannotate_utils.h"
#include "fpga_x2p_setup.h"
#include "fpga_x2p_naming.h"
#include "mux_library_builder.h"
#include "build_device_module.h"
@ -36,6 +38,7 @@
#include "spice_api.h"
#include "verilog_api.h"
#include "sdc_api.h"
#include "fpga_bitstream.h"
#include "fpga_x2p_reserved_words.h"
@ -139,6 +142,30 @@ void vpr_fpga_x2p_tool_suites(t_vpr_setup vpr_setup,
vpr_setup, Arch, vpr_setup.FileNameOpts.CircuitName);
}
/* Run SDC Generator */
std::string src_dir = find_path_dir_name(std::string(vpr_setup.FileNameOpts.CircuitName));
/* Use current directory if there is not dir path given */
if (false == src_dir.empty()) {
src_dir = format_dir_path(src_dir);
}
SdcOption sdc_options(format_dir_path(src_dir + std::string(FPGA_X2P_DEFAULT_SDC_DIR)));
sdc_options.set_generate_sdc_pnr(TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_sdc_pnr);
sdc_options.set_generate_sdc_analysis(TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_sdc_analysis);
if (true == sdc_options.generate_sdc()) {
std::vector<CircuitPortId> global_ports = find_circuit_library_global_ports(Arch.spice->circuit_lib);
/* TODO: the critical path delay unit should be explicit! */
fpga_sdc_generator(sdc_options,
Arch.spice->spice_params.stimulate_params.vpr_crit_path_delay / 1e-9,
grids, rr_switches, device_rr_gsb,
L_logical_blocks, device_size, grids, L_blocks,
module_manager, mux_lib,
Arch.spice->circuit_lib, global_ports,
TRUE == vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy);
}
/* Xifan Tang: Bitstream Generator */
if ((TRUE == vpr_setup.FPGA_SPICE_Opts.BitstreamGenOpts.gen_bitstream)
&&(FALSE == vpr_setup.FPGA_SPICE_Opts.SpiceOpts.do_spice)

View File

@ -1480,6 +1480,10 @@ void update_one_grid_pack_net_num(int x, int y) {
assert ((NULL != type)
&& (EMPTY_TYPE != type)
&& (IO_TYPE != type));
/* Bypass grids whose offset is larger than 0 ! They have been processed! */
if (0 < grid[x][y].offset) {
return;
}
for (iblk = 0; iblk < grid[x][y].usage; iblk++) {
blk_id = grid[x][y].blocks[iblk];

View File

@ -758,6 +758,25 @@ std::string generate_grid_block_module_name(const std::string& prefix,
return module_name;
}
/*********************************************************************
* Generate the instance name for a programmable routing multiplexer module
* in a Switch Block
* To keep a unique name in each module and also consider unique routing modules,
* please do NOT include any coordinates in the naming!!!
* Consider only relative coordinate, such as side!
********************************************************************/
std::string generate_sb_mux_instance_name(const std::string& prefix,
const e_side& sb_side,
const size_t& track_id,
const std::string& postfix) {
std::string instance_name(prefix);
instance_name += Side(sb_side).to_string();
instance_name += std::string("_track_") + std::to_string(track_id);
instance_name += postfix;
return instance_name;
}
/*********************************************************************
* Generate the instance name for a configurable memory module in a Switch Block
* To keep a unique name in each module and also consider unique routing modules,
@ -776,6 +795,26 @@ std::string generate_sb_memory_instance_name(const std::string& prefix,
return instance_name;
}
/*********************************************************************
* Generate the instance name for a programmable routing multiplexer module
* in a Connection Block
* To keep a unique name in each module and also consider unique routing modules,
* please do NOT include any coordinates in the naming!!!
* Consider only relative coordinate, such as side!
********************************************************************/
std::string generate_cb_mux_instance_name(const std::string& prefix,
const e_side& cb_side,
const size_t& pin_id,
const std::string& postfix) {
std::string instance_name(prefix);
instance_name += Side(cb_side).to_string();
instance_name += std::string("_ipin_") + std::to_string(pin_id);
instance_name += postfix;
return instance_name;
}
/*********************************************************************
* Generate the instance name for a configurable memory module in a Connection Block
* To keep a unique name in each module and also consider unique routing modules,
@ -795,6 +834,38 @@ std::string generate_cb_memory_instance_name(const std::string& prefix,
return instance_name;
}
/*********************************************************************
* Generate the instance name for a programmable routing multiplexer
* module in a physical block of a grid
* To guarentee a unique name for pb_graph pin,
* the instance name includes the index of parent node
* as well as the port name and pin index of this pin
*
* Exceptions:
* For OUTPUT ports, due to hierarchical module organization,
* their parent nodes will be uniquified
* So, we should not add any index here
********************************************************************/
std::string generate_pb_mux_instance_name(const std::string& prefix,
t_pb_graph_pin* pb_graph_pin,
const std::string& postfix) {
std::string instance_name(prefix);
instance_name += std::string(pb_graph_pin->parent_node->pb_type->name);
if (IN_PORT == pb_graph_pin->port->type) {
instance_name += std::string("_");
instance_name += std::to_string(pb_graph_pin->parent_node->placement_index);
}
instance_name += std::string("_");
instance_name += std::string(pb_graph_pin->port->name);
instance_name += std::string("_");
instance_name += std::to_string(pb_graph_pin->pin_number);
instance_name += postfix;
return instance_name;
}
/*********************************************************************
* Generate the instance name for a configurable memory module in a
* physical block of a grid

View File

@ -13,6 +13,8 @@
#include "circuit_library.h"
#include "vpr_types.h"
constexpr char* FPGA_X2P_DEFAULT_SDC_DIR = "SDC";
std::string generate_mux_node_name(const size_t& node_level,
const bool& add_buffer_postfix);
@ -76,16 +78,30 @@ std::string generate_switch_block_module_name(const vtr::Point<size_t>& coordina
std::string generate_connection_block_module_name(const t_rr_type& cb_type,
const vtr::Point<size_t>& coordinate);
std::string generate_sb_mux_instance_name(const std::string& prefix,
const e_side& sb_side,
const size_t& track_id,
const std::string& postfix);
std::string generate_sb_memory_instance_name(const std::string& prefix,
const e_side& sb_side,
const size_t& track_id,
const std::string& postfix);
std::string generate_cb_mux_instance_name(const std::string& prefix,
const e_side& cb_side,
const size_t& pin_id,
const std::string& postfix);
std::string generate_cb_memory_instance_name(const std::string& prefix,
const e_side& cb_side,
const size_t& pin_id,
const std::string& postfix);
std::string generate_pb_mux_instance_name(const std::string& prefix,
t_pb_graph_pin* pb_graph_pin,
const std::string& postfix);
std::string generate_pb_memory_instance_name(const std::string& prefix,
t_pb_graph_pin* pb_graph_pin,
const std::string& postfix);

View File

@ -16,6 +16,10 @@ constexpr char* SWITCH_BLOCK_MEM_INSTANCE_PREFIX = "mem_";
constexpr char* CONNECTION_BLOCK_MEM_INSTANCE_PREFIX = "mem_";
constexpr char* MEMORY_MODULE_POSTFIX = "_mem";
/* Multiplexer naming constant strings */
constexpr char* GRID_MUX_INSTANCE_PREFIX = "mux_";
constexpr char* SWITCH_BLOCK_MUX_INSTANCE_PREFIX = "mux_";
constexpr char* CONNECTION_BLOCK_MUX_INSTANCE_PREFIX = "mux_";
/* Bitstream file strings */
constexpr char* BITSTREAM_XML_FILE_NAME_POSTFIX = "_bitstream.xml";

View File

@ -1119,6 +1119,22 @@ RRGSB build_rr_gsb(DeviceCoordinator& device_range,
if (0 == rr_gsb.get_chan_width(chan_side)) {
continue;
}
/* For bottom side: Skip IPIN collection if the offset of the grid is not zero!
* (it means this CB is in the middle of a grid (whose height > 1)
*
* | | | |
* | | | |
* | Grid | | Grid |
* +------------+ | |
* IPIN nodes IPIN nodes
* exist do NOT exist
*/
if ((BOTTOM == ipin_rr_node_grid_side) && (0 < grid[ix][iy].offset)) {
continue;
}
if ((TOP == ipin_rr_node_grid_side) && (grid[ix][iy].offset != grid[ix][iy].type->height - 1)) {
continue;
}
/* Collect IPIN rr_nodes*/
temp_ipin_rr_node = get_grid_side_pin_rr_nodes(&(num_temp_ipin_rr_nodes),
IPIN, ix, iy, ipin_rr_node_grid_side,

View File

@ -85,26 +85,6 @@ char* format_dir_path(char* dir_path) {
return ret;
}
/************************************************
* Format a path of directory:
* 1. Replace "\" with "/"
* 2. add a "/" if the string does not end with a "/"
***********************************************/
std::string format_dir_path(const std::string& dir_path) {
std::string ret = dir_path;
/* Replace "\" with "/" */
std::replace(ret.begin(), ret.end(), '\\', '/');
/* Complete the string with a "/" if it does not end with that */
if ('/' != ret.back()) {
ret.push_back('/');
}
return ret;
}
int try_access_file(char* file_path) {
/* F_OK checks existence and also R_OK, W_OK, X_OK,
* for readable, writable, excutable
@ -251,18 +231,6 @@ char* chomp_file_name_postfix(char* file_name) {
return ret;
}
void check_file_handler(std::fstream& fp) {
/* Make sure we have a valid file handler*/
/* Print out debugging information for if the file is not opened/created properly */
if (!fp.is_open() || !fp.good()) {
vpr_printf(TIO_MESSAGE_ERROR,
"(FILE:%s,LINE[%d])Failure in create file!\n",
__FILE__, __LINE__);
exit(1);
}
}
/* Print SRAM bits, typically in a comment line */
void fprint_commented_sram_bits(FILE* fp,
int num_sram_bits, int* sram_bits) {
@ -633,21 +601,6 @@ char* my_ito1hot(int in_int, int bin_len) {
return ret;
}
/* Convert an integer to an one-hot encoding integer array */
std::vector<size_t> my_ito1hot_vec(const size_t& in_int, const size_t& bin_len) {
/* Make sure we do not have any overflow! */
VTR_ASSERT ( (in_int <= bin_len) );
/* Initialize */
std::vector<size_t> ret(bin_len, 0);
if (bin_len == in_int) {
return ret; /* all zero case */
}
ret[in_int] = 1; /* Keep a good sequence of bits */
return ret;
}
/* Converter an integer to a binary string */
int* my_itobin_int(int in_int, int bin_len) {
@ -669,24 +622,6 @@ int* my_itobin_int(int in_int, int bin_len) {
return ret;
}
/* Converter an integer to a binary vector */
std::vector<size_t> my_itobin_vec(const size_t& in_int, const size_t& bin_len) {
std::vector<size_t> ret(bin_len, 0);
/* Make sure we do not have any overflow! */
VTR_ASSERT ( (in_int < pow(2., bin_len)) );
size_t temp = in_int;
for (size_t i = 0; i < bin_len; i++) {
if (1 == temp % 2) {
ret[i] = 1; /* Keep a good sequence of bits */
}
temp = temp / 2;
}
return ret;
}
/* Converter an integer to a binary string */
char* my_itobin(int in_int, int bin_len) {
char* ret = (char*) my_calloc (bin_len + 1, sizeof(char));

View File

@ -0,0 +1,135 @@
/********************************************************************
* Most utilized functions in FPGA X2P framework
*******************************************************************/
#include <string>
#include <algorithm>
#include "vtr_assert.h"
#include "fpga_x2p_utils.h"
/********************************************************************
* Format a directory path:
* 1. Replace "\" with "/"
* 2. add a "/" if the string does not end with a "/"
*******************************************************************/
std::string format_dir_path(const std::string& dir_path_to_format) {
std::string formatted_dir_path = dir_path_to_format;
char illegal_back_slash = '\\';
char legal_back_slash = '/';
#ifdef _WIN32
/* For windows OS, replace any '/' with '\' */
char illegal_back_slash = '/';
char legal_back_slash = '\\';
#endif
/* Replace "\" with "/" */
std::replace(formatted_dir_path.begin(), formatted_dir_path.end(), illegal_back_slash, legal_back_slash);
/* Add a back slash the string is not ended like this! */
if (legal_back_slash != formatted_dir_path.back()) {
formatted_dir_path.push_back(legal_back_slash);
}
return formatted_dir_path;
}
/********************************************************************
* Extract full file name from a full path of file
* For example: <dir_path>/<file_name>
* This function will return <file_name>
********************************************************************/
std::string find_path_file_name(const std::string& file_name) {
char back_slash = '/';
#ifdef _WIN32
/* For windows OS, replace any '/' with '\' */
char back_slash = '\\';
#endif
/* Find the last '/' in the string and return the left part */
size_t found = file_name.rfind(back_slash);
if (found != std::string::npos) {
return file_name.substr(found + 1);
}
/* Not found, return an empty string */
return std::string();
}
/********************************************************************
* Extract full directory path from a full path of file
* For example: <dir_path>/<file_name>
* This function will return <dir_path>
********************************************************************/
std::string find_path_dir_name(const std::string& file_name) {
char back_slash = '/';
#ifdef _WIN32
/* For windows OS, replace any '/' with '\' */
char back_slash = '\\';
#endif
/* Find the last '/' in the string and return the left part */
size_t found = file_name.rfind(back_slash);
if (found != std::string::npos) {
return file_name.substr(0, found);
}
/* Not found, return an empty string */
return std::string();
}
/********************************************************************
* Check if the file stream is valid
********************************************************************/
void check_file_handler(std::fstream& fp) {
/* Make sure we have a valid file handler*/
/* Print out debugging information for if the file is not opened/created properly */
if (!fp.is_open() || !fp.good()) {
vpr_printf(TIO_MESSAGE_ERROR,
"(FILE:%s,LINE[%d])Failure in create file!\n",
__FILE__, __LINE__);
exit(1);
}
}
/********************************************************************
* Convert an integer to an one-hot encoding integer array
********************************************************************/
std::vector<size_t> my_ito1hot_vec(const size_t& in_int, const size_t& bin_len) {
/* Make sure we do not have any overflow! */
VTR_ASSERT ( (in_int <= bin_len) );
/* Initialize */
std::vector<size_t> ret(bin_len, 0);
if (bin_len == in_int) {
return ret; /* all zero case */
}
ret[in_int] = 1; /* Keep a good sequence of bits */
return ret;
}
/********************************************************************
* Converter an integer to a binary vector
********************************************************************/
std::vector<size_t> my_itobin_vec(const size_t& in_int, const size_t& bin_len) {
std::vector<size_t> ret(bin_len, 0);
/* Make sure we do not have any overflow! */
VTR_ASSERT ( (in_int < pow(2., bin_len)) );
size_t temp = in_int;
for (size_t i = 0; i < bin_len; i++) {
if (1 == temp % 2) {
ret[i] = 1; /* Keep a good sequence of bits */
}
temp = temp / 2;
}
return ret;
}

View File

@ -3,16 +3,28 @@
#include <fstream>
#include <vector>
#include <string>
#include "my_free_fwd.h"
#include "rr_blocks_naming.h"
std::string format_dir_path(const std::string& dir_path_to_format);
void check_file_handler(std::fstream& fp);
std::vector<size_t> my_ito1hot_vec(const size_t& in_int, const size_t& bin_len);
std::string find_path_dir_name(const std::string& file_name);
std::string find_path_file_name(const std::string& file_name);
std::vector<size_t> my_itobin_vec(const size_t& in_int, const size_t& bin_len);
/* Old functions */
char* my_gettime();
char* format_dir_path(char* dir_path); /* TODO: TO BE REMOVED !!! */
std::string format_dir_path(const std::string& dir_path);
int try_access_file(char* file_path);
@ -66,14 +78,10 @@ t_spice_transistor_type* find_mosfet_tech_lib(t_spice_tech_lib tech_lib,
char* my_ito1hot(int in_int, int bin_len);
std::vector<size_t> my_ito1hot_vec(const size_t& in_int, const size_t& bin_len);
char* my_itobin(int in_int, int bin_len);
int* my_itobin_int(int in_int, int bin_len);
std::vector<size_t> my_itobin_vec(const size_t& in_int, const size_t& bin_len);
char* my_itoa(int input);
char* fpga_spice_create_one_subckt_filename(const char* file_name_prefix,

View File

@ -462,6 +462,15 @@ ModulePortId ModuleManager::add_port(const ModuleId& module,
return port;
}
/* Set a name for a module port */
void ModuleManager::set_module_port_name(const ModuleId& module, const ModulePortId& module_port,
const std::string& port_name) {
/* Validate the id of module port */
VTR_ASSERT( valid_module_port_id(module, module_port) );
ports_[module][module_port].set_name(port_name);
}
/* Set a name for a module */
void ModuleManager::set_module_name(const ModuleId& module, const std::string& name) {
/* Validate the id of module */

View File

@ -127,6 +127,8 @@ class ModuleManager {
/* Add a port to a module */
ModulePortId add_port(const ModuleId& module,
const BasicPort& port_info, const enum e_module_port_type& port_type);
/* Set a name for a module port */
void set_module_port_name(const ModuleId& module, const ModulePortId& module_port, const std::string& port_name);
/* Set a name for a module */
void set_module_name(const ModuleId& module, const std::string& name);
/* Set a port to be a wire */

View File

@ -36,7 +36,7 @@ ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager,
/* Add ports */
/* Find global ports and add one by one */
for (const auto& port : circuit_lib.model_global_ports(circuit_model, false)) {
BasicPort port_info(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
BasicPort port_info(circuit_lib.port_prefix(port), circuit_lib.port_size(port));
module_manager.add_port(module, port_info, ModuleManager::MODULE_GLOBAL_PORT);
}
@ -56,7 +56,7 @@ ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager,
/* Input ports (ignore all the global ports when searching the circuit_lib */
for (const auto& kv : port_type2type_map) {
for (const auto& port : circuit_lib.model_ports_by_type(circuit_model, kv.first, true)) {
BasicPort port_info(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
BasicPort port_info(circuit_lib.port_prefix(port), circuit_lib.port_size(port));
module_manager.add_port(module, port_info, kv.second);
}
}
@ -304,6 +304,35 @@ bool module_net_is_local_wire(const ModuleManager& module_manager,
return true;
}
/********************************************************************
* Identify if a net is an output short connection inside a module:
* The short connection is defined as the direct connection
* between two outputs port of the module
*
* module
* +-----------------------------+
* |
* src------>+--------------->|--->outputA
* | |
* | |
* +--------------->|--->outputB
* +-----------------------------+
*******************************************************************/
bool module_net_include_output_short_connection(const ModuleManager& module_manager,
const ModuleId& module_id, const ModuleNetId& module_net) {
/* Check all the sink modules of the net */
size_t contain_num_module_output = 0;
for (ModuleId sink_module : module_manager.net_sink_modules(module_id, module_net)) {
if (module_id == sink_module) {
contain_num_module_output++;
}
}
/* If we have found more than 1 module outputs, it indicated output short connection! */
return (1 < contain_num_module_output);
}
/********************************************************************
* Identify if a net is a local short connection inside a module:
* The short connection is defined as the direct connection
@ -368,7 +397,7 @@ void add_primitive_pb_type_module_nets(ModuleManager& module_manager,
BasicPort src_port = module_manager.module_port(pb_type_module, src_module_port_id);
/* Get the des module port id */
std::string des_module_port_name = circuit_lib.port_lib_name(pb_type_port->circuit_model_port);
std::string des_module_port_name = circuit_lib.port_prefix(pb_type_port->circuit_model_port);
ModulePortId des_module_port_id = module_manager.find_module_port(child_module, des_module_port_name);
VTR_ASSERT(ModulePortId::INVALID() != des_module_port_id);
BasicPort des_port = module_manager.module_port(child_module, des_module_port_id);
@ -529,11 +558,11 @@ void add_module_nets_between_logic_and_memory_sram_bus(ModuleManager& module_man
std::vector<std::string> logic_model_sram_port_names;
/* Regular sram port goes first */
for (CircuitPortId regular_sram_port : find_circuit_regular_sram_ports(circuit_lib, logic_model)) {
logic_model_sram_port_names.push_back(circuit_lib.port_lib_name(regular_sram_port));
logic_model_sram_port_names.push_back(circuit_lib.port_prefix(regular_sram_port));
}
/* Mode-select sram port goes first */
for (CircuitPortId mode_select_sram_port : find_circuit_mode_select_sram_ports(circuit_lib, logic_model)) {
logic_model_sram_port_names.push_back(circuit_lib.port_lib_name(mode_select_sram_port));
logic_model_sram_port_names.push_back(circuit_lib.port_prefix(mode_select_sram_port));
}
/* Find the port ids in the memory */
std::vector<ModulePortId> logic_module_sram_port_ids;
@ -565,11 +594,11 @@ void add_module_nets_between_logic_and_memory_sram_bus(ModuleManager& module_man
std::vector<std::string> logic_model_sramb_port_names;
/* Regular sram port goes first */
for (CircuitPortId regular_sram_port : find_circuit_regular_sram_ports(circuit_lib, logic_model)) {
logic_model_sramb_port_names.push_back(circuit_lib.port_lib_name(regular_sram_port) + std::string("_inv"));
logic_model_sramb_port_names.push_back(circuit_lib.port_prefix(regular_sram_port) + std::string("_inv"));
}
/* Mode-select sram port goes first */
for (CircuitPortId mode_select_sram_port : find_circuit_mode_select_sram_ports(circuit_lib, logic_model)) {
logic_model_sramb_port_names.push_back(circuit_lib.port_lib_name(mode_select_sram_port) + std::string("_inv"));
logic_model_sramb_port_names.push_back(circuit_lib.port_prefix(mode_select_sram_port) + std::string("_inv"));
}
/* Find the port ids in the memory */
std::vector<ModulePortId> logic_module_sramb_port_ids;

View File

@ -50,6 +50,9 @@ void add_pb_type_ports_to_module_manager(ModuleManager& module_manager,
bool module_net_is_local_wire(const ModuleManager& module_manager,
const ModuleId& module_id, const ModuleNetId& module_net);
bool module_net_include_output_short_connection(const ModuleManager& module_manager,
const ModuleId& module_id, const ModuleNetId& module_net);
bool module_net_include_local_short_connection(const ModuleManager& module_manager,
const ModuleId& module_id, const ModuleNetId& module_net);

View File

@ -334,4 +334,25 @@ size_t find_switch_block_num_shared_conf_bits(t_sram_orgz_info* cur_sram_orgz_in
return num_shared_conf_bits;
}
/********************************************************************
* Find if a X-direction or Y-direction Connection Block contains
* routing tracks only (zero configuration bits and routing multiplexers)
*******************************************************************/
bool connection_block_contain_only_routing_tracks(const RRGSB& rr_gsb,
const t_rr_type& cb_type) {
bool routing_track_only = true;
/* Find routing multiplexers on the sides of a Connection block where IPIN nodes locate */
std::vector<enum e_side> cb_sides = rr_gsb.get_cb_ipin_sides(cb_type);
for (size_t side = 0; side < cb_sides.size(); ++side) {
enum e_side cb_ipin_side = cb_sides[side];
Side side_manager(cb_ipin_side);
if (0 < rr_gsb.get_num_ipin_nodes(cb_ipin_side)) {
routing_track_only = false;
break;
}
}
return routing_track_only;
}

View File

@ -51,4 +51,7 @@ size_t find_switch_block_num_shared_conf_bits(t_sram_orgz_info* cur_sram_orgz_in
const std::vector<t_switch_inf>& rr_switches,
const RRGSB& rr_gsb);
bool connection_block_contain_only_routing_tracks(const RRGSB& rr_gsb,
const t_rr_type& cb_type);
#endif

View File

@ -10,6 +10,7 @@
#include "vtr_assert.h"
#include "util.h"
#include "mux_utils.h"
#include "rr_blocks_utils.h"
#include "fpga_x2p_reserved_words.h"
#include "fpga_x2p_types.h"
#include "fpga_x2p_naming.h"
@ -247,7 +248,7 @@ void build_connection_block_interc_bitstream(BitstreamManager& bitstream_manager
/* No bitstream generation required by a special direct connection*/
} else if (1 < src_rr_node->fan_in) {
/* Create the block denoting the memory instances that drives this node in Switch Block */
std::string mem_block_name = generate_cb_memory_instance_name(CONNECTION_BLOCK_MEM_INSTANCE_PREFIX, rr_gsb.get_ipin_node_grid_side(cb_ipin_side, ipin_index), src_rr_node->ptc_num, std::string(""));
std::string mem_block_name = generate_cb_memory_instance_name(CONNECTION_BLOCK_MEM_INSTANCE_PREFIX, rr_gsb.get_ipin_node_grid_side(cb_ipin_side, ipin_index), ipin_index, std::string(""));
ConfigBlockId mux_mem_block = bitstream_manager.add_block(mem_block_name);
bitstream_manager.add_child_block(cb_configurable_block, mux_mem_block);
/* This is a routing multiplexer! Generate bitstream */
@ -318,8 +319,11 @@ void build_connection_block_bitstreams(BitstreamManager& bitstream_manager,
* Some of them do NOT exist due to heterogeneous blocks (height > 1)
* We will skip those modules
*/
if ( (TRUE != is_cb_exist(cb_type, rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)))
|| (true != rr_gsb.is_cb_exist(cb_type))) {
if (false == rr_gsb.is_cb_exist(cb_type)) {
continue;
}
/* Skip if the cb does not contain any configuration bits! */
if (true == connection_block_contain_only_routing_tracks(rr_gsb, cb_type)) {
continue;
}
/* Create a block for the bitstream which corresponds to the Switch block */
@ -376,13 +380,13 @@ void build_routing_bitstream(BitstreamManager& bitstream_manager,
* To organize the bitstream in blocks, we create a block for each connection block
* and give names which are same as they are in top-level module managers
*/
vpr_printf(TIO_MESSAGE_INFO,"Generating bitstream for X-directionConnection blocks ...\n");
vpr_printf(TIO_MESSAGE_INFO,"Generating bitstream for X-direction Connection blocks ...\n");
build_connection_block_bitstreams(bitstream_manager, top_configurable_block, module_manager,
circuit_lib, mux_lib, rr_switches, L_rr_node,
L_device_rr_gsb, CHANX);
vpr_printf(TIO_MESSAGE_INFO,"Generating bitstream for Y-directionConnection blocks ...\n");
vpr_printf(TIO_MESSAGE_INFO,"Generating bitstream for Y-direction Connection blocks ...\n");
build_connection_block_bitstreams(bitstream_manager, top_configurable_block, module_manager,
circuit_lib, mux_lib, rr_switches, L_rr_node,

View File

@ -75,12 +75,6 @@ ModuleManager build_device_module_graph(const t_vpr_setup& vpr_setup,
arch.sram_inf.verilog_sram_inf_orgz->spice_model);
config_circuit_models_sram_port_to_default_sram_model(arch.spice->circuit_lib, sram_model);
/* Create a vector of segments. TODO: should come from DeviceContext */
std::vector<t_segment_inf> L_segment_vec;
for (int i = 0; i < arch.num_segments; ++i) {
L_segment_vec.push_back(arch.Segments[i]);
}
/* Add constant generator modules: VDD and GND */
build_constant_generator_modules(module_manager);
@ -88,7 +82,7 @@ ModuleManager build_device_module_graph(const t_vpr_setup& vpr_setup,
* This should be done prior to other steps in this function,
* because they will be instanciated by other primitive modules
*/
build_user_defined_modules(module_manager, arch.spice->circuit_lib, L_segment_vec);
build_user_defined_modules(module_manager, arch.spice->circuit_lib);
/* Build elmentary modules */
build_essential_modules(module_manager, arch.spice->circuit_lib);
@ -103,7 +97,7 @@ ModuleManager build_device_module_graph(const t_vpr_setup& vpr_setup,
build_lut_modules(module_manager, arch.spice->circuit_lib);
/* Build wire modules */
build_wire_modules(module_manager, arch.spice->circuit_lib, L_segment_vec);
build_wire_modules(module_manager, arch.spice->circuit_lib);
/* Build memory modules */
build_memory_modules(module_manager, mux_lib, arch.spice->circuit_lib,
@ -132,6 +126,15 @@ ModuleManager build_device_module_graph(const t_vpr_setup& vpr_setup,
arch.sram_inf.verilog_sram_inf_orgz->type, sram_model,
TRUE == vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy);
/* Now a critical correction has to be done!
* In the module construction, we always use prefix of ports because they are binded
* to the ports in architecture description (logic blocks etc.)
* To interface with standard cell, we should
* rename the ports of primitive modules using lib_name instead of prefix
* (which have no children and are probably linked to a standard cell!)
*/
rename_primitive_module_port_names(module_manager, arch.spice->circuit_lib);
/* End time count */
clock_t t_end = clock();

View File

@ -155,6 +155,12 @@ void build_essential_modules(ModuleManager& module_manager,
"Building essential (inverter/buffer/logic gate) modules...");
for (const auto& circuit_model : circuit_lib.models()) {
/* Add essential modules upon on demand: only when it is not yet in the module library */
ModuleId module = module_manager.find_module(circuit_lib.model_name(circuit_model));
if (true == module_manager.valid_module_id(module)) {
continue;
}
if (SPICE_MODEL_INVBUF == circuit_lib.model_type(circuit_model)) {
build_invbuf_module(module_manager, circuit_lib, circuit_model);
continue;
@ -184,8 +190,7 @@ void build_essential_modules(ModuleManager& module_manager,
* to the module_manager
********************************************************************/
void build_user_defined_modules(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const std::vector<t_segment_inf>& routing_segments) {
const CircuitLibrary& circuit_lib) {
/* Start time count */
clock_t t_start = clock();
@ -196,7 +201,7 @@ void build_user_defined_modules(ModuleManager& module_manager,
for (const auto& model : circuit_lib.models()) {
/* We only care about user-defined models */
if ( (true == circuit_lib.model_verilog_netlist(model).empty())
&& (true == circuit_lib.model_verilog_netlist(model).empty()) ) {
&& (true == circuit_lib.model_spice_netlist(model).empty()) ) {
continue;
}
/* Skip Routing channel wire models because they need a different name. Do it later */
@ -209,33 +214,6 @@ void build_user_defined_modules(ModuleManager& module_manager,
add_circuit_model_to_module_manager(module_manager, circuit_lib, model);
}
/* Register the routing channel wires */
for (const auto& seg : routing_segments) {
VTR_ASSERT( CircuitModelId::INVALID() != seg.circuit_model);
VTR_ASSERT( SPICE_MODEL_CHAN_WIRE == circuit_lib.model_type(seg.circuit_model));
/* We care only user-defined circuit models */
if ( (circuit_lib.model_verilog_netlist(seg.circuit_model).empty())
&& (circuit_lib.model_verilog_netlist(seg.circuit_model).empty()) ) {
continue;
}
/* Give a unique name for subckt of wire_model of segment,
* circuit_model name is unique, and segment id is unique as well
*/
std::string segment_wire_subckt_name = generate_segment_wire_subckt_name(circuit_lib.model_name(seg.circuit_model), &seg - &routing_segments[0]);
/* Create a Verilog Module based on the circuit model, and add to module manager */
ModuleId module_id = add_circuit_model_to_module_manager(module_manager, circuit_lib, seg.circuit_model, segment_wire_subckt_name);
/* Find the output port*/
std::vector<CircuitPortId> output_ports = circuit_lib.model_ports_by_type(seg.circuit_model, SPICE_MODEL_PORT_OUTPUT, true);
/* Make sure the port size is what we want */
VTR_ASSERT (1 == circuit_lib.port_size(output_ports[0]));
/* Add a mid-output port to the module */
BasicPort module_mid_output_port(generate_segment_wire_mid_output_name(circuit_lib.port_lib_name(output_ports[0])), circuit_lib.port_size(output_ports[0]));
module_manager.add_port(module_id, module_mid_output_port, ModuleManager::MODULE_OUTPUT_PORT);
}
/* End time count */
clock_t t_end = clock();
@ -288,3 +266,40 @@ void build_constant_generator_modules(ModuleManager& module_manager) {
"took %.2g seconds\n",
run_time_sec);
}
/*********************************************************************
* This function will rename the ports of primitive modules
* using lib_name instead of prefix
* Primitive modules are defined as those modules in the module manager
* which have user defined netlists
********************************************************************/
void rename_primitive_module_port_names(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib) {
for (const CircuitModelId& model : circuit_lib.models()) {
/* We only care about user-defined models */
if ( (true == circuit_lib.model_verilog_netlist(model).empty())
&& (true == circuit_lib.model_spice_netlist(model).empty()) ) {
continue;
}
/* Skip Routing channel wire models because they need a different name. Do it later */
if (SPICE_MODEL_CHAN_WIRE == circuit_lib.model_type(model)) {
continue;
}
/* Find the module in module manager */
ModuleId module = module_manager.find_module(circuit_lib.model_name(model));
/* We must find one! */
VTR_ASSERT(true == module_manager.valid_module_id(module));
/* Rename all the ports to use lib_name! */
for (const CircuitPortId& model_port : circuit_lib.model_ports(model)) {
/* Find the module port in module manager. We used prefix when creating the ports */
ModulePortId module_port = module_manager.find_module_port(module, circuit_lib.port_prefix(model_port));
/* We must find one! */
VTR_ASSERT(true == module_manager.valid_module_port_id(module, module_port));
/* Name it with lib_name */
module_manager.set_module_port_name(module, module_port, circuit_lib.port_lib_name(model_port));
}
}
}

View File

@ -8,9 +8,11 @@ void build_essential_modules(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib);
void build_user_defined_modules(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const std::vector<t_segment_inf>& routing_segments);
const CircuitLibrary& circuit_lib);
void build_constant_generator_modules(ModuleManager& module_manager);
void rename_primitive_module_port_names(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib);
#endif

View File

@ -369,7 +369,7 @@ void build_primitive_block_module(ModuleManager& module_manager,
for (auto port : primitive_model_inout_ports) {
BasicPort module_port(generate_fpga_global_io_port_name(std::string(gio_inout_prefix), circuit_lib, primitive_model), circuit_lib.port_size(port));
ModulePortId primitive_gpio_port_id = module_manager.add_port(primitive_module, module_port, ModuleManager::MODULE_GPIO_PORT);
ModulePortId logic_gpio_port_id = module_manager.find_module_port(logic_module, circuit_lib.port_lib_name(port));
ModulePortId logic_gpio_port_id = module_manager.find_module_port(logic_module, circuit_lib.port_prefix(port));
BasicPort logic_gpio_port = module_manager.module_port(logic_module, logic_gpio_port_id);
VTR_ASSERT(logic_gpio_port.get_width() == module_port.get_width());
@ -483,7 +483,7 @@ void add_module_pb_graph_pin_interc(ModuleManager& module_manager,
}
/* Initialize the interconnection type that will be physically implemented in module */
enum e_interconnect verilog_interc_type = determine_actual_pb_interc_type(cur_interc, fan_in);
enum e_interconnect interc_type = determine_actual_pb_interc_type(cur_interc, fan_in);
/* Find input ports of the wire module */
std::vector<CircuitPortId> interc_model_inputs = circuit_lib.model_ports_by_type(cur_interc->circuit_model, SPICE_MODEL_PORT_INPUT, true); /* the last argument to guarantee that we ignore any global inputs */
@ -497,7 +497,7 @@ void add_module_pb_graph_pin_interc(ModuleManager& module_manager,
/* Branch on the type of physical implementation,
* We add instances of programmable interconnection
*/
switch (verilog_interc_type) {
switch (interc_type) {
case DIRECT_INTERC: {
/* Ensure direct interc has only one fan-in */
VTR_ASSERT(1 == fan_in);
@ -521,7 +521,7 @@ void add_module_pb_graph_pin_interc(ModuleManager& module_manager,
/* Get the instance id and add an instance of wire */
size_t wire_instance = module_manager.num_instance(pb_module, wire_module);
module_manager.add_child_module(pb_module, wire_module);
/* Ensure input and output ports of the wire model has only 1 pin respectively */
VTR_ASSERT(1 == circuit_lib.port_size(interc_model_inputs[0]));
VTR_ASSERT(1 == circuit_lib.port_size(interc_model_outputs[0]));
@ -530,7 +530,7 @@ void add_module_pb_graph_pin_interc(ModuleManager& module_manager,
/* First net is to connect input of src_pb_graph_node to input of the wire module */
add_module_pb_graph_pin2pin_net(module_manager, pb_module,
wire_module, wire_instance,
circuit_lib.port_lib_name(interc_model_inputs[0]),
circuit_lib.port_prefix(interc_model_inputs[0]),
0, /* wire input port has only 1 pin */
module_name_prefix,
src_pb_graph_pin,
@ -539,7 +539,7 @@ void add_module_pb_graph_pin_interc(ModuleManager& module_manager,
/* Second net is to connect output of the wire module to output of des_pb_graph_pin */
add_module_pb_graph_pin2pin_net(module_manager, pb_module,
wire_module, wire_instance,
circuit_lib.port_lib_name(interc_model_outputs[0]),
circuit_lib.port_prefix(interc_model_outputs[0]),
0, /* wire output port has only 1 pin */
module_name_prefix,
des_pb_graph_pin,
@ -559,6 +559,11 @@ void add_module_pb_graph_pin_interc(ModuleManager& module_manager,
/* Instanciate the MUX */
size_t mux_instance = module_manager.num_instance(pb_module, mux_module);
module_manager.add_child_module(pb_module, mux_module);
/* Give an instance name: this name should be consistent with the block name given in SDC generator,
* If you want to bind the SDC generation to modules
*/
std::string mux_instance_name = generate_pb_mux_instance_name(GRID_MUX_INSTANCE_PREFIX, des_pb_graph_pin, std::string(""));
module_manager.set_child_instance_name(pb_module, mux_module, mux_instance, mux_instance_name);
/* Instanciate a memory module for the MUX */
std::string mux_mem_module_name = generate_mux_subckt_name(circuit_lib,
@ -610,7 +615,7 @@ void add_module_pb_graph_pin_interc(ModuleManager& module_manager,
/* Add a net, set its source and sink */
add_module_pb_graph_pin2pin_net(module_manager, pb_module,
mux_module, mux_instance,
circuit_lib.port_lib_name(interc_model_inputs[0]),
circuit_lib.port_prefix(interc_model_inputs[0]),
mux_input_pin_id,
module_name_prefix,
src_pb_graph_pin,
@ -623,7 +628,7 @@ void add_module_pb_graph_pin_interc(ModuleManager& module_manager,
/* Add a net to wire the output of the multiplexer to des_pb_graph_pin */
add_module_pb_graph_pin2pin_net(module_manager, pb_module,
mux_module, mux_instance,
circuit_lib.port_lib_name(interc_model_outputs[0]),
circuit_lib.port_prefix(interc_model_outputs[0]),
0, /* MUX should have only 1 pin in its output port */
module_name_prefix,
des_pb_graph_pin,
@ -921,7 +926,7 @@ void rec_build_physical_block_modules(ModuleManager& module_manager,
/* Add the memory module as a child of primitive module */
module_manager.add_child_module(pb_module, child_pb_module);
/* Set an instance name to bind to a block in bitstream generation */
/* Set an instance name to bind to a block in bitstream generation and SDC generation! */
std::string child_pb_instance_name = generate_physical_block_instance_name(pb_module_name_prefix, &(physical_pb_type->modes[physical_mode_index].pb_type_children[ichild]), inst);
module_manager.set_child_instance_name(pb_module, child_pb_module, child_instance_id, child_pb_instance_name);

View File

@ -82,36 +82,36 @@ void build_lut_module(ModuleManager& module_manager,
/* Add each global port */
for (const auto& port : lut_global_ports) {
/* Configure each global port */
BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
BasicPort global_port(circuit_lib.port_prefix(port), circuit_lib.port_size(port));
module_manager.add_port(lut_module, global_port, ModuleManager::MODULE_GLOBAL_PORT);
}
/* Add each input port */
for (const auto& port : lut_input_ports) {
BasicPort input_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
BasicPort input_port(circuit_lib.port_prefix(port), circuit_lib.port_size(port));
module_manager.add_port(lut_module, input_port, ModuleManager::MODULE_INPUT_PORT);
/* Set the port to be wire-connection */
module_manager.set_port_is_wire(lut_module, input_port.get_name(), true);
}
/* Add each output port */
for (const auto& port : lut_output_ports) {
BasicPort output_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
BasicPort output_port(circuit_lib.port_prefix(port), circuit_lib.port_size(port));
module_manager.add_port(lut_module, output_port, ModuleManager::MODULE_OUTPUT_PORT);
/* Set the port to be wire-connection */
module_manager.set_port_is_wire(lut_module, output_port.get_name(), true);
}
/* Add each regular (not mode select) SRAM port */
for (const auto& port : lut_regular_sram_ports) {
BasicPort mem_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
BasicPort mem_port(circuit_lib.port_prefix(port), circuit_lib.port_size(port));
module_manager.add_port(lut_module, mem_port, ModuleManager::MODULE_INPUT_PORT);
BasicPort mem_inv_port(std::string(circuit_lib.port_lib_name(port) + "_inv"), circuit_lib.port_size(port));
BasicPort mem_inv_port(std::string(circuit_lib.port_prefix(port) + "_inv"), circuit_lib.port_size(port));
module_manager.add_port(lut_module, mem_inv_port, ModuleManager::MODULE_INPUT_PORT);
}
/* Add each mode-select SRAM port */
for (const auto& port : lut_mode_select_sram_ports) {
BasicPort mem_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
BasicPort mem_port(circuit_lib.port_prefix(port), circuit_lib.port_size(port));
module_manager.add_port(lut_module, mem_port, ModuleManager::MODULE_INPUT_PORT);
BasicPort mem_inv_port(std::string(circuit_lib.port_lib_name(port) + "_inv"), circuit_lib.port_size(port));
BasicPort mem_inv_port(std::string(circuit_lib.port_prefix(port) + "_inv"), circuit_lib.port_size(port));
module_manager.add_port(lut_module, mem_inv_port, ModuleManager::MODULE_INPUT_PORT);
}
@ -149,7 +149,7 @@ void build_lut_module(ModuleManager& module_manager,
std::string tri_state_map = circuit_lib.port_tri_state_map(lut_input_ports[0]);
size_t mode_select_port_lsb = 0;
for (const auto& pin : circuit_lib.pins(lut_input_ports[0])) {
ModulePortId lut_module_input_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_lib_name(lut_input_ports[0]));
ModulePortId lut_module_input_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_prefix(lut_input_ports[0]));
VTR_ASSERT(true == module_manager.valid_module_port_id(lut_module, lut_module_input_port_id));
/* Create a module net for the connection */
@ -222,13 +222,13 @@ void build_lut_module(ModuleManager& module_manager,
ModuleNetId gate_sram_net = module_manager.create_module_net(lut_module);
/* Find the module port id of the SRAM port of LUT module */
ModulePortId lut_module_mode_select_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_lib_name(lut_mode_select_sram_ports[0]));
ModulePortId lut_module_mode_select_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_prefix(lut_mode_select_sram_ports[0]));
VTR_ASSERT(true == module_manager.valid_module_port_id(lut_module, lut_module_mode_select_port_id));
/* Set the source of the net to an mode-select SRAM port of the LUT module */
module_manager.add_module_net_source(lut_module, gate_sram_net, lut_module, 0, lut_module_mode_select_port_id, mode_select_port_lsb);
/* Find the module port id of the SRAM port of LUT module */
ModulePortId gate_module_input0_port_id = module_manager.find_module_port(gate_module, circuit_lib.port_lib_name(gate_input_ports[0]));
ModulePortId gate_module_input0_port_id = module_manager.find_module_port(gate_module, circuit_lib.port_prefix(gate_input_ports[0]));
VTR_ASSERT(true == module_manager.valid_module_port_id(gate_module, gate_module_input0_port_id));
/* Set the sink of the net to an input[0] port of the gate module */
VTR_ASSERT(1 == module_manager.module_port(gate_module, gate_module_input0_port_id).get_width());
@ -237,7 +237,7 @@ void build_lut_module(ModuleManager& module_manager,
}
/* Use the existing net to connect to the input[1] port of the gate module */
ModulePortId gate_module_input1_port_id = module_manager.find_module_port(gate_module, circuit_lib.port_lib_name(gate_input_ports[1]));
ModulePortId gate_module_input1_port_id = module_manager.find_module_port(gate_module, circuit_lib.port_prefix(gate_input_ports[1]));
VTR_ASSERT(true == module_manager.valid_module_port_id(gate_module, gate_module_input1_port_id));
VTR_ASSERT(1 == module_manager.module_port(gate_module, gate_module_input1_port_id).get_width());
for (const size_t& gate_pin : module_manager.module_port(gate_module, gate_module_input1_port_id).pins()) {
@ -246,7 +246,7 @@ void build_lut_module(ModuleManager& module_manager,
/* Create a module net for the output connection */
ModuleNetId gate_output_net = module_manager.create_module_net(lut_module);
ModulePortId gate_module_output_port_id = module_manager.find_module_port(gate_module, circuit_lib.port_lib_name(gate_output_ports[0]));
ModulePortId gate_module_output_port_id = module_manager.find_module_port(gate_module, circuit_lib.port_prefix(gate_output_ports[0]));
VTR_ASSERT(true == module_manager.valid_module_port_id(gate_module, gate_module_output_port_id));
BasicPort gate_module_output_port = module_manager.module_port(gate_module, gate_module_output_port_id);
VTR_ASSERT(1 == gate_module_output_port.get_width());
@ -326,7 +326,7 @@ void build_lut_module(ModuleManager& module_manager,
* 3. Data input of LUT MUX module to SRAM port of LUT
* 4. Data output of LUT MUX module to output ports of LUT
*/
ModulePortId lut_mux_sram_port_id = module_manager.find_module_port(lut_mux_module, circuit_lib.port_lib_name(lut_regular_sram_ports[0]));
ModulePortId lut_mux_sram_port_id = module_manager.find_module_port(lut_mux_module, circuit_lib.port_prefix(lut_regular_sram_ports[0]));
BasicPort lut_mux_sram_port = module_manager.module_port(lut_mux_module, lut_mux_sram_port_id);
VTR_ASSERT(lut_mux_sram_port.get_width() == lut_mux_sram_nets.size());
/* Wire the port to lut_mux_sram_net */
@ -334,7 +334,7 @@ void build_lut_module(ModuleManager& module_manager,
module_manager.add_module_net_sink(lut_module, lut_mux_sram_nets[pin], lut_mux_module, lut_mux_instance, lut_mux_sram_port_id, pin);
}
ModulePortId lut_mux_sram_inv_port_id = module_manager.find_module_port(lut_mux_module, std::string(circuit_lib.port_lib_name(lut_regular_sram_ports[0]) + "_inv"));
ModulePortId lut_mux_sram_inv_port_id = module_manager.find_module_port(lut_mux_module, std::string(circuit_lib.port_prefix(lut_regular_sram_ports[0]) + "_inv"));
BasicPort lut_mux_sram_inv_port = module_manager.module_port(lut_mux_module, lut_mux_sram_inv_port_id);
VTR_ASSERT(lut_mux_sram_inv_port.get_width() == lut_mux_sram_inv_nets.size());
/* Wire the port to lut_mux_sram_net */
@ -351,9 +351,9 @@ void build_lut_module(ModuleManager& module_manager,
* |
* net
*/
ModulePortId lut_sram_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_lib_name(lut_regular_sram_ports[0]));
ModulePortId lut_sram_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_prefix(lut_regular_sram_ports[0]));
BasicPort lut_sram_port = module_manager.module_port(lut_module, lut_sram_port_id);
ModulePortId lut_mux_input_port_id = module_manager.find_module_port(lut_mux_module, circuit_lib.port_lib_name(lut_input_ports[0]));
ModulePortId lut_mux_input_port_id = module_manager.find_module_port(lut_mux_module, circuit_lib.port_prefix(lut_input_ports[0]));
BasicPort lut_mux_input_port = module_manager.module_port(lut_mux_module, lut_mux_input_port_id);
VTR_ASSERT(lut_mux_input_port.get_width() == lut_sram_port.get_width());
/* Wire the port to lut_mux_sram_net */
@ -364,9 +364,9 @@ void build_lut_module(ModuleManager& module_manager,
}
for (const auto& port : lut_output_ports) {
ModulePortId lut_output_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_lib_name(port));
ModulePortId lut_output_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_prefix(port));
BasicPort lut_output_port = module_manager.module_port(lut_module, lut_output_port_id);
ModulePortId lut_mux_output_port_id = module_manager.find_module_port(lut_mux_module, circuit_lib.port_lib_name(port));
ModulePortId lut_mux_output_port_id = module_manager.find_module_port(lut_mux_module, circuit_lib.port_prefix(port));
BasicPort lut_mux_output_port = module_manager.module_port(lut_mux_module, lut_mux_output_port_id);
VTR_ASSERT(lut_mux_output_port.get_width() == lut_output_port.get_width());
/* Wire the port to lut_mux_sram_net */

View File

@ -48,8 +48,8 @@ void add_module_input_nets_to_mem_modules(ModuleManager& module_manager,
const size_t& child_instance) {
/* Wire inputs of parent module to inputs of child modules */
for (const auto& port : circuit_ports) {
ModulePortId src_port_id = module_manager.find_module_port(mem_module, circuit_lib.port_lib_name(port));
ModulePortId sink_port_id = module_manager.find_module_port(child_module, circuit_lib.port_lib_name(port));
ModulePortId src_port_id = module_manager.find_module_port(mem_module, circuit_lib.port_prefix(port));
ModulePortId sink_port_id = module_manager.find_module_port(child_module, circuit_lib.port_prefix(port));
for (size_t pin_id = 0; pin_id < module_manager.module_port(mem_module, sink_port_id).pins().size(); ++pin_id) {
ModuleNetId net = module_manager.create_module_net(mem_module);
/* Source pin is shifted by the number of memories */
@ -82,8 +82,8 @@ void add_module_output_nets_to_mem_modules(ModuleManager& module_manager,
const size_t& child_instance) {
/* Wire inputs of parent module to inputs of child modules */
for (const auto& port : circuit_ports) {
ModulePortId src_port_id = module_manager.find_module_port(child_module, circuit_lib.port_lib_name(port));
ModulePortId sink_port_id = module_manager.find_module_port(mem_module, circuit_lib.port_lib_name(port));
ModulePortId src_port_id = module_manager.find_module_port(child_module, circuit_lib.port_prefix(port));
ModulePortId sink_port_id = module_manager.find_module_port(mem_module, circuit_lib.port_prefix(port));
for (size_t pin_id = 0; pin_id < module_manager.module_port(child_module, src_port_id).pins().size(); ++pin_id) {
ModuleNetId net = module_manager.create_module_net(mem_module);
/* Source pin is shifted by the number of memories */
@ -106,18 +106,22 @@ void add_module_output_nets_to_mem_modules(ModuleManager& module_manager,
* j-th pin of output port of the i-th child module is wired to the j + i*W -th
* pin of output port of the memory module, where W is the size of port
* 3. It assumes fixed port name for output ports
*
* We cache the module nets that have been created because they will be used later
********************************************************************/
static
void add_module_output_nets_to_chain_mem_modules(ModuleManager& module_manager,
const ModuleId& mem_module,
const std::string& mem_module_output_name,
const CircuitLibrary& circuit_lib,
const CircuitPortId& circuit_port,
const ModuleId& child_module,
const size_t& child_index,
const size_t& child_instance) {
std::vector<ModuleNetId> add_module_output_nets_to_chain_mem_modules(ModuleManager& module_manager,
const ModuleId& mem_module,
const std::string& mem_module_output_name,
const CircuitLibrary& circuit_lib,
const CircuitPortId& circuit_port,
const ModuleId& child_module,
const size_t& child_index,
const size_t& child_instance) {
std::vector<ModuleNetId> module_nets;
/* Wire inputs of parent module to inputs of child modules */
ModulePortId src_port_id = module_manager.find_module_port(child_module, circuit_lib.port_lib_name(circuit_port));
ModulePortId src_port_id = module_manager.find_module_port(child_module, circuit_lib.port_prefix(circuit_port));
ModulePortId sink_port_id = module_manager.find_module_port(mem_module, mem_module_output_name);
for (size_t pin_id = 0; pin_id < module_manager.module_port(child_module, src_port_id).pins().size(); ++pin_id) {
ModuleNetId net = module_manager.create_module_net(mem_module);
@ -128,7 +132,12 @@ void add_module_output_nets_to_chain_mem_modules(ModuleManager& module_manager,
/* Sink node of the input net is the input of sram module */
size_t sink_pin_id = child_index * circuit_lib.port_size(circuit_port) + module_manager.module_port(mem_module, sink_port_id).pins()[pin_id];
module_manager.add_module_net_sink(mem_module, net, mem_module, 0, sink_port_id, sink_pin_id);
/* Cache the nets */
module_nets.push_back(net);
}
return module_nets;
}
/********************************************************************
@ -155,9 +164,13 @@ void add_module_output_nets_to_chain_mem_modules(ModuleManager& module_manager,
static
void add_module_nets_to_cmos_memory_chain_module(ModuleManager& module_manager,
const ModuleId& parent_module,
const std::vector<ModuleNetId>& output_nets,
const CircuitLibrary& circuit_lib,
const CircuitPortId& model_input_port,
const CircuitPortId& model_output_port) {
/* Counter for the nets */
size_t net_counter = 0;
for (size_t mem_index = 0; mem_index < module_manager.configurable_children(parent_module).size(); ++mem_index) {
ModuleId net_src_module_id;
size_t net_src_instance_id;
@ -175,19 +188,19 @@ void add_module_nets_to_cmos_memory_chain_module(ModuleManager& module_manager,
net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
/* Find the port name of next memory module */
std::string sink_port_name = circuit_lib.port_lib_name(model_input_port);
std::string sink_port_name = circuit_lib.port_prefix(model_input_port);
net_sink_module_id = module_manager.configurable_children(parent_module)[mem_index];
net_sink_instance_id = module_manager.configurable_child_instances(parent_module)[mem_index];
net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name);
} else {
/* Find the port name of previous memory module */
std::string src_port_name = circuit_lib.port_lib_name(model_output_port);
std::string src_port_name = circuit_lib.port_prefix(model_output_port);
net_src_module_id = module_manager.configurable_children(parent_module)[mem_index - 1];
net_src_instance_id = module_manager.configurable_child_instances(parent_module)[mem_index - 1];
net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
/* Find the port name of next memory module */
std::string sink_port_name = circuit_lib.port_lib_name(model_input_port);
std::string sink_port_name = circuit_lib.port_prefix(model_input_port);
net_sink_module_id = module_manager.configurable_children(parent_module)[mem_index];
net_sink_instance_id = module_manager.configurable_child_instances(parent_module)[mem_index];
net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name);
@ -203,11 +216,21 @@ void add_module_nets_to_cmos_memory_chain_module(ModuleManager& module_manager,
/* Create a net for each pin */
for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) {
/* Create a net and add source and sink to it */
ModuleNetId net = module_manager.create_module_net(parent_module);
ModuleNetId net;
if (0 == mem_index) {
net = module_manager.create_module_net(parent_module);
} else {
net = output_nets[net_counter];
}
/* Add net source */
module_manager.add_module_net_source(parent_module, net, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]);
/* Add net sink */
module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]);
/* Update net counter */
if (0 < mem_index) {
net_counter++;
}
}
}
@ -216,7 +239,7 @@ void add_module_nets_to_cmos_memory_chain_module(ModuleManager& module_manager,
* net sink is the configuration chain tail of the primitive module
*/
/* Find the port name of previous memory module */
std::string src_port_name = circuit_lib.port_lib_name(model_output_port);
std::string src_port_name = circuit_lib.port_prefix(model_output_port);
ModuleId net_src_module_id = module_manager.configurable_children(parent_module).back();
size_t net_src_instance_id = module_manager.configurable_child_instances(parent_module).back();
ModulePortId net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
@ -237,12 +260,17 @@ void add_module_nets_to_cmos_memory_chain_module(ModuleManager& module_manager,
/* Create a net for each pin */
for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) {
/* Create a net and add source and sink to it */
ModuleNetId net = module_manager.create_module_net(parent_module);
ModuleNetId net = output_nets[net_counter];
/* Add net source */
module_manager.add_module_net_source(parent_module, net, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]);
/* Add net sink */
module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]);
/* Update net counter */
net_counter++;
}
VTR_ASSERT(net_counter == output_nets.size());
}
/*********************************************************************
@ -283,12 +311,12 @@ void build_memory_standalone_module(ModuleManager& module_manager,
/* Add each input port */
for (const auto& port : sram_input_ports) {
BasicPort input_port(circuit_lib.port_lib_name(port), num_mems);
BasicPort input_port(circuit_lib.port_prefix(port), num_mems);
module_manager.add_port(mem_module, input_port, ModuleManager::MODULE_INPUT_PORT);
}
/* Add each output port: port width should match the number of memories */
for (const auto& port : sram_output_ports) {
BasicPort output_port(circuit_lib.port_lib_name(port), num_mems);
BasicPort output_port(circuit_lib.port_prefix(port), num_mems);
module_manager.add_port(mem_module, output_port, ModuleManager::MODULE_OUTPUT_PORT);
}
@ -381,6 +409,9 @@ void build_memory_chain_module(ModuleManager& module_manager,
/* Find the sram module in the module manager */
ModuleId sram_mem_module = module_manager.find_module(circuit_lib.model_name(sram_model));
/* Cache the output nets for non-inverted data output */
std::vector<ModuleNetId> mem_output_nets;
/* Instanciate each submodule */
for (size_t i = 0; i < num_mems; ++i) {
size_t sram_mem_instance = module_manager.num_instance(mem_module, sram_mem_module);
@ -396,13 +427,18 @@ void build_memory_chain_module(ModuleManager& module_manager,
VTR_ASSERT( 1 == iport);
port_name = generate_configuration_chain_inverted_data_out_name();
}
add_module_output_nets_to_chain_mem_modules(module_manager, mem_module, port_name, circuit_lib, sram_output_ports[iport],
sram_mem_module, i, sram_mem_instance);
std::vector<ModuleNetId> output_nets = add_module_output_nets_to_chain_mem_modules(module_manager, mem_module,
port_name, circuit_lib, sram_output_ports[iport],
sram_mem_module, i, sram_mem_instance);
/* Cache only for regular data outputs */
if (0 == iport) {
mem_output_nets.insert(mem_output_nets.end(), output_nets.begin(), output_nets.end());
}
}
}
/* Build module nets to wire the configuration chain */
add_module_nets_to_cmos_memory_chain_module(module_manager, mem_module,
add_module_nets_to_cmos_memory_chain_module(module_manager, mem_module, mem_output_nets,
circuit_lib, sram_input_ports[0], sram_output_ports[0]);
@ -464,29 +500,29 @@ void build_memory_bank_module(ModuleManager& module_manager,
/* Add module ports: the ports come from the SRAM modules */
/* Add each input port */
for (const auto& port : sram_input_ports) {
BasicPort input_port(circuit_lib.port_lib_name(port), num_mems * circuit_lib.port_size(port));
BasicPort input_port(circuit_lib.port_prefix(port), num_mems * circuit_lib.port_size(port));
module_manager.add_port(mem_module, input_port, ModuleManager::MODULE_INPUT_PORT);
}
/* Add each output port: port width should match the number of memories */
for (const auto& port : sram_output_ports) {
BasicPort output_port(circuit_lib.port_lib_name(port), num_mems * circuit_lib.port_size(port));
BasicPort output_port(circuit_lib.port_prefix(port), num_mems * circuit_lib.port_size(port));
module_manager.add_port(mem_module, output_port, ModuleManager::MODULE_OUTPUT_PORT);
}
/* Add each output port: port width should match the number of memories */
for (const auto& port : sram_bl_ports) {
BasicPort bl_port(circuit_lib.port_lib_name(port), num_mems * circuit_lib.port_size(port));
BasicPort bl_port(circuit_lib.port_prefix(port), num_mems * circuit_lib.port_size(port));
module_manager.add_port(mem_module, bl_port, ModuleManager::MODULE_INPUT_PORT);
}
for (const auto& port : sram_blb_ports) {
BasicPort blb_port(circuit_lib.port_lib_name(port), num_mems * circuit_lib.port_size(port));
BasicPort blb_port(circuit_lib.port_prefix(port), num_mems * circuit_lib.port_size(port));
module_manager.add_port(mem_module, blb_port, ModuleManager::MODULE_INPUT_PORT);
}
for (const auto& port : sram_wl_ports) {
BasicPort wl_port(circuit_lib.port_lib_name(port), num_mems * circuit_lib.port_size(port));
BasicPort wl_port(circuit_lib.port_prefix(port), num_mems * circuit_lib.port_size(port));
module_manager.add_port(mem_module, wl_port, ModuleManager::MODULE_INPUT_PORT);
}
for (const auto& port : sram_wlb_ports) {
BasicPort wlb_port(circuit_lib.port_lib_name(port), num_mems * circuit_lib.port_size(port));
BasicPort wlb_port(circuit_lib.port_prefix(port), num_mems * circuit_lib.port_size(port));
module_manager.add_port(mem_module, wlb_port, ModuleManager::MODULE_INPUT_PORT);
}

View File

@ -28,7 +28,7 @@ ModulePortId find_inverter_buffer_module_port(const ModuleManager& module_manage
VTR_ASSERT(1 == model_ports.size());
/* Find the input and output module ports */
ModulePortId module_port_id = module_manager.find_module_port(module_id, circuit_lib.port_lib_name(model_ports[0]));
ModulePortId module_port_id = module_manager.find_module_port(module_id, circuit_lib.port_prefix(model_ports[0]));
VTR_ASSERT(true == module_manager.valid_module_port_id(module_id, module_port_id));
return module_port_id;

View File

@ -74,25 +74,25 @@ void build_cmos_mux_branch_body(ModuleManager& module_manager,
/* Find the module ports of tgate module */
/* Input port is the data path input of the tgate, whose size must be 1 ! */
ModulePortId tgate_module_input = module_manager.find_module_port(tgate_module_id, circuit_lib.port_lib_name(tgate_input_ports[0]));
ModulePortId tgate_module_input = module_manager.find_module_port(tgate_module_id, circuit_lib.port_prefix(tgate_input_ports[0]));
VTR_ASSERT(true == module_manager.valid_module_port_id(tgate_module_id, tgate_module_input));
BasicPort tgate_module_input_port = module_manager.module_port(tgate_module_id, tgate_module_input);
VTR_ASSERT(1 == tgate_module_input_port.get_width());
/* Mem port is the memory of the tgate, whose size must be 1 ! */
ModulePortId tgate_module_mem = module_manager.find_module_port(tgate_module_id, circuit_lib.port_lib_name(tgate_input_ports[1]));
ModulePortId tgate_module_mem = module_manager.find_module_port(tgate_module_id, circuit_lib.port_prefix(tgate_input_ports[1]));
VTR_ASSERT(true == module_manager.valid_module_port_id(tgate_module_id, tgate_module_mem));
BasicPort tgate_module_mem_port = module_manager.module_port(tgate_module_id, tgate_module_mem);
VTR_ASSERT(1 == tgate_module_mem_port.get_width());
/* Mem inv port is the inverted memory of the tgate, whose size must be 1 ! */
ModulePortId tgate_module_mem_inv = module_manager.find_module_port(tgate_module_id, circuit_lib.port_lib_name(tgate_input_ports[2]));
ModulePortId tgate_module_mem_inv = module_manager.find_module_port(tgate_module_id, circuit_lib.port_prefix(tgate_input_ports[2]));
VTR_ASSERT(true == module_manager.valid_module_port_id(tgate_module_id, tgate_module_mem_inv));
BasicPort tgate_module_mem_inv_port = module_manager.module_port(tgate_module_id, tgate_module_mem_inv);
VTR_ASSERT(1 == tgate_module_mem_inv_port.get_width());
/* Output port is the data path output of the tgate, whose size must be 1 ! */
ModulePortId tgate_module_output = module_manager.find_module_port(tgate_module_id, circuit_lib.port_lib_name(tgate_output_ports[0]));
ModulePortId tgate_module_output = module_manager.find_module_port(tgate_module_id, circuit_lib.port_prefix(tgate_output_ports[0]));
VTR_ASSERT(true == module_manager.valid_module_port_id(tgate_module_id, tgate_module_output));
BasicPort tgate_module_output_port = module_manager.module_port(tgate_module_id, tgate_module_output);
VTR_ASSERT(1 == tgate_module_output_port.get_width());
@ -300,26 +300,26 @@ void build_rram_mux_branch_module(ModuleManager& module_manager,
std::vector<CircuitPortId> prog_enable_ports = circuit_lib.model_global_ports_by_type(mux_model, SPICE_MODEL_PORT_INPUT, true, true);
for (const auto& port : prog_enable_ports) {
/* Configure each global port */
BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
BasicPort global_port(circuit_lib.port_prefix(port), circuit_lib.port_size(port));
module_manager.add_port(mux_module, global_port, ModuleManager::MODULE_GLOBAL_PORT);
}
/* Add each input port */
BasicPort input_port(circuit_lib.port_lib_name(mux_input_ports[0]), num_inputs);
BasicPort input_port(circuit_lib.port_prefix(mux_input_ports[0]), num_inputs);
module_manager.add_port(mux_module, input_port, ModuleManager::MODULE_INPUT_PORT);
/* Add each output port */
BasicPort output_port(circuit_lib.port_lib_name(mux_output_ports[0]), num_outputs);
BasicPort output_port(circuit_lib.port_prefix(mux_output_ports[0]), num_outputs);
module_manager.add_port(mux_module, output_port, ModuleManager::MODULE_OUTPUT_PORT);
/* Add RRAM programming ports,
* RRAM MUXes require one more pair of BLB and WL
* to configure the memories. See schematic for details
*/
BasicPort blb_port(circuit_lib.port_lib_name(mux_blb_ports[0]), num_mems + 1);
BasicPort blb_port(circuit_lib.port_prefix(mux_blb_ports[0]), num_mems + 1);
module_manager.add_port(mux_module, blb_port, ModuleManager::MODULE_INPUT_PORT);
BasicPort wl_port(circuit_lib.port_lib_name(mux_wl_ports[0]), num_mems + 1);
BasicPort wl_port(circuit_lib.port_prefix(mux_wl_ports[0]), num_mems + 1);
module_manager.add_port(mux_module, wl_port, ModuleManager::MODULE_INPUT_PORT);
/* Note: we do not generate the internal structure of the ReRAM-based MUX
@ -398,20 +398,20 @@ void build_cmos_mux_module_mux2_multiplexing_structure(ModuleManager& module_man
std::vector<BasicPort> std_cell_module_input_ports;
/* Input 0 port is the first data path input of the tgate, whose size must be 1 ! */
for (size_t port_id = 0; port_id < 2; ++port_id) {
std_cell_module_inputs.push_back(module_manager.find_module_port(std_cell_module_id, circuit_lib.port_lib_name(std_cell_input_ports[port_id])));
std_cell_module_inputs.push_back(module_manager.find_module_port(std_cell_module_id, circuit_lib.port_prefix(std_cell_input_ports[port_id])));
VTR_ASSERT(true == module_manager.valid_module_port_id(std_cell_module_id, std_cell_module_inputs[port_id]));
std_cell_module_input_ports.push_back(module_manager.module_port(std_cell_module_id, std_cell_module_inputs[port_id]));
VTR_ASSERT(1 == std_cell_module_input_ports[port_id].get_width());
}
/* Mem port is the memory of the standard cell MUX2, whose size must be 1 ! */
ModulePortId std_cell_module_mem = module_manager.find_module_port(std_cell_module_id, circuit_lib.port_lib_name(std_cell_input_ports[2]));
ModulePortId std_cell_module_mem = module_manager.find_module_port(std_cell_module_id, circuit_lib.port_prefix(std_cell_input_ports[2]));
VTR_ASSERT(true == module_manager.valid_module_port_id(std_cell_module_id, std_cell_module_mem));
BasicPort std_cell_module_mem_port = module_manager.module_port(std_cell_module_id, std_cell_module_mem);
VTR_ASSERT(1 == std_cell_module_mem_port.get_width());
/* Output port is the data path output of the standard cell MUX2, whose size must be 1 ! */
ModulePortId std_cell_module_output = module_manager.find_module_port(std_cell_module_id, circuit_lib.port_lib_name(std_cell_output_ports[0]));
ModulePortId std_cell_module_output = module_manager.find_module_port(std_cell_module_id, circuit_lib.port_prefix(std_cell_output_ports[0]));
VTR_ASSERT(true == module_manager.valid_module_port_id(std_cell_module_id, std_cell_module_output));
BasicPort std_cell_module_output_port = module_manager.module_port(std_cell_module_id, std_cell_module_output);
VTR_ASSERT(1 == std_cell_module_output_port.get_width());
@ -745,7 +745,7 @@ vtr::vector<MuxInputId, ModuleNetId> build_mux_module_input_buffers(ModuleManage
VTR_ASSERT(1 == mux_input_ports.size());
/* Get the input port from MUX module */
ModulePortId module_input_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_lib_name(mux_input_ports[0]));
ModulePortId module_input_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(mux_input_ports[0]));
VTR_ASSERT(ModulePortId::INVALID() != module_input_port_id);
/* Get the port from module */
BasicPort module_input_port = module_manager.module_port(mux_module, module_input_port_id);
@ -860,7 +860,7 @@ vtr::vector<MuxOutputId, ModuleNetId> build_mux_module_output_buffers(ModuleMana
/* Iterate over all the outputs in the MUX module */
for (const auto& output_port : mux_output_ports) {
/* Get the output port from MUX module */
ModulePortId module_output_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_lib_name(output_port));
ModulePortId module_output_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(output_port));
VTR_ASSERT(ModulePortId::INVALID() != module_output_port_id);
/* Get the port from module */
BasicPort module_output_port = module_manager.module_port(mux_module, module_output_port_id);
@ -968,7 +968,7 @@ void build_mux_module_local_encoders_and_memory_nets(ModuleManager& module_manag
/* Add mem and mem_inv nets here */
size_t mem_net_cnt = 0;
for (const auto& port : mux_sram_ports) {
ModulePortId mem_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_lib_name(port));
ModulePortId mem_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(port));
BasicPort mem_port = module_manager.module_port(mux_module, mem_port_id);
for (const size_t& pin : mem_port.pins()) {
MuxMemId mem_id = MuxMemId(mem_net_cnt);
@ -983,7 +983,7 @@ void build_mux_module_local_encoders_and_memory_nets(ModuleManager& module_manag
/* Add mem and mem_inv nets here */
size_t mem_inv_net_cnt = 0;
for (const auto& port : mux_sram_ports) {
ModulePortId mem_inv_port_id = module_manager.find_module_port(mux_module, std::string(circuit_lib.port_lib_name(port) + "_inv"));
ModulePortId mem_inv_port_id = module_manager.find_module_port(mux_module, std::string(circuit_lib.port_prefix(port) + "_inv"));
BasicPort mem_inv_port = module_manager.module_port(mux_module, mem_inv_port_id);
for (const size_t& pin : mem_inv_port.pins()) {
MuxMemId mem_id = MuxMemId(mem_inv_net_cnt);
@ -1003,9 +1003,9 @@ void build_mux_module_local_encoders_and_memory_nets(ModuleManager& module_manag
BasicPort decoder_data_inv_port(generate_mux_local_decoder_data_inv_port_name(), mux_graph.num_memory_bits());
/* Local port to record the LSB and MSB of each level, here, we deposite (0, 0) */
ModulePortId mux_module_sram_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_lib_name(mux_sram_ports[0]));
ModulePortId mux_module_sram_inv_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_lib_name(mux_sram_ports[0]) + "_inv");
BasicPort lvl_addr_port(circuit_lib.port_lib_name(mux_sram_ports[0]), 0);
ModulePortId mux_module_sram_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(mux_sram_ports[0]));
ModulePortId mux_module_sram_inv_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(mux_sram_ports[0]) + "_inv");
BasicPort lvl_addr_port(circuit_lib.port_prefix(mux_sram_ports[0]), 0);
BasicPort lvl_data_port(decoder_data_port.get_name(), 0);
BasicPort lvl_data_inv_port(decoder_data_inv_port.get_name(), 0);
@ -1161,7 +1161,7 @@ void build_cmos_mux_module(ModuleManager& module_manager,
*/
size_t input_port_cnt = 0;
for (const auto& port : mux_input_ports) {
BasicPort input_port(circuit_lib.port_lib_name(port), num_inputs);
BasicPort input_port(circuit_lib.port_prefix(port), num_inputs);
module_manager.add_port(mux_module, input_port, ModuleManager::MODULE_INPUT_PORT);
/* Update counter */
input_port_cnt++;
@ -1173,7 +1173,7 @@ void build_cmos_mux_module(ModuleManager& module_manager,
vtr::vector<MuxInputId, ModuleNetId> mux_input_nets = build_mux_module_input_buffers(module_manager, circuit_lib, mux_module, mux_model, mux_graph);
for (const auto& port : mux_output_ports) {
BasicPort output_port(circuit_lib.port_lib_name(port), num_outputs);
BasicPort output_port(circuit_lib.port_prefix(port), num_outputs);
if (SPICE_MODEL_LUT == circuit_lib.model_type(mux_model)) {
output_port.set_width(circuit_lib.port_size(port));
}
@ -1185,9 +1185,9 @@ void build_cmos_mux_module(ModuleManager& module_manager,
size_t sram_port_cnt = 0;
for (const auto& port : mux_sram_ports) {
BasicPort mem_port(circuit_lib.port_lib_name(port), num_mems);
BasicPort mem_port(circuit_lib.port_prefix(port), num_mems);
module_manager.add_port(mux_module, mem_port, ModuleManager::MODULE_INPUT_PORT);
BasicPort mem_inv_port(std::string(circuit_lib.port_lib_name(port) + "_inv"), num_mems);
BasicPort mem_inv_port(std::string(circuit_lib.port_prefix(port) + "_inv"), num_mems);
module_manager.add_port(mux_module, mem_inv_port, ModuleManager::MODULE_INPUT_PORT);
/* Update counter */
sram_port_cnt++;
@ -1305,13 +1305,13 @@ void build_rram_mux_module(ModuleManager& module_manager,
/* Add each global port */
for (const auto& port : mux_global_ports) {
/* Configure each global port */
BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
BasicPort global_port(circuit_lib.port_prefix(port), circuit_lib.port_size(port));
module_manager.add_port(module_id, global_port, ModuleManager::MODULE_GLOBAL_PORT);
}
/* Add each input port */
size_t input_port_cnt = 0;
for (const auto& port : mux_input_ports) {
BasicPort input_port(circuit_lib.port_lib_name(port), num_inputs);
BasicPort input_port(circuit_lib.port_prefix(port), num_inputs);
module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT);
/* Update counter */
input_port_cnt++;
@ -1320,7 +1320,7 @@ void build_rram_mux_module(ModuleManager& module_manager,
VTR_ASSERT(1 == input_port_cnt);
for (const auto& port : mux_output_ports) {
BasicPort output_port(circuit_lib.port_lib_name(port), num_outputs);
BasicPort output_port(circuit_lib.port_prefix(port), num_outputs);
if (SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model)) {
output_port.set_width(circuit_lib.port_size(port));
}
@ -1332,7 +1332,7 @@ void build_rram_mux_module(ModuleManager& module_manager,
/* IMPORTANT: RRAM-based MUX has an additional BLB pin per level
* So, the actual port width of BLB should be added by the number of levels of the MUX graph
*/
BasicPort blb_port(circuit_lib.port_lib_name(port), num_mems + mux_graph.num_levels());
BasicPort blb_port(circuit_lib.port_prefix(port), num_mems + mux_graph.num_levels());
module_manager.add_port(module_id, blb_port, ModuleManager::MODULE_INPUT_PORT);
}
@ -1341,7 +1341,7 @@ void build_rram_mux_module(ModuleManager& module_manager,
/* IMPORTANT: RRAM-based MUX has an additional WL pin per level
* So, the actual port width of WL should be added by the number of levels of the MUX graph
*/
BasicPort wl_port(circuit_lib.port_lib_name(port), num_mems + mux_graph.num_levels());
BasicPort wl_port(circuit_lib.port_prefix(port), num_mems + mux_graph.num_levels());
module_manager.add_port(module_id, wl_port, ModuleManager::MODULE_INPUT_PORT);
}

View File

@ -0,0 +1,219 @@
/********************************************************************
* This file includes most utilized functions that are used to build modules
* for global routing architecture of a FPGA fabric
* Covering:
* 1. Connection blocks
* 2. Switch blocks
*******************************************************************/
#include "vtr_assert.h"
#include "vtr_geometry.h"
#include "device_coordinator.h"
#include "fpga_x2p_naming.h"
#include "build_routing_module_utils.h"
/*********************************************************************
* Generate a port for a routing track of a swtich block
********************************************************************/
ModulePortId find_switch_block_module_chan_port(const ModuleManager& module_manager,
const ModuleId& sb_module,
const RRGSB& rr_gsb,
const e_side& chan_side,
t_rr_node* cur_rr_node,
const PORTS& cur_rr_node_direction) {
/* Get the index in sb_info of cur_rr_node */
int index = rr_gsb.get_node_index(cur_rr_node, chan_side, cur_rr_node_direction);
/* Make sure this node is included in this sb_info */
VTR_ASSERT((-1 != index)&&(NUM_SIDES != chan_side));
DeviceCoordinator chan_rr_node_coordinator = rr_gsb.get_side_block_coordinator(chan_side);
vtr::Point<size_t> chan_port_coord(chan_rr_node_coordinator.get_x(), chan_rr_node_coordinator.get_y());
std::string chan_port_name = generate_routing_track_port_name(rr_gsb.get_chan_node(chan_side, index)->type,
chan_port_coord, index,
rr_gsb.get_chan_node_direction(chan_side, index));
/* Must find a valid port id in the Switch Block module */
ModulePortId chan_port_id = module_manager.find_module_port(sb_module, chan_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, chan_port_id));
return chan_port_id;
}
/*********************************************************************
* Generate an input port for routing multiplexer inside the switch block
* In addition to give the Routing Resource node of the input
* Users should provide the side of input, which is different case by case:
* 1. When the input is a pin of a CLB/Logic Block, the input_side should
* be the side of the node on its grid!
* For example, the input pin is on the top side of a switch block
* but on the right side of a switch block
* +--------+
* | |
* | Grid |---+
* | | |
* +--------+ v input_pin
* +----------------+
* | Switch Block |
* +----------------+
* 2. When the input is a routing track, the input_side should be
* the side of the node locating on the switch block
********************************************************************/
ModulePortId find_switch_block_module_input_port(const ModuleManager& module_manager,
const ModuleId& sb_module,
const RRGSB& rr_gsb,
const std::vector<std::vector<t_grid_tile>>& grids,
const e_side& input_side,
t_rr_node* input_rr_node) {
/* Deposit an invalid value */
ModulePortId input_port_id = ModulePortId::INVALID();
/* Generate the input port object */
switch (input_rr_node->type) {
/* case SOURCE: */
case OPIN: {
/* Find the coordinator (grid_x and grid_y) for the input port */
vtr::Point<size_t> input_port_coord(input_rr_node->xlow, input_rr_node->ylow);
std::string input_port_name = generate_grid_side_port_name(grids,
input_port_coord,
input_side,
input_rr_node->ptc_num);
/* Must find a valid port id in the Switch Block module */
input_port_id = module_manager.find_module_port(sb_module, input_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, input_port_id));
break;
}
case CHANX:
case CHANY: {
input_port_id = find_switch_block_module_chan_port(module_manager, sb_module,
rr_gsb, input_side, input_rr_node, IN_PORT);
break;
}
default: /* SOURCE, IPIN, SINK are invalid*/
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n",
__FILE__, __LINE__);
exit(1);
}
return input_port_id;
}
/*********************************************************************
* Generate a list of input ports for routing multiplexer inside the switch block
********************************************************************/
std::vector<ModulePortId> find_switch_block_module_input_ports(const ModuleManager& module_manager,
const ModuleId& sb_module,
const RRGSB& rr_gsb,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_rr_node*>& input_rr_nodes) {
std::vector<ModulePortId> input_ports;
for (auto input_rr_node : input_rr_nodes) {
enum e_side input_pin_side = NUM_SIDES;
switch (input_rr_node->type) {
case OPIN:
input_pin_side = rr_gsb.get_opin_node_grid_side(input_rr_node);
break;
case CHANX:
case CHANY: {
/* The input could be at any side of the switch block, find it */
int index = -1;
rr_gsb.get_node_side_and_index(input_rr_node, IN_PORT, &input_pin_side, &index);
VTR_ASSERT(NUM_SIDES != input_pin_side);
break;
}
default: /* SOURCE, IPIN, SINK are invalid*/
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n",
__FILE__, __LINE__);
exit(1);
}
input_ports.push_back(find_switch_block_module_input_port(module_manager, sb_module, rr_gsb, grids, input_pin_side, input_rr_node));
}
return input_ports;
}
/*********************************************************************
* Generate an input port for routing multiplexer inside the connection block
* which is the middle output of a routing track
********************************************************************/
ModulePortId find_connection_block_module_chan_port(const ModuleManager& module_manager,
const ModuleId& cb_module,
const RRGSB& rr_gsb,
const t_rr_type& cb_type,
t_rr_node* chan_rr_node) {
ModulePortId input_port_id;
/* Generate the input port object */
switch (chan_rr_node->type) {
case CHANX:
case CHANY: {
/* Create port description for the routing track middle output */
vtr::Point<size_t> port_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
int chan_node_track_id = rr_gsb.get_cb_chan_node_index(cb_type, chan_rr_node);
/* Create a port description for the middle output */
std::string input_port_name = generate_routing_track_port_name(cb_type,
port_coord, chan_node_track_id,
IN_PORT);
/* Must find a valid port id in the Switch Block module */
input_port_id = module_manager.find_module_port(cb_module, input_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, input_port_id));
break;
}
default: /* OPIN, SOURCE, IPIN, SINK are invalid*/
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n",
__FILE__, __LINE__);
exit(1);
}
return input_port_id;
}
/*********************************************************************
* Generate a port for a routing track of a swtich block
********************************************************************/
ModulePortId find_connection_block_module_ipin_port(const ModuleManager& module_manager,
const ModuleId& cb_module,
const RRGSB& rr_gsb,
const std::vector<std::vector<t_grid_tile>>& grids,
t_rr_node* src_rr_node) {
/* Ensure the src_rr_node is an input pin of a CLB */
VTR_ASSERT(IPIN == src_rr_node->type);
/* Create port description for input pin of a CLB */
vtr::Point<size_t> port_coord(src_rr_node->xlow, src_rr_node->ylow);
/* Search all the sides of a SB, see this drive_rr_node is an INPUT of this SB */
enum e_side cb_ipin_side = NUM_SIDES;
int cb_ipin_index = -1;
rr_gsb.get_node_side_and_index(src_rr_node, OUT_PORT, &cb_ipin_side, &cb_ipin_index);
/* We need to be sure that drive_rr_node is part of the CB */
VTR_ASSERT((-1 != cb_ipin_index)&&(NUM_SIDES != cb_ipin_side));
std::string port_name = generate_grid_side_port_name(grids,
port_coord,
rr_gsb.get_ipin_node_grid_side(cb_ipin_side, cb_ipin_index),
rr_gsb.get_ipin_node(cb_ipin_side, cb_ipin_index)->ptc_num);
/* Must find a valid port id in the Switch Block module */
ModulePortId ipin_port_id = module_manager.find_module_port(cb_module, port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, ipin_port_id));
return ipin_port_id;
}
/*********************************************************************
* Generate a list of routing track middle output ports
* for routing multiplexer inside the connection block
********************************************************************/
std::vector<ModulePortId> find_connection_block_module_input_ports(const ModuleManager& module_manager,
const ModuleId& cb_module,
const RRGSB& rr_gsb,
const t_rr_type& cb_type,
const std::vector<t_rr_node*>& input_rr_nodes) {
std::vector<ModulePortId> input_ports;
for (auto input_rr_node : input_rr_nodes) {
input_ports.push_back(find_connection_block_module_chan_port(module_manager, cb_module, rr_gsb, cb_type, input_rr_node));
}
return input_ports;
}

View File

@ -0,0 +1,48 @@
#ifndef BUILD_ROUTING_MODULE_UTILS_H
#define BUILD_ROUTING_MODULE_UTILS_H
#include <vector>
#include "rr_blocks.h"
#include "module_manager.h"
#include "sides.h"
#include "vpr_types.h"
ModulePortId find_switch_block_module_chan_port(const ModuleManager& module_manager,
const ModuleId& sb_module,
const RRGSB& rr_gsb,
const e_side& chan_side,
t_rr_node* cur_rr_node,
const PORTS& cur_rr_node_direction);
ModulePortId find_switch_block_module_input_port(const ModuleManager& module_manager,
const ModuleId& sb_module,
const RRGSB& rr_gsb,
const std::vector<std::vector<t_grid_tile>>& grids,
const e_side& input_side,
t_rr_node* input_rr_node);
std::vector<ModulePortId> find_switch_block_module_input_ports(const ModuleManager& module_manager,
const ModuleId& sb_module,
const RRGSB& rr_gsb,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_rr_node*>& input_rr_nodes);
ModulePortId find_connection_block_module_chan_port(const ModuleManager& module_manager,
const ModuleId& cb_module,
const RRGSB& rr_gsb,
const t_rr_type& cb_type,
t_rr_node* chan_rr_node);
ModulePortId find_connection_block_module_ipin_port(const ModuleManager& module_manager,
const ModuleId& cb_module,
const RRGSB& rr_gsb,
const std::vector<std::vector<t_grid_tile>>& grids,
t_rr_node* src_rr_node);
std::vector<ModulePortId> find_connection_block_module_input_ports(const ModuleManager& module_manager,
const ModuleId& cb_module,
const RRGSB& rr_gsb,
const t_rr_type& cb_type,
const std::vector<t_rr_node*>& input_rr_nodes);
#endif

View File

@ -21,135 +21,11 @@
#include "fpga_x2p_utils.h"
#include "module_manager_utils.h"
#include "build_module_graph_utils.h"
#include "build_routing_module_utils.h"
#include "build_routing_modules.h"
#include "verilog_global.h"
/*********************************************************************
* Generate a port for a routing track of a swtich block
********************************************************************/
static
ModulePortId find_switch_block_module_chan_port(const ModuleManager& module_manager,
const ModuleId& sb_module,
const RRGSB& rr_gsb,
const e_side& chan_side,
t_rr_node* cur_rr_node,
const PORTS& cur_rr_node_direction) {
/* Get the index in sb_info of cur_rr_node */
int index = rr_gsb.get_node_index(cur_rr_node, chan_side, cur_rr_node_direction);
/* Make sure this node is included in this sb_info */
VTR_ASSERT((-1 != index)&&(NUM_SIDES != chan_side));
DeviceCoordinator chan_rr_node_coordinator = rr_gsb.get_side_block_coordinator(chan_side);
vtr::Point<size_t> chan_port_coord(chan_rr_node_coordinator.get_x(), chan_rr_node_coordinator.get_y());
std::string chan_port_name = generate_routing_track_port_name(rr_gsb.get_chan_node(chan_side, index)->type,
chan_port_coord, index,
rr_gsb.get_chan_node_direction(chan_side, index));
/* Must find a valid port id in the Switch Block module */
ModulePortId chan_port_id = module_manager.find_module_port(sb_module, chan_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, chan_port_id));
return chan_port_id;
}
/*********************************************************************
* Generate an input port for routing multiplexer inside the switch block
* In addition to give the Routing Resource node of the input
* Users should provide the side of input, which is different case by case:
* 1. When the input is a pin of a CLB/Logic Block, the input_side should
* be the side of the node on its grid!
* For example, the input pin is on the top side of a switch block
* but on the right side of a switch block
* +--------+
* | |
* | Grid |---+
* | | |
* +--------+ v input_pin
* +----------------+
* | Switch Block |
* +----------------+
* 2. When the input is a routing track, the input_side should be
* the side of the node locating on the switch block
********************************************************************/
static
ModulePortId find_switch_block_module_input_port(const ModuleManager& module_manager,
const ModuleId& sb_module,
const RRGSB& rr_gsb,
const std::vector<std::vector<t_grid_tile>>& grids,
const e_side& input_side,
t_rr_node* input_rr_node) {
/* Deposit an invalid value */
ModulePortId input_port_id = ModulePortId::INVALID();
/* Generate the input port object */
switch (input_rr_node->type) {
/* case SOURCE: */
case OPIN: {
/* Find the coordinator (grid_x and grid_y) for the input port */
vtr::Point<size_t> input_port_coord(input_rr_node->xlow, input_rr_node->ylow);
std::string input_port_name = generate_grid_side_port_name(grids,
input_port_coord,
input_side,
input_rr_node->ptc_num);
/* Must find a valid port id in the Switch Block module */
input_port_id = module_manager.find_module_port(sb_module, input_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, input_port_id));
break;
}
case CHANX:
case CHANY: {
input_port_id = find_switch_block_module_chan_port(module_manager, sb_module,
rr_gsb, input_side, input_rr_node, IN_PORT);
break;
}
default: /* SOURCE, IPIN, SINK are invalid*/
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n",
__FILE__, __LINE__);
exit(1);
}
return input_port_id;
}
/*********************************************************************
* Generate a list of input ports for routing multiplexer inside the switch block
********************************************************************/
static
std::vector<ModulePortId> find_switch_block_module_input_ports(const ModuleManager& module_manager,
const ModuleId& sb_module,
const RRGSB& rr_gsb,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_rr_node*>& input_rr_nodes) {
std::vector<ModulePortId> input_ports;
for (auto input_rr_node : input_rr_nodes) {
enum e_side input_pin_side = NUM_SIDES;
switch (input_rr_node->type) {
case OPIN:
input_pin_side = rr_gsb.get_opin_node_grid_side(input_rr_node);
break;
case CHANX:
case CHANY: {
/* The input could be at any side of the switch block, find it */
int index = -1;
rr_gsb.get_node_side_and_index(input_rr_node, IN_PORT, &input_pin_side, &index);
VTR_ASSERT(NUM_SIDES != input_pin_side);
break;
}
default: /* SOURCE, IPIN, SINK are invalid*/
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n",
__FILE__, __LINE__);
exit(1);
}
input_ports.push_back(find_switch_block_module_input_port(module_manager, sb_module, rr_gsb, grids, input_pin_side, input_rr_node));
}
return input_ports;
}
/*********************************************************************
* Generate a short interconneciton in switch box
* There are two cases should be noticed.
@ -252,6 +128,12 @@ void build_switch_block_mux_module(ModuleManager& module_manager,
/* Instanciate the MUX Module */
module_manager.add_child_module(sb_module, mux_module);
/* Give an instance name: this name should be consistent with the block name given in SDC manager,
* If you want to bind the SDC generation to modules
*/
std::string mux_instance_name = generate_sb_memory_instance_name(SWITCH_BLOCK_MUX_INSTANCE_PREFIX, chan_side, chan_node_id, std::string(""));
module_manager.set_child_instance_name(sb_module, mux_module, mux_instance_id, mux_instance_name);
/* Generate input ports that are wired to the input bus of the routing multiplexer */
std::vector<ModulePortId> sb_input_port_ids = find_switch_block_module_input_ports(module_manager, sb_module, rr_gsb, grids, drive_rr_nodes);
@ -259,7 +141,7 @@ void build_switch_block_mux_module(ModuleManager& module_manager,
std::vector<CircuitPortId> mux_model_input_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_INPUT, true);
VTR_ASSERT(1 == mux_model_input_ports.size());
/* Find the module port id of the input port */
ModulePortId mux_input_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_lib_name(mux_model_input_ports[0]));
ModulePortId mux_input_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(mux_model_input_ports[0]));
VTR_ASSERT(true == module_manager.valid_module_port_id(mux_module, mux_input_port_id));
BasicPort mux_input_port = module_manager.module_port(mux_module, mux_input_port_id);
@ -278,7 +160,7 @@ void build_switch_block_mux_module(ModuleManager& module_manager,
std::vector<CircuitPortId> mux_model_output_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_OUTPUT, true);
VTR_ASSERT(1 == mux_model_output_ports.size());
/* Use the port name convention in the circuit library */
ModulePortId mux_output_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_lib_name(mux_model_output_ports[0]));
ModulePortId mux_output_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(mux_model_output_ports[0]));
VTR_ASSERT(true == module_manager.valid_module_port_id(mux_module, mux_output_port_id));
BasicPort mux_output_port = module_manager.module_port(mux_module, mux_output_port_id);
ModulePortId sb_output_port_id = find_switch_block_module_chan_port(module_manager, sb_module, rr_gsb, chan_side, cur_rr_node, OUT_PORT);
@ -550,93 +432,6 @@ void build_switch_block_module(ModuleManager& module_manager,
}
}
/*********************************************************************
* Generate an input port for routing multiplexer inside the connection block
* which is the middle output of a routing track
********************************************************************/
static
ModulePortId find_connection_block_module_chan_port(const ModuleManager& module_manager,
const ModuleId& cb_module,
const RRGSB& rr_gsb,
const t_rr_type& cb_type,
t_rr_node* chan_rr_node) {
ModulePortId input_port_id;
/* Generate the input port object */
switch (chan_rr_node->type) {
case CHANX:
case CHANY: {
/* Create port description for the routing track middle output */
vtr::Point<size_t> port_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
int chan_node_track_id = rr_gsb.get_cb_chan_node_index(cb_type, chan_rr_node);
/* Create a port description for the middle output */
std::string input_port_name = generate_routing_track_port_name(cb_type,
port_coord, chan_node_track_id,
IN_PORT);
/* Must find a valid port id in the Switch Block module */
input_port_id = module_manager.find_module_port(cb_module, input_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, input_port_id));
break;
}
default: /* OPIN, SOURCE, IPIN, SINK are invalid*/
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n",
__FILE__, __LINE__);
exit(1);
}
return input_port_id;
}
/*********************************************************************
* Generate a port for a routing track of a swtich block
********************************************************************/
static
ModulePortId find_connection_block_module_ipin_port(const ModuleManager& module_manager,
const ModuleId& cb_module,
const RRGSB& rr_gsb,
const std::vector<std::vector<t_grid_tile>>& grids,
t_rr_node* src_rr_node) {
/* Ensure the src_rr_node is an input pin of a CLB */
VTR_ASSERT(IPIN == src_rr_node->type);
/* Create port description for input pin of a CLB */
vtr::Point<size_t> port_coord(src_rr_node->xlow, src_rr_node->ylow);
/* Search all the sides of a SB, see this drive_rr_node is an INPUT of this SB */
enum e_side cb_ipin_side = NUM_SIDES;
int cb_ipin_index = -1;
rr_gsb.get_node_side_and_index(src_rr_node, OUT_PORT, &cb_ipin_side, &cb_ipin_index);
/* We need to be sure that drive_rr_node is part of the CB */
VTR_ASSERT((-1 != cb_ipin_index)&&(NUM_SIDES != cb_ipin_side));
std::string port_name = generate_grid_side_port_name(grids,
port_coord,
rr_gsb.get_ipin_node_grid_side(cb_ipin_side, cb_ipin_index),
rr_gsb.get_ipin_node(cb_ipin_side, cb_ipin_index)->ptc_num);
/* Must find a valid port id in the Switch Block module */
ModulePortId ipin_port_id = module_manager.find_module_port(cb_module, port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, ipin_port_id));
return ipin_port_id;
}
/*********************************************************************
* Generate a list of routing track middle output ports
* for routing multiplexer inside the connection block
********************************************************************/
static
std::vector<ModulePortId> find_connection_block_module_input_ports(const ModuleManager& module_manager,
const ModuleId& cb_module,
const RRGSB& rr_gsb,
const t_rr_type& cb_type,
const std::vector<t_rr_node*>& input_rr_nodes) {
std::vector<ModulePortId> input_ports;
for (auto input_rr_node : input_rr_nodes) {
input_ports.push_back(find_connection_block_module_chan_port(module_manager, cb_module, rr_gsb, cb_type, input_rr_node));
}
return input_ports;
}
/*********************************************************************
* Print a short interconneciton in connection
********************************************************************/
@ -651,7 +446,7 @@ void build_connection_block_module_short_interc(ModuleManager& module_manager,
/* Ensure we have only one 1 driver node */
VTR_ASSERT_SAFE(1 == src_rr_node->fan_in);
/* Find the driver node */
/* Find the driver node */
t_rr_node* drive_rr_node = src_rr_node->drive_rr_nodes[0];
/* We have OPINs since we may have direct connections:
@ -726,6 +521,12 @@ void build_connection_block_mux_module(ModuleManager& module_manager,
size_t mux_instance_id = module_manager.num_instance(cb_module, mux_module);
module_manager.add_child_module(cb_module, mux_module);
/* Give an instance name: this name should be consistent with the block name given in SDC manager,
* If you want to bind the SDC generation to modules
*/
std::string mux_instance_name = generate_cb_mux_instance_name(CONNECTION_BLOCK_MUX_INSTANCE_PREFIX, rr_gsb.get_ipin_node_grid_side(cb_ipin_side, ipin_index), ipin_index, std::string(""));
module_manager.set_child_instance_name(cb_module, mux_module, mux_instance_id, mux_instance_name);
/* TODO: Generate input ports that are wired to the input bus of the routing multiplexer */
std::vector<ModulePortId> cb_input_port_ids = find_connection_block_module_input_ports(module_manager, cb_module, rr_gsb, cb_type, drive_rr_nodes);
@ -733,7 +534,7 @@ void build_connection_block_mux_module(ModuleManager& module_manager,
std::vector<CircuitPortId> mux_model_input_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_INPUT, true);
VTR_ASSERT(1 == mux_model_input_ports.size());
/* Find the module port id of the input port */
ModulePortId mux_input_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_lib_name(mux_model_input_ports[0]));
ModulePortId mux_input_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(mux_model_input_ports[0]));
VTR_ASSERT(true == module_manager.valid_module_port_id(mux_module, mux_input_port_id));
BasicPort mux_input_port = module_manager.module_port(mux_module, mux_input_port_id);
@ -752,7 +553,7 @@ void build_connection_block_mux_module(ModuleManager& module_manager,
std::vector<CircuitPortId> mux_model_output_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_OUTPUT, true);
VTR_ASSERT(1 == mux_model_output_ports.size());
/* Use the port name convention in the circuit library */
ModulePortId mux_output_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_lib_name(mux_model_output_ports[0]));
ModulePortId mux_output_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(mux_model_output_ports[0]));
VTR_ASSERT(true == module_manager.valid_module_port_id(mux_module, mux_output_port_id));
BasicPort mux_output_port = module_manager.module_port(mux_module, mux_output_port_id);
ModulePortId cb_output_port_id = find_connection_block_module_ipin_port(module_manager, cb_module, rr_gsb, grids, cur_rr_node);
@ -780,7 +581,7 @@ void build_connection_block_mux_module(ModuleManager& module_manager,
/* Give an instance name: this name should be consistent with the block name given in bitstream manager,
* If you want to bind the bitstream generation to modules
*/
std::string mem_instance_name = generate_cb_memory_instance_name(CONNECTION_BLOCK_MEM_INSTANCE_PREFIX, rr_gsb.get_ipin_node_grid_side(cb_ipin_side, ipin_index), cur_rr_node->ptc_num, std::string(""));
std::string mem_instance_name = generate_cb_memory_instance_name(CONNECTION_BLOCK_MEM_INSTANCE_PREFIX, rr_gsb.get_ipin_node_grid_side(cb_ipin_side, ipin_index), ipin_index, std::string(""));
module_manager.set_child_instance_name(cb_module, mem_module, mem_instance_id, mem_instance_name);
/* Add nets to connect regular and mode-select SRAM ports to the SRAM port of memory module */
@ -1044,8 +845,7 @@ void build_flatten_connection_block_modules(ModuleManager& module_manager,
* We will skip those modules
*/
const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy);
if ( (TRUE != is_cb_exist(cb_type, rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)))
|| (true != rr_gsb.is_cb_exist(cb_type))) {
if (false == rr_gsb.is_cb_exist(cb_type)) {
continue;
}
build_connection_block_module(module_manager,

View File

@ -11,6 +11,7 @@
#include "vpr_types.h"
#include "globals.h"
#include "rr_blocks_utils.h"
#include "fpga_x2p_reserved_words.h"
#include "fpga_x2p_naming.h"
#include "fpga_x2p_utils.h"
@ -311,9 +312,7 @@ std::vector<std::vector<size_t>> add_top_module_connection_block_instances(Modul
*/
const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy);
vtr::Point<size_t> cb_coordinate(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
const DeviceCoordinator cb_coordinator = rr_gsb.get_cb_coordinator(cb_type);
if ( (TRUE != is_cb_exist(cb_type, cb_coordinator.get_x(), cb_coordinator.get_y()))
|| (true != rr_gsb.is_cb_exist(cb_type))) {
if ( false == rr_gsb.is_cb_exist(cb_type) ) {
continue;
}
/* If we use compact routing hierarchy, we should instanciate the unique module of SB */
@ -522,8 +521,12 @@ void add_top_module_nets_connect_grids_and_cb(ModuleManager& module_manager,
DeviceCoordinator module_gsb_coordinate(rr_gsb.get_x(), rr_gsb.get_y());
/* Skip those Connection blocks that do not exist */
if ( (TRUE != is_cb_exist(cb_type, rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)))
|| (true != rr_gsb.is_cb_exist(cb_type))) {
if (false == rr_gsb.is_cb_exist(cb_type)) {
return;
}
/* Skip if the cb does not contain any configuration bits! */
if (true == connection_block_contain_only_routing_tracks(rr_gsb, cb_type)) {
return;
}
@ -684,16 +687,14 @@ void add_top_module_nets_connect_sb_and_cb(ModuleManager& module_manager,
* FOr RIGHT and BOTTOM side, find the adjacent RRGSB and then use is_cb_exist()
*/
if ( TOP == side_manager.get_side() || LEFT == side_manager.get_side() ) {
if ( (TRUE != is_cb_exist(cb_type, module_gsb_cb_coordinate.get_x(), module_gsb_cb_coordinate.get_y()))
|| (true != rr_gsb.is_cb_exist(cb_type))) {
if ( false == rr_gsb.is_cb_exist(cb_type)) {
continue;
}
}
if ( RIGHT == side_manager.get_side() || BOTTOM == side_manager.get_side() ) {
const RRGSB& adjancent_gsb = L_device_rr_gsb.get_gsb(module_gsb_cb_coordinate);
if ( (TRUE != is_cb_exist(cb_type, module_gsb_cb_coordinate.get_x(), module_gsb_cb_coordinate.get_y()))
|| (true != adjancent_gsb.is_cb_exist(cb_type))) {
const RRGSB& adjacent_gsb = L_device_rr_gsb.get_gsb(module_gsb_cb_coordinate);
if ( false == adjacent_gsb.is_cb_exist(cb_type)) {
continue;
}
}

View File

@ -92,17 +92,17 @@ void add_module_nets_clb2clb_direct_connection(ModuleManager& module_manager,
/* Find inputs and outputs of the direct circuit module */
std::vector<CircuitPortId> direct_input_ports = circuit_lib.model_ports_by_type(direct.circuit_model, SPICE_MODEL_PORT_INPUT, true);
VTR_ASSERT(1 == direct_input_ports.size());
ModulePortId direct_input_port_id = module_manager.find_module_port(direct_module, circuit_lib.port_lib_name(direct_input_ports[0]));
ModulePortId direct_input_port_id = module_manager.find_module_port(direct_module, circuit_lib.port_prefix(direct_input_ports[0]));
VTR_ASSERT(true == module_manager.valid_module_port_id(direct_module, direct_input_port_id));
VTR_ASSERT(1 == module_manager.module_port(direct_module, direct_input_port_id).get_width());
std::vector<CircuitPortId> direct_output_ports = circuit_lib.model_ports_by_type(direct.circuit_model, SPICE_MODEL_PORT_OUTPUT, true);
VTR_ASSERT(1 == direct_output_ports.size());
ModulePortId direct_output_port_id = module_manager.find_module_port(direct_module, circuit_lib.port_lib_name(direct_output_ports[0]));
ModulePortId direct_output_port_id = module_manager.find_module_port(direct_module, circuit_lib.port_prefix(direct_output_ports[0]));
VTR_ASSERT(true == module_manager.valid_module_port_id(direct_module, direct_output_port_id));
VTR_ASSERT(1 == module_manager.module_port(direct_module, direct_output_port_id).get_width());
for (size_t pin_id : src_clb_port.pins()) {
for (size_t pin_id = 0; pin_id < src_clb_port.pins().size(); ++pin_id) {
/* Generate the pin name of source port/pin in the grid */
size_t src_pin_height = find_grid_pin_height(grids, src_clb_coord, src_clb_port.pins()[pin_id]);
e_side src_pin_grid_side = find_grid_pin_side(device_size, grids, src_clb_coord, src_pin_height, src_clb_port.pins()[pin_id]);

View File

@ -4,6 +4,7 @@
*******************************************************************/
#include "vtr_assert.h"
#include "rr_blocks_utils.h"
#include "fpga_x2p_utils.h"
#include "fpga_x2p_naming.h"
@ -31,8 +32,12 @@ void organize_top_module_tile_cb_modules(ModuleManager& module_manager,
const t_rr_type& cb_type,
const bool& compact_routing_hierarchy) {
/* If the CB does not exist, we can skip addition */
if ( (TRUE != is_cb_exist(cb_type, rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)))
|| (true != rr_gsb.is_cb_exist(cb_type))) {
if ( false == rr_gsb.is_cb_exist(cb_type)) {
return;
}
/* Skip if the cb does not contain any configuration bits! */
if (true == connection_block_contain_only_routing_tracks(rr_gsb, cb_type)) {
return;
}

View File

@ -52,51 +52,6 @@ void build_wire_module(ModuleManager& module_manager,
add_circuit_model_to_module_manager(module_manager, circuit_lib, wire_model);
}
/********************************************************************
* Build module of a routing track wire segment
* Routing track wire, which is 1-input and dual output
* This type of wires are used in the global routing architecture.
* One of the output is wired to another Switch block multiplexer,
* while the mid-output is wired to a Connection block multiplexer.
*
* | CLB |
* +------------+
* ^
* |
* +------------------------------+
* | Connection block multiplexer |
* +------------------------------+
* ^
* | mid-output +--------------
* +--------------------+ |
* input --->| Routing track wire |--------->| Switch Block
* +--------------------+ output |
* +--------------
*
*******************************************************************/
static
void build_routing_wire_module(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const CircuitModelId& wire_model,
const std::string& wire_subckt_name) {
/* Find the input port, output port*/
std::vector<CircuitPortId> input_ports = circuit_lib.model_ports_by_type(wire_model, SPICE_MODEL_PORT_INPUT, true);
std::vector<CircuitPortId> output_ports = circuit_lib.model_ports_by_type(wire_model, SPICE_MODEL_PORT_OUTPUT, true);
/* Make sure the port size is what we want */
VTR_ASSERT (1 == input_ports.size());
VTR_ASSERT (1 == output_ports.size());
VTR_ASSERT (1 == circuit_lib.port_size(input_ports[0]));
VTR_ASSERT (1 == circuit_lib.port_size(output_ports[0]));
/* Create a Verilog Module based on the circuit model, and add to module manager */
ModuleId wire_module = add_circuit_model_to_module_manager(module_manager, circuit_lib, wire_model, wire_subckt_name);
/* Add a mid-output port to the module */
BasicPort module_mid_output_port(generate_segment_wire_mid_output_name(circuit_lib.port_lib_name(output_ports[0])), circuit_lib.port_size(output_ports[0]));
module_manager.add_port(wire_module, module_mid_output_port, ModuleManager::MODULE_OUTPUT_PORT);
}
/********************************************************************
* This function will only create wire modules with a number of
* ports that are defined by users.
@ -104,8 +59,7 @@ void build_routing_wire_module(ModuleManager& module_manager,
* by Verilog/SPICE writers
*******************************************************************/
void build_wire_modules(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
std::vector<t_segment_inf> routing_segments) {
const CircuitLibrary& circuit_lib) {
/* Start time count */
clock_t t_start = clock();
@ -122,23 +76,6 @@ void build_wire_modules(ModuleManager& module_manager,
build_wire_module(module_manager, circuit_lib, wire_model);
}
for (const auto& seg : routing_segments) {
VTR_ASSERT( CircuitModelId::INVALID() != seg.circuit_model);
VTR_ASSERT( SPICE_MODEL_CHAN_WIRE == circuit_lib.model_type(seg.circuit_model));
/* Bypass user-defined circuit models */
if ( (!circuit_lib.model_spice_netlist(seg.circuit_model).empty())
&& (!circuit_lib.model_verilog_netlist(seg.circuit_model).empty()) ) {
continue;
}
/* Give a unique name for subckt of wire_model of segment,
* circuit_model name is unique, and segment id is unique as well
*/
std::string segment_wire_subckt_name = generate_segment_wire_subckt_name(circuit_lib.model_name(seg.circuit_model), &seg - &routing_segments[0]);
/* Print a Verilog module */
build_routing_wire_module(module_manager, circuit_lib, seg.circuit_model, segment_wire_subckt_name);
}
/* End time count */
clock_t t_end = clock();

View File

@ -14,7 +14,6 @@
#include "module_manager.h"
void build_wire_modules(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
std::vector<t_segment_inf> routing_segments);
const CircuitLibrary& circuit_lib);
#endif

View File

@ -2,8 +2,8 @@
* This function includes the writer for generating exchangeable
* information, in order to interface different simulators
********************************************************************/
#include <math.h>
#include <time.h>
#include <cmath>
#include <ctime>
#include <map>
#define MINI_CASE_SENSITIVE
#include "ini.h"
@ -18,17 +18,39 @@
#include "verilog_global.h"
#include "simulation_info_writer.h"
/*********************************************************************
* Local Variable
********************************************************************/
constexpr char* DEFAULT_SIMULATION_INI_FILE_NAME = "simulation_deck_info.ini";
/*********************************************************************
* Top-level function to write an ini file which contains exchangeable
* information, in order to interface different Verilog simulators
********************************************************************/
void print_verilog_simulation_info(const int &num_operating_clock_cycles,
const std::string &verilog_dir_formatted,
const std::string &chomped_circuit_name,
const std::string &src_dir_path,
const size_t &num_program_clock_cycles,
const float &prog_clock_freq,
const float &op_clock_freq) {
void print_verilog_simulation_info(const std::string& simulation_ini_filename,
const std::string& parent_dir,
const std::string& circuit_name,
const std::string& src_dir,
const size_t& num_program_clock_cycles,
const int& num_operating_clock_cycles,
const float& prog_clock_freq,
const float& op_clock_freq) {
/* Start time count */
clock_t t_start = clock();
/* Use default name if user does not provide one */
std::string ini_fname;
if (true == simulation_ini_filename.empty()) {
ini_fname = parent_dir + std::string(DEFAULT_SIMULATION_INI_FILE_NAME);
} else {
ini_fname = simulation_ini_filename;
}
vpr_printf(TIO_MESSAGE_INFO,
"Writing exchangeable file containing simulation information: %s...",
ini_fname.c_str());
mINI::INIStructure ini;
// std::map<char, int> units_map;
// units_map['s']=1; // units_map['ms']=1E-3; // units_map['us']=1E-6;
@ -40,16 +62,23 @@ void print_verilog_simulation_info(const int &num_operating_clock_cycles,
1. / prog_clock_freq,
num_operating_clock_cycles,
1. / op_clock_freq);
ini["SIMULATION_DECK"]["PROJECTNAME "] = "ModelSimProject";
ini["SIMULATION_DECK"]["BENCHMARK "] = chomped_circuit_name;
ini["SIMULATION_DECK"]["TOP_TB"] = chomped_circuit_name + std::string("_top_formal_verification_random_tb");
ini["SIMULATION_DECK"]["BENCHMARK "] = circuit_name;
ini["SIMULATION_DECK"]["TOP_TB"] = circuit_name + std::string("_top_formal_verification_random_tb");
ini["SIMULATION_DECK"]["SIMTIME "] = std::to_string(simulation_time_period);
ini["SIMULATION_DECK"]["UNIT "] = "ms";
ini["SIMULATION_DECK"]["VERILOG_PATH "] = std::string(src_dir_path);
ini["SIMULATION_DECK"]["VERILOG_PATH "] = std::string(src_dir);
ini["SIMULATION_DECK"]["VERILOG_FILE1"] = std::string(defines_verilog_file_name);
ini["SIMULATION_DECK"]["VERILOG_FILE2"] = std::string(chomped_circuit_name + "_include_netlists.v");
ini["SIMULATION_DECK"]["VERILOG_FILE2"] = std::string(circuit_name + "_include_netlists.v");
mINI::INIFile file("SimulationDeckInfo.ini");
mINI::INIFile file(ini_fname);
file.generate(ini, true);
/* End time count */
clock_t t_end = clock();
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
vpr_printf(TIO_MESSAGE_INFO,
"took %g seconds\n",
run_time_sec);
}

View File

@ -3,11 +3,12 @@
#include <string>
void print_verilog_simulation_info(const int &num_operating_clock_cycles,
const std::string &verilog_dir_formatted,
const std::string &chomped_circuit_name,
const std::string &src_dir_path,
const size_t &num_program_clock_cycles,
const float &prog_clock_freq,
const float &op_clock_freq);
void print_verilog_simulation_info(const std::string& simulation_ini_filename,
const std::string& parent_dir,
const std::string& circuit_name,
const std::string& src_dir,
const size_t& num_program_clock_cycles,
const int& num_operating_clock_cycles,
const float& prog_clock_freq,
const float& op_clock_freq);
#endif

View File

@ -61,7 +61,7 @@
#include "verilog_sdc.h"
#include "verilog_formality_autodeck.h"
#include "verilog_sdc_pb_types.h"
#include "verilog_include_netlists.h"
#include "verilog_auxiliary_netlists.h"
#include "simulation_info_writer.h"
#include "verilog_api.h"
@ -152,14 +152,10 @@ void vpr_fpga_verilog(ModuleManager& module_manager,
char* fm_dir_path = NULL;
char* top_netlist_file = NULL;
char* top_netlist_path = NULL;
char* top_testbench_file_name = NULL;
char* top_testbench_file_path = NULL;
char* blif_testbench_file_name = NULL;
char* blif_testbench_file_path = NULL;
char* bitstream_file_name = NULL;
char* bitstream_file_path = NULL;
char* autocheck_top_testbench_file_name = NULL;
char* autocheck_top_testbench_file_path = NULL;
char* chomped_parent_dir = NULL;
char* chomped_circuit_name = NULL;
@ -268,11 +264,16 @@ void vpr_fpga_verilog(ModuleManager& module_manager,
init_pb_types_num_iopads();
/* init_grids_num_mode_bits(); */
dump_verilog_defines_preproc(src_dir_path,
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts);
/* Print Verilog files containing preprocessing flags */
print_verilog_preprocessing_flags_netlist(std::string(src_dir_path),
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts);
print_verilog_simulation_preprocessing_flags(std::string(src_dir_path),
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts);
/*
dump_verilog_simulation_preproc(src_dir_path,
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts);
*/
/* Generate primitive Verilog modules, which are corner stones of FPGA fabric
* Note that this function MUST be called before Verilog generation of
@ -390,19 +391,21 @@ void vpr_fpga_verilog(ModuleManager& module_manager,
my_free(bitstream_file_path);
}
/* dump verilog testbench only for top-level: ONLY valid when bitstream is generated! */
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_top_testbench) {
top_testbench_file_name = my_strcat(chomped_circuit_name, top_testbench_verilog_file_postfix);
top_testbench_file_path = my_strcat(src_dir_path, top_testbench_file_name);
dump_verilog_top_testbench(sram_verilog_orgz_info, chomped_circuit_name, top_testbench_file_path,
src_dir_path, *(Arch.spice));
/* Free */
my_free(top_testbench_file_name);
my_free(top_testbench_file_path);
}
/* Collect global ports from the circuit library
* TODO: move outside this function
*/
std::vector<CircuitPortId> global_ports = find_circuit_library_global_ports(Arch.spice->circuit_lib);
/* dump verilog testbench only for top-level: ONLY valid when bitstream is generated! */
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_top_testbench) {
std::string top_testbench_file_path = std::string(src_dir_path)
+ std::string(chomped_circuit_name)
+ std::string(top_testbench_verilog_file_postfix);
/* TODO: this is an old function, to be shadowed */
dump_verilog_top_testbench(sram_verilog_orgz_info, chomped_circuit_name, top_testbench_file_path.c_str(),
src_dir_path, *(Arch.spice));
}
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_formal_verification_top_netlist) {
std::string formal_verification_top_netlist_file_path = std::string(src_dir_path)
+ std::string(chomped_circuit_name)
@ -431,21 +434,43 @@ void vpr_fpga_verilog(ModuleManager& module_manager,
print_verilog_random_top_testbench(std::string(chomped_circuit_name), random_top_testbench_file_path,
std::string(src_dir_path), L_logical_blocks,
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, Arch.spice->spice_params);
print_verilog_simulation_info(Arch.spice->spice_params.meas_params.sim_num_clock_cycle,
std::string(msim_dir_path),
}
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_simulation_ini) {
/* Print exchangeable files which contains simulation settings */
std::string simulation_ini_file_name;
if (NULL != vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.simulation_ini_path) {
simulation_ini_file_name = std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.simulation_ini_path);
}
print_verilog_simulation_info(simulation_ini_file_name,
std::string(format_dir_path(chomped_parent_dir)),
std::string(chomped_circuit_name),
std::string(src_dir_path),
bitstream_manager.bits().size(),
Arch.spice->spice_params.meas_params.sim_num_clock_cycle,
Arch.spice->spice_params.stimulate_params.prog_clock_freq,
Arch.spice->spice_params.stimulate_params.op_clock_freq);
}
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_autocheck_top_testbench) {
autocheck_top_testbench_file_name = my_strcat(chomped_circuit_name, autocheck_top_testbench_verilog_file_postfix);
autocheck_top_testbench_file_path = my_strcat(src_dir_path, autocheck_top_testbench_file_name);
std::string autocheck_top_testbench_file_path = std::string(src_dir_path)
+ std::string(chomped_circuit_name)
+ std::string(autocheck_top_testbench_verilog_file_postfix);
/* TODO: this is an old function, to be shadowed */
/*
dump_verilog_autocheck_top_testbench(sram_verilog_orgz_info, chomped_circuit_name,
autocheck_top_testbench_file_path, src_dir_path,
autocheck_top_testbench_file_path.c_str(), src_dir_path,
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, *(Arch.spice));
*/
/* TODO: new function: to be tested */
print_verilog_top_testbench(module_manager, bitstream_manager, fabric_bitstream,
sram_verilog_orgz_info->type,
Arch.spice->circuit_lib, global_ports,
L_logical_blocks, device_size, L_grids, L_blocks,
std::string(chomped_circuit_name),
autocheck_top_testbench_file_path,
std::string(src_dir_path),
Arch.spice->spice_params);
}
/* Output Modelsim Autodeck scripts */
@ -489,9 +514,15 @@ void vpr_fpga_verilog(ModuleManager& module_manager,
sram_verilog_orgz_info->type);
}
write_include_netlists(src_dir_path,
chomped_circuit_name,
*(Arch.spice) );
/* Print a Verilog file including all the netlists that have been generated */
std::string ref_verilog_benchmark_file_name;
if (NULL != vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.reference_verilog_benchmark_file) {
ref_verilog_benchmark_file_name = std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.reference_verilog_benchmark_file);
}
print_include_netlists(std::string(src_dir_path),
std::string(chomped_circuit_name),
ref_verilog_benchmark_file_name,
Arch.spice->circuit_lib);
vpr_printf(TIO_MESSAGE_INFO, "Outputted %lu Verilog modules in total.\n", module_manager.num_modules());

View File

@ -348,7 +348,7 @@ void dump_verilog_top_auto_testbench_check(FILE* fp){
void dump_verilog_autocheck_top_testbench(t_sram_orgz_info* cur_sram_orgz_info,
char* circuit_name,
char* top_netlist_name,
const char* top_netlist_name,
char* verilog_dir_path,
t_syn_verilog_opts fpga_verilog_opts,
t_spice verilog) {

Some files were not shown because too many files have changed in this diff Show More