Merge remote-tracking branch 'origin/master' into ganesh_dev

This commit is contained in:
Ganesh Gore 2020-12-01 11:29:15 -07:00
commit fd7a65c756
51 changed files with 2510 additions and 1355 deletions

90
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,90 @@
name: linux_build
# Run CI on
# - each push
# - each pull request
# - scheduled weekly
on:
push:
pull_request:
schedule:
- cron: '0 0 * * 0 ' # weekly
# Environment variables
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release
MAKEFLAGS: "-j8"
# Multiple job to tests
jobs:
# Test the compilation compatibility
linux_build:
name: ${{ matrix.config.name }}
runs-on: ${{ matrix.config.os }}
# Branch on different OS and settings
strategy:
fail-fast: false
matrix:
config:
- {
name: "Quick Test: GCC-8 (Ubuntu 18.04)",
artifact: "OpenFPGA-basic-tests-ubuntu-18.04-gcc8-build.7z",
os: ubuntu-18.04,
cc: "gcc-8", cxx: "g++-8",
reg_script: "quick_test.sh"
}
# Define the steps to run the build job
steps:
- name: Checkout Skywater-OpenFPGA repo
uses: actions/checkout@v2
- name: Checkout OpenFPGA repo
uses: actions/checkout@v2
with:
repository: LNIS-Projects/OpenFPGA
path: OpenFPGA
- name: Install dependency
run: source ./.github/workflows/install_dependency.sh
- name: Checkout CMake version
run: cmake --version
- name: Checkout iVerilog version
run: |
iverilog -V
vvp -V
- name: Create CMake build environment
# Some projects don't allow in-source building, so create a separate build directory
# We'll use this as our working directory for all subsequent commands
run: cmake -E make_directory ${{runner.workspace}}/OpenFPGA/build
- name: Configure CMake
# Use a bash shell so we can use the same syntax for environment variable
# access regardless of the host operating system
shell: bash
working-directory: ${{runner.workspace}}/OpenFPGA/build
# Note the current convention is to use the -S and -B options here to specify source
# and build directories, but this is only available with CMake 3.13 and higher.
# The CMake binaries on the Github Actions machines are (as of this writing) 3.12
run: |
export CC=${{ matrix.config.cc }}
export CXX=${{ matrix.config.cxx }}
cmake $GITHUB_WORKSPACE/OpenFPGA -DCMAKE_BUILD_TYPE=$BUILD_TYPE
- name: Build
working-directory: ${{runner.workspace}}/OpenFPGA/build
shell: bash
# Execute the build. You can specify a specific target with "--target <NAME>"
run: |
cmake --build . --config $BUILD_TYPE
- name: ${{matrix.config.name}}
if: contains(matrix.config.name, 'Quick Test')
shell: bash
# Execute the test.
run: source ./.github/workflows/${{matrix.config.reg_script}}

48
.github/workflows/install_dependency.sh vendored Normal file
View File

@ -0,0 +1,48 @@
# Install all the dependency for OpenFPGA in Ubuntu-18.04
sudo apt-get update
sudo apt-get install autoconf
sudo apt-get install automake
sudo apt-get install bash
sudo apt-get install bison
sudo apt-get install build-essential
sudo apt-get install cmake
sudo apt-get install ccache
sudo apt-get install ctags
sudo apt-get install curl
sudo apt-get install doxygen
sudo apt-get install flex
sudo apt-get install fontconfig
sudo apt-get install gdb
sudo apt-get install git
sudo apt-get install gperf
sudo apt-get install iverilog
sudo apt-get install libcairo2-dev
sudo apt-get install libevent-dev
sudo apt-get install libfontconfig1-dev
sudo apt-get install liblist-moreutils-perl
sudo apt-get install libncurses5-dev
sudo apt-get install libx11-dev
sudo apt-get install libxft-dev
sudo apt-get install libxml++2.6-dev
sudo apt-get install perl
sudo apt-get install python
sudo apt-get install python-lxml
sudo apt-get install texinfo
sudo apt-get install time
sudo apt-get install valgrind
sudo apt-get install zip
sudo apt-get install qt5-default
sudo apt-get install clang-format-7
# Add all the supported compilers
sudo apt-get install g++-5
sudo apt-get install gcc-5
sudo apt-get install g++-6
sudo apt-get install gcc-6
sudo apt-get install g++-7
sudo apt-get install gcc-7
sudo apt-get install g++-8
sudo apt-get install gcc-8
sudo apt-get install g++-9
sudo apt-get install gcc-9
sudo apt-get install clang-6.0
sudo apt-get install clang-8

20
.github/workflows/quick_test.sh vendored Executable file
View File

@ -0,0 +1,20 @@
#!/bin/bash
set -e
###############################################
# OpenFPGA Shell with VPR8
##############################################
##############################################
# Initialize the repository
# - Generate final version of architecture files
# - Run FPGA tasks to validate netlist generations
python3 SCRIPT/repo_setup.py --openfpga_root_path ./OpenFPGA
##############################################
# Generate post-PnR testbenches
python3 TESTBENCH/common/generate_post_pnr_testbenches.py --pre_pnr_testbench_dir_name ./TESTBENCH/k4_N8_caravel_io_FPGA_12x12_fdhd_cc --pin_assignment_file ./HDL/common/caravel_wrapper_pin_assignment_v1.0.json
python3 TESTBENCH/common/generate_post_pnr_testbenches.py --pre_pnr_testbench_dir_name ./TESTBENCH/k4_N8_reset_caravel_io_FPGA_12x12_fdhd_cc --pin_assignment_file ./HDL/common/caravel_wrapper_pin_assignment_v1.1.json
python3 TESTBENCH/common/generate_post_pnr_testbenches.py --pre_pnr_testbench_dir_name ./TESTBENCH/k4_N8_softadder_caravel_io_FPGA_12x12_fdhd_cc --pin_assignment_file ./HDL/common/caravel_wrapper_pin_assignment_v1.0.json
python3 TESTBENCH/common/generate_post_pnr_testbenches.py --pre_pnr_testbench_dir_name ./TESTBENCH/k4_N8_reset_softadder_caravel_io_FPGA_12x12_fdhd_cc --pin_assignment_file ./HDL/common/caravel_wrapper_pin_assignment_v1.1.json

View File

@ -181,7 +181,7 @@
<port type="input" prefix="D" size="1"/>
<port type="output" prefix="Q" size="1"/>
<port type="clock" prefix="prog_clk" lib_name="CLK" size="1" is_global="true" default_val="0" is_prog="true"/>
<port type="input" prefix="prog_reset" lib_name="RESET_B" size="1" is_global="true" default_val="1" is_prog="true" is_reset="true"/>
<port type="input" prefix="pReset" lib_name="RESET_B" size="1" is_global="true" default_val="1" is_prog="true" is_reset="true"/>
</circuit_model>
<circuit_model type="iopad" name="EMBEDDED_IO_HD" prefix="EMBEDDED_IO_HD" is_default="true" verilog_netlist="${SKYWATER_OPENFPGA_HOME}/HDL/common/digital_io_hd.v">
<design_technology type="cmos"/>

View File

@ -0,0 +1,268 @@
<!-- Architecture annotation for OpenFPGA framework
This annotation supports the k4_frac_cc_sky130nm.xml
- General purpose logic block
- K = 6, N = 10, I = 40
- Single mode
- Routing architecture
- L = 4, fc_in = 0.15, fc_out = 0.1
- Skywater 130nm PDK
- circuit models are binded to the opensource skywater
foundry middle-speed (ms) standard cell library
-->
<openfpga_architecture>
<technology_library>
<device_library>
<device_model name="logic" type="transistor">
<lib type="industry" corner="TOP_TT" ref="M" path="${OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.pm"/>
<design vdd="0.9" pn_ratio="2"/>
<pmos name="pch" chan_length="40e-9" min_width="140e-9" variation="logic_transistor_var"/>
<nmos name="nch" chan_length="40e-9" min_width="140e-9" variation="logic_transistor_var"/>
</device_model>
<device_model name="io" type="transistor">
<lib type="academia" ref="M" path="${OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.pm"/>
<design vdd="2.5" pn_ratio="3"/>
<pmos name="pch_25" chan_length="270e-9" min_width="320e-9" variation="io_transistor_var"/>
<nmos name="nch_25" chan_length="270e-9" min_width="320e-9" variation="io_transistor_var"/>
</device_model>
</device_library>
<variation_library>
<variation name="logic_transistor_var" abs_deviation="0.1" num_sigma="3"/>
<variation name="io_transistor_var" abs_deviation="0.1" num_sigma="3"/>
</variation_library>
</technology_library>
<circuit_library>
<circuit_model type="inv_buf" name="sky130_fd_sc_hd__inv_1" prefix="sky130_fd_sc_hd__inv_1" is_default="true" verilog_netlist="${SKYWATER_OPENFPGA_HOME}/PDK/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/inv/sky130_fd_sc_hd__inv_1.v">
<design_technology type="cmos" topology="inverter" size="1"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" lib_name="A" size="1"/>
<port type="output" prefix="out" lib_name="Y" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="inv_buf" name="sky130_fd_sc_hd__buf_2" prefix="sky130_fd_sc_hd__buf_2" is_default="false" verilog_netlist="${SKYWATER_OPENFPGA_HOME}/PDK/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/buf/sky130_fd_sc_hd__buf_2.v">
<design_technology type="cmos" topology="buffer" size="1" num_level="2" f_per_stage="2"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" lib_name="A" size="1"/>
<port type="output" prefix="out" lib_name="X" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="inv_buf" name="sky130_fd_sc_hd__buf_4" prefix="sky130_fd_sc_hd__buf_4" is_default="false" verilog_netlist="${SKYWATER_OPENFPGA_HOME}/PDK/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/buf/sky130_fd_sc_hd__buf_4.v">
<design_technology type="cmos" topology="buffer" size="1" num_level="2" f_per_stage="4"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" lib_name="A" size="1"/>
<port type="output" prefix="out" lib_name="X" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="inv_buf" name="sky130_fd_sc_hd__inv_2" prefix="sky130_fd_sc_hd__inv_2" is_default="false" verilog_netlist="${SKYWATER_OPENFPGA_HOME}/PDK/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/inv/sky130_fd_sc_hd__inv_2.v">
<design_technology type="cmos" topology="buffer" size="1"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" lib_name="A" size="1"/>
<port type="output" prefix="out" lib_name="Y" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="gate" name="sky130_fd_sc_hd__or2_1" prefix="sky130_fd_sc_hd__or2_1" is_default="true" verilog_netlist="${SKYWATER_OPENFPGA_HOME}/PDK/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/or2/sky130_fd_sc_hd__or2_1.v">
<design_technology type="cmos" topology="OR"/>
<device_technology device_model_name="logic"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="a" lib_name="A" size="1"/>
<port type="input" prefix="b" lib_name="B" size="1"/>
<port type="output" prefix="out" lib_name="X" size="1"/>
<delay_matrix type="rise" in_port="a b" out_port="out">
10e-12 5e-12
</delay_matrix>
<delay_matrix type="fall" in_port="a b" out_port="out">
10e-12 5e-12
</delay_matrix>
</circuit_model>
<!-- Define a circuit model for the standard cell MUX2
OpenFPGA requires the following truth table for the MUX2
When the select signal sel is enabled, the first input, i.e., in0
will be propagated to the output, i.e., out
If your standard cell provider does not offer the exact truth table,
you can simply swap the inputs as shown in the example below
-->
<circuit_model type="gate" name="sky130_fd_sc_hd__mux2_1" prefix="sky130_fd_sc_hd__mux2_1" verilog_netlist="${SKYWATER_OPENFPGA_HOME}/PDK/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/mux2/sky130_fd_sc_hd__mux2_1.v">
<design_technology type="cmos" topology="MUX2"/>
<device_technology device_model_name="logic"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="in0" lib_name="A1" size="1"/>
<port type="input" prefix="in1" lib_name="A0" size="1"/>
<port type="input" prefix="sel" lib_name="S" size="1"/>
<port type="output" prefix="out" lib_name="X" size="1"/>
</circuit_model>
<circuit_model type="chan_wire" name="chan_segment" prefix="track_seg" is_default="true">
<design_technology type="cmos"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<wire_param model_type="pi" R="101" C="22.5e-15" num_level="1"/>
<!-- model_type could be T, res_val and cap_val DON'T CARE -->
</circuit_model>
<circuit_model type="wire" name="direct_interc" prefix="direct_interc" is_default="true">
<design_technology type="cmos"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<wire_param model_type="pi" R="0" C="0" num_level="1"/>
<!-- model_type could be T, res_val cap_val should be defined -->
</circuit_model>
<circuit_model type="mux" name="mux_tree" prefix="mux_tree" is_default="true" dump_structural_verilog="true">
<design_technology type="cmos" structure="tree" add_const_input="true" const_input_val="1"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<pass_gate_logic circuit_model_name="sky130_fd_sc_hd__mux2_1"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<port type="sram" prefix="sram" size="1"/>
</circuit_model>
<circuit_model type="mux" name="mux_tree_tapbuf" prefix="mux_tree_tapbuf" dump_structural_verilog="true">
<design_technology type="cmos" structure="tree" add_const_input="true" const_input_val="1"/>
<input_buffer exist="false"/>
<output_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__buf_4"/>
<pass_gate_logic circuit_model_name="sky130_fd_sc_hd__mux2_1"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<port type="sram" prefix="sram" size="1"/>
</circuit_model>
<!--DFF subckt ports should be defined as <D> <Q> <CLK> <RESET> <SET> -->
<circuit_model type="ff" name="sky130_fd_sc_hd__sdfrtp_1" prefix="sky130_fd_sc_hd__sdfrtp_1" verilog_netlist="${SKYWATER_OPENFPGA_HOME}/PDK/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/sdfrtp/sky130_fd_sc_hd__sdfrtp_1.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<output_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<port type="input" prefix="D" size="1"/>
<port type="input" prefix="DI" lib_name="SCD" size="1"/>
<port type="input" prefix="Test_en" lib_name="SCE" size="1" is_global="true" default_val="0"/>
<port type="input" prefix="reset" lib_name="RESET_B" size="1" default_val="1"/>
<port type="output" prefix="Q" size="1"/>
<port type="clock" prefix="clk" lib_name="CLK" size="1" is_global="false" default_val="0" />
</circuit_model>
<circuit_model type="lut" name="frac_lut4" prefix="frac_lut4" dump_structural_verilog="true">
<design_technology type="cmos" fracturable_lut="true"/>
<input_buffer exist="false"/>
<output_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__buf_2"/>
<lut_input_inverter exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<lut_input_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__buf_2"/>
<lut_intermediate_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__buf_2" location_map="-1-"/>
<pass_gate_logic circuit_model_name="sky130_fd_sc_hd__mux2_1"/>
<port type="input" prefix="in" size="4" tri_state_map="---1" circuit_model_name="sky130_fd_sc_hd__or2_1"/>
<port type="output" prefix="lut2_out" size="2" lut_frac_level="2" lut_output_mask="2,3"/>
<port type="output" prefix="lut3_out" size="2" lut_frac_level="3" lut_output_mask="0,1"/>
<port type="output" prefix="lut4_out" size="1" lut_output_mask="0"/>
<port type="sram" prefix="sram" size="16"/>
<port type="sram" prefix="mode" size="1" mode_select="true" circuit_model_name="sky130_fd_sc_hd__dfrtp_1" default_val="1"/>
</circuit_model>
<!--Scan-chain DFF subckt ports should be defined as <D> <Q> <Qb> <CLK> <RESET> <SET> -->
<circuit_model type="ccff" name="sky130_fd_sc_hd__dfrtp_1" prefix="sky130_fd_sc_hd__dfrtp_1" verilog_netlist="${SKYWATER_OPENFPGA_HOME}/PDK/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/dfrtp/sky130_fd_sc_hd__dfrtp_1.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<output_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<port type="input" prefix="D" size="1"/>
<port type="output" prefix="Q" size="1"/>
<port type="clock" prefix="prog_clk" lib_name="CLK" size="1" is_global="true" default_val="0" is_prog="true"/>
<port type="input" prefix="pReset" lib_name="RESET_B" size="1" is_global="true" default_val="1" is_prog="true" is_reset="true"/>
</circuit_model>
<circuit_model type="iopad" name="EMBEDDED_IO_HD" prefix="EMBEDDED_IO_HD" is_default="true" verilog_netlist="${SKYWATER_OPENFPGA_HOME}/HDL/common/digital_io_hd.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<output_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<port type="input" prefix="SOC_IN" lib_name="SOC_IN" size="1" is_global="true" is_io="true" is_data_io="true"/>
<port type="output" prefix="SOC_OUT" lib_name="SOC_OUT" size="1" is_global="true" is_io="true" is_data_io="true"/>
<port type="output" prefix="SOC_DIR" lib_name="SOC_DIR" size="1" is_global="true" is_io="true"/>
<port type="input" prefix="IO_ISOL_N" lib_name="IO_ISOL_N" size="1" is_global="true" default_val="1"/>
<port type="output" prefix="inpad" lib_name="FPGA_IN" size="1"/>
<port type="input" prefix="outpad" lib_name="FPGA_OUT" size="1"/>
<port type="sram" prefix="en" lib_name="FPGA_DIR" size="1" mode_select="true" circuit_model_name="sky130_fd_sc_hd__dfrtp_1" default_val="1"/>
</circuit_model>
<circuit_model type="hard_logic" name="sky130_fd_sc_hd__mux2_1_wrapper" prefix="sky130_fd_sc_hd__mux2_1_wrapper" verilog_netlist="${SKYWATER_OPENFPGA_HOME}/HDL/common/sky130_fd_sc_hd_wrapper.v">
<design_technology type="cmos"/>
<device_technology device_model_name="logic"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="a" lib_name="A0" size="1"/>
<port type="input" prefix="b" lib_name="A1" size="1"/>
<port type="input" prefix="cin" lib_name="S" size="1"/>
<port type="output" prefix="cout" lib_name="X" size="1"/>
</circuit_model>
</circuit_library>
<configuration_protocol>
<organization type="scan_chain" circuit_model_name="sky130_fd_sc_hd__dfrtp_1" num_regions="1"/>
</configuration_protocol>
<connection_block>
<switch name="ipin_cblock" circuit_model_name="mux_tree_tapbuf"/>
</connection_block>
<switch_block>
<switch name="L1_mux" circuit_model_name="mux_tree_tapbuf"/>
<switch name="L2_mux" circuit_model_name="mux_tree_tapbuf"/>
<switch name="L4_mux" circuit_model_name="mux_tree_tapbuf"/>
</switch_block>
<routing_segment>
<segment name="L1" circuit_model_name="chan_segment"/>
<segment name="L2" circuit_model_name="chan_segment"/>
<segment name="L4" circuit_model_name="chan_segment"/>
</routing_segment>
<direct_connection>
<direct name="carry_chain" circuit_model_name="direct_interc"/>
<direct name="shift_register" circuit_model_name="direct_interc"/>
<direct name="scan_chain" circuit_model_name="direct_interc" type="column" x_dir="positive" y_dir="positive"/>
</direct_connection>
<tile_annotations>
<global_port name="clk" tile_port="clb.clk" is_clock="true" default_val="0"/>
<global_port name="reset" tile_port="clb.reset" is_reset="true" default_val="1"/>
</tile_annotations>
<pb_type_annotations>
<!-- physical pb_type binding in complex block IO -->
<pb_type name="io" physical_mode_name="physical" idle_mode_name="inpad"/>
<!-- IMPORTANT: must set unused I/Os to operating in INPUT mode !!! -->
<pb_type name="io[physical].iopad" circuit_model_name="EMBEDDED_IO_HD" mode_bits="1"/>
<pb_type name="io[inpad].inpad" physical_pb_type_name="io[physical].iopad" mode_bits="1"/>
<pb_type name="io[outpad].outpad" physical_pb_type_name="io[physical].iopad" mode_bits="0"/>
<!-- End physical pb_type binding in complex block IO -->
<!-- physical pb_type binding in complex block CLB -->
<!-- physical mode will be the default mode if not specified -->
<pb_type name="clb.fle" physical_mode_name="physical"/>
<pb_type name="clb.fle[physical].fabric.frac_logic.frac_lut4" circuit_model_name="frac_lut4" mode_bits="0"/>
<pb_type name="clb.fle[physical].fabric.frac_logic.carry_follower" circuit_model_name="sky130_fd_sc_hd__mux2_1_wrapper"/>
<pb_type name="clb.fle[physical].fabric.ff" circuit_model_name="sky130_fd_sc_hd__sdfrtp_1"/>
<!-- Binding operating pb_type to physical pb_type -->
<pb_type name="clb.fle[n2_lut3].lut3inter.ble3.lut3" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.frac_lut4" mode_bits="1" physical_pb_type_index_factor="0.5">
<!-- Binding the lut3 to the first 3 inputs of fracturable lut4 -->
<port name="in" physical_mode_port="in[0:2]"/>
<port name="out" physical_mode_port="lut3_out[0:0]" physical_mode_pin_rotate_offset="1"/>
</pb_type>
<pb_type name="clb.fle[n2_lut3].lut3inter.ble3.ff" physical_pb_type_name="clb.fle[physical].fabric.ff"/>
<!-- Binding operating pb_types in mode 'ble4' -->
<pb_type name="clb.fle[n1_lut4].ble4.lut4" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.frac_lut4" mode_bits="0">
<!-- Binding the lut4 to the first 4 inputs of fracturable lut4 -->
<port name="in" physical_mode_port="in[0:3]"/>
<port name="out" physical_mode_port="lut4_out"/>
</pb_type>
<pb_type name="clb.fle[n1_lut4].ble4.ff" physical_pb_type_name="clb.fle[physical].fabric.ff" physical_pb_type_index_factor="2" physical_pb_type_index_offset="0"/>
<!-- Binding operating pb_types in mode 'shift_register' -->
<pb_type name="clb.fle[shift_register].shift_reg.ff" physical_pb_type_name="clb.fle[physical].fabric.ff"/>
<!-- End physical pb_type binding in complex block IO -->
</pb_type_annotations>
</openfpga_architecture>

View File

@ -187,6 +187,16 @@
<output_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<port type="output" prefix="a" lib_name="Y" size="1"/>
</circuit_model>
<circuit_model type="hard_logic" name="sky130_fd_sc_hd__mux2_1_wrapper" prefix="sky130_fd_sc_hd__mux2_1_wrapper" verilog_netlist="${SKYWATER_OPENFPGA_HOME}/HDL/common/sky130_fd_sc_hd_wrapper.v">
<design_technology type="cmos"/>
<device_technology device_model_name="logic"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="a" lib_name="A0" size="1"/>
<port type="input" prefix="b" lib_name="A1" size="1"/>
<port type="input" prefix="cin" lib_name="S" size="1"/>
<port type="output" prefix="cout" lib_name="X" size="1"/>
</circuit_model>
</circuit_library>
<configuration_protocol>
<organization type="scan_chain" circuit_model_name="sky130_fd_sc_hd__dfxtp_1" num_regions="1"/>
@ -220,7 +230,7 @@
<pb_type name="SUPER_LOGIC_CELL.LC" physical_mode_name="PHYSICAL"/>
<pb_type name="SUPER_LOGIC_CELL.LC[PHYSICAL].PHYSICAL.frac_logic.frac_lut4" circuit_model_name="frac_lut4" mode_bits="0"/>
<pb_type name="SUPER_LOGIC_CELL.LC[PHYSICAL].PHYSICAL.ff" circuit_model_name="sky130_fd_sc_hd__dfxtp_1"/>
<pb_type name="SUPER_LOGIC_CELL.LC[PHYSICAL].PHYSICAL.co_mux" circuit_model_name="sky130_fd_sc_hd__mux2_1"/>
<pb_type name="clb.fle[physical].fabric.frac_logic.carry_follower" circuit_model_name="sky130_fd_sc_hd__mux2_1_wrapper"/>
<!-- BEGIN Binding operating pb_types in mode 'ble4' -->
<pb_type name="SUPER_LOGIC_CELL.LC[DEFAULT].DEFAULT.lut_part[VPR_LUT4].VPR_LUT4.lut_inst" physical_pb_type_name="SUPER_LOGIC_CELL.LC[PHYSICAL].PHYSICAL.frac_logic.frac_lut4" mode_bits="0">
<!-- Binding the lut4 to the first 4 inputs of fracturable lut4 -->

View File

@ -0,0 +1,737 @@
<!--
Low-cost homogeneous FPGA Architecture.
- Skywater 130 nm technology
- General purpose logic block:
K = 4, N = 8, fracturable 4 LUTs (can operate as one 4-LUT or two 3-LUTs with all 3 inputs shared)
with optionally registered outputs
- Routing architecture:
- 10% L = 1, fc_in = 0.15, Fc_out = 0.10
- 10% L = 2, fc_in = 0.15, Fc_out = 0.10
- 80% L = 4, fc_in = 0.15, Fc_out = 0.10
- 100 routing tracks per channel
Authors: Xifan Tang
-->
<architecture>
<!--
ODIN II specific config begins
Describes the types of user-specified netlist blocks (in blif, this corresponds to
".model [type_of_block]") that this architecture supports.
Note: Basic LUTs, I/Os, and flip-flops are not included here as there are
already special structures in blif (.names, .input, .output, and .latch)
that describe them.
-->
<models>
<!-- A virtual model for I/O to be used in the physical mode of io block -->
<model name="io">
<input_ports>
<port name="outpad"/>
</input_ports>
<output_ports>
<port name="inpad"/>
</output_ports>
</model>
<model name="frac_lut4">
<input_ports>
<port name="in"/>
</input_ports>
<output_ports>
<port name="lut2_out"/>
<port name="lut3_out"/>
<port name="lut4_out"/>
</output_ports>
</model>
<model name="carry_follower">
<input_ports>
<port name="a"/>
<port name="b"/>
<port name="cin"/>
</input_ports>
<output_ports>
<port name="cout"/>
</output_ports>
</model>
<!-- A virtual model for scan-chain flip-flop to be used in the physical mode of FF -->
<model name="scff">
<input_ports>
<port name="D" clock="clk"/>
<port name="DI" clock="clk"/>
<port name="reset" clock="clk"/>
<port name="clk" is_clock="1"/>
</input_ports>
<output_ports>
<port name="Q" clock="clk"/>
</output_ports>
</model>
</models>
<tiles>
<!-- Do NOT add clock pins to I/O here!!! VPR does not build clock network in the way that OpenFPGA can support
If you need to register the I/O, define clocks in the circuit models
These clocks can be handled in back-end
-->
<!-- Top-side has 1 I/O per tile -->
<tile name="io_top" capacity="1" area="0">
<equivalent_sites>
<site pb_type="io"/>
</equivalent_sites>
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10"/>
<pinlocations pattern="custom">
<loc side="bottom">io_top.outpad io_top.inpad</loc>
</pinlocations>
</tile>
<!-- Right-side has 1 I/O per tile -->
<tile name="io_right" capacity="1" area="0">
<equivalent_sites>
<site pb_type="io"/>
</equivalent_sites>
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10"/>
<pinlocations pattern="custom">
<loc side="left">io_right.outpad io_right.inpad</loc>
</pinlocations>
</tile>
<!-- Bottom-side has 9 I/O per tile -->
<tile name="io_bottom" capacity="9" area="0">
<equivalent_sites>
<site pb_type="io"/>
</equivalent_sites>
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10"/>
<pinlocations pattern="custom">
<loc side="top">io_bottom.outpad io_bottom.inpad</loc>
</pinlocations>
</tile>
<!-- Left-side has 1 I/O per tile -->
<tile name="io_left" capacity="1" area="0">
<equivalent_sites>
<site pb_type="io"/>
</equivalent_sites>
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10"/>
<pinlocations pattern="custom">
<loc side="right">io_left.outpad io_left.inpad</loc>
</pinlocations>
</tile>
<!-- CLB has most pins on the top and right sides -->
<tile name="clb" area="53894">
<equivalent_sites>
<site pb_type="clb"/>
</equivalent_sites>
<input name="I0" num_pins="2" equivalent="full"/>
<input name="I0i" num_pins="2" equivalent="none"/>
<input name="I1" num_pins="2" equivalent="full"/>
<input name="I1i" num_pins="2" equivalent="none"/>
<input name="I2" num_pins="2" equivalent="full"/>
<input name="I2i" num_pins="2" equivalent="none"/>
<input name="I3" num_pins="2" equivalent="full"/>
<input name="I3i" num_pins="2" equivalent="none"/>
<input name="I4" num_pins="2" equivalent="full"/>
<input name="I4i" num_pins="2" equivalent="none"/>
<input name="I5" num_pins="2" equivalent="full"/>
<input name="I5i" num_pins="2" equivalent="none"/>
<input name="I6" num_pins="2" equivalent="full"/>
<input name="I6i" num_pins="2" equivalent="none"/>
<input name="I7" num_pins="2" equivalent="full"/>
<input name="I7i" num_pins="2" equivalent="none"/>
<input name="reg_in" num_pins="1"/>
<input name="sc_in" num_pins="1"/>
<input name="cin" num_pins="1"/>
<input name="reset" num_pins="1" is_non_clock_global="true"/>
<output name="O" num_pins="16" equivalent="none"/>
<output name="reg_out" num_pins="1"/>
<output name="sc_out" num_pins="1"/>
<output name="cout" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10">
<fc_override port_name="reg_in" fc_type="frac" fc_val="0"/>
<fc_override port_name="reg_out" fc_type="frac" fc_val="0"/>
<fc_override port_name="sc_in" fc_type="frac" fc_val="0"/>
<fc_override port_name="sc_out" fc_type="frac" fc_val="0"/>
<fc_override port_name="cin" fc_type="frac" fc_val="0"/>
<fc_override port_name="cout" fc_type="frac" fc_val="0"/>
<fc_override port_name="clk" fc_type="frac" fc_val="0"/>
<fc_override port_name="reset" fc_type="frac" fc_val="0"/>
</fc>
<!--pinlocations pattern="spread"/-->
<pinlocations pattern="custom">
<loc side="left">clb.clk clb.reset</loc>
<loc side="top">clb.reg_in clb.sc_in clb.cin clb.O[7:0] clb.I0 clb.I0i clb.I1 clb.I1i clb.I2 clb.I2i clb.I3 clb.I3i</loc>
<loc side="right">clb.O[15:8] clb.I4 clb.I4i clb.I5 clb.I5i clb.I6 clb.I6i clb.I7 clb.I7i</loc>
<loc side="bottom">clb.reg_out clb.sc_out clb.cout</loc>
</pinlocations>
</tile>
</tiles>
<!-- ODIN II specific config ends -->
<!-- Physical descriptions begin -->
<layout tileable="true">
<auto_layout aspect_ratio="1.0">
<!--Perimeter of 'io' blocks with 'EMPTY' blocks at corners-->
<row type="io_top" starty="H-1" priority="100"/>
<row type="io_bottom" starty="0" priority="100"/>
<col type="io_left" startx="0" priority="100"/>
<col type="io_right" startx="W-1" priority="100"/>
<corners type="EMPTY" priority="101"/>
<!--Fill with 'clb'-->
<fill type="clb" priority="10"/>
</auto_layout>
<fixed_layout name="2x2" width="4" height="4">
<!--Perimeter of 'io' blocks with 'EMPTY' blocks at corners-->
<row type="io_top" starty="H-1" priority="100"/>
<row type="io_bottom" starty="0" priority="100"/>
<col type="io_left" startx="0" priority="100"/>
<col type="io_right" startx="W-1" priority="100"/>
<corners type="EMPTY" priority="101"/>
<!--Fill with 'clb'-->
<fill type="clb" priority="10"/>
</fixed_layout>
<fixed_layout name="12x12" width="14" height="14">
<!--Perimeter of 'io' blocks with 'EMPTY' blocks at corners-->
<row type="io_top" starty="H-1" priority="100"/>
<row type="io_bottom" starty="0" priority="100"/>
<col type="io_left" startx="0" priority="100"/>
<col type="io_right" startx="W-1" priority="100"/>
<corners type="EMPTY" priority="101"/>
<!--Fill with 'clb'-->
<fill type="clb" priority="10"/>
</fixed_layout>
</layout>
<device>
<!-- VB & JL: Using Ian Kuon's transistor sizing and drive strength data for routing, at 40 nm. Ian used BPTM
models. We are modifying the delay values however, to include metal C and R, which allows more architecture
experimentation. We are also modifying the relative resistance of PMOS to be 1.8x that of NMOS
(vs. Ian's 3x) as 1.8x lines up with Jeff G's data from a 45 nm process (and is more typical of
45 nm in general). I'm upping the Rmin_nmos from Ian's just over 6k to nearly 9k, and dropping
RminW_pmos from 18k to 16k to hit this 1.8x ratio, while keeping the delays of buffers approximately
lined up with Stratix IV.
We are using Jeff G.'s capacitance data for 45 nm (in tech/ptm_45nm).
Jeff's tables list C in for transistors with widths in multiples of the minimum feature size (45 nm).
The minimum contactable transistor is 2.5 * 45 nm, so I need to multiply drive strength sizes in this file
by 2.5x when looking up in Jeff's tables.
The delay values are lined up with Stratix IV, which has an architecture similar to this
proposed FPGA, and which is also 40 nm
C_ipin_cblock: input capacitance of a track buffer, which VPR assumes is a single-stage
4x minimum drive strength buffer. -->
<sizing R_minW_nmos="8926" R_minW_pmos="16067"/>
<!-- The grid_logic_tile_area below will be used for all blocks that do not explicitly set their own (non-routing)
area; set to 0 since we explicitly set the area of all blocks currently in this architecture file.
-->
<area grid_logic_tile_area="0"/>
<chan_width_distr>
<x distr="uniform" peak="1.000000"/>
<y distr="uniform" peak="1.000000"/>
</chan_width_distr>
<switch_block type="wilton" fs="3" sub_type="subset" sub_fs="3"/>
<connection_block input_switch_name="ipin_cblock"/>
</device>
<switchlist>
<!-- VB: the mux_trans_size and buf_size data below is in minimum width transistor *areas*, assuming the purple
book area formula. This means the mux transistors are about 5x minimum drive strength.
We assume the first stage of the buffer is 3x min drive strength to be reasonable given the large
mux transistors, and this gives a reasonable stage ratio of a bit over 5x to the second stage. We assume
the n and p transistors in the first stage are equal-sized to lower the buffer trip point, since it's fed
by a pass transistor mux. We can then reverse engineer the buffer second stage to hit the specified
buf_size (really buffer area) - 16.2x minimum drive nmos and 1.8*16.2 = 29.2x minimum drive.
I then took the data from Jeff G.'s PTM modeling of 45 nm to get the Cin (gate of first stage) and Cout
(diff of second stage) listed below. Jeff's models are in tech/ptm_45nm, and are in min feature multiples.
The minimum contactable transistor is 2.5 * 45 nm, so I need to multiply the drive strength sizes above by
2.5x when looking up in Jeff's tables.
Finally, we choose a switch delay (58 ps) that leads to length 4 wires having a delay equal to that of SIV of 126 ps.
This also leads to the switch being 46% of the total wire delay, which is reasonable. -->
<switch type="mux" name="L1_mux" R="551" Cin=".77e-15" Cout="4e-15" Tdel="58e-12" mux_trans_size="2.630740" buf_size="27.645901"/>
<switch type="mux" name="L2_mux" R="551" Cin=".77e-15" Cout="4e-15" Tdel="58e-12" mux_trans_size="2.630740" buf_size="27.645901"/>
<switch type="mux" name="L4_mux" R="551" Cin=".77e-15" Cout="4e-15" Tdel="58e-12" mux_trans_size="2.630740" buf_size="27.645901"/>
<!--switch ipin_cblock resistance set to yeild for 4x minimum drive strength buffer-->
<switch type="mux" name="ipin_cblock" R="2231.5" Cout="0." Cin="1.47e-15" Tdel="7.247000e-11" mux_trans_size="1.222260" buf_size="auto"/>
</switchlist>
<segmentlist>
<!--- VB & JL: using ITRS metal stack data, 96 nm half pitch wires, which are intermediate metal width/space.
With the 96 nm half pitch, such wires would take 60 um of height, vs. a 90 nm high (approximated as square) Stratix IV tile so this seems
reasonable. Using a tile length of 90 nm, corresponding to the length of a Stratix IV tile if it were square. -->
<!-- GIVE a specific name for the segment! OpenFPGA appreciate that! -->
<segment name="L1" freq="0.10" length="1" type="unidir" Rmetal="101" Cmetal="22.5e-15">
<mux name="L1_mux"/>
<sb type="pattern">1 1</sb>
<cb type="pattern">1</cb>
</segment>
<segment name="L2" freq="0.10" length="2" type="unidir" Rmetal="101" Cmetal="22.5e-15">
<mux name="L2_mux"/>
<sb type="pattern">1 1 1</sb>
<cb type="pattern">1 1</cb>
</segment>
<segment name="L4" freq="0.80" length="4" type="unidir" Rmetal="101" Cmetal="22.5e-15">
<mux name="L4_mux"/>
<sb type="pattern">1 1 1 1 1</sb>
<cb type="pattern">1 1 1 1</cb>
</segment>
</segmentlist>
<directlist>
<direct name="carry_chain" from_pin="clb.cout" to_pin="clb.cin" x_offset="0" y_offset="-1" z_offset="0"/>
<direct name="shift_register" from_pin="clb.reg_out" to_pin="clb.reg_in" x_offset="0" y_offset="-1" z_offset="0"/>
<direct name="scan_chain" from_pin="clb.sc_out" to_pin="clb.sc_in" x_offset="0" y_offset="-1" z_offset="0"/>
</directlist>
<complexblocklist>
<!-- Define input pads begin -->
<pb_type name="io">
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
<!-- Do NOT add clock pins to I/O here!!! VPR does not build clock network in the way that OpenFPGA can support
If you need to register the I/O, define clocks in the circuit models
These clocks can be handled in back-end
-->
<!-- A mode denotes the physical implementation of an I/O
This mode will be not packable but is mainly used for fabric verilog generation
-->
<mode name="physical" disabled_in_pack="true">
<pb_type name="iopad" blif_model=".subckt io" num_pb="1">
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
</pb_type>
<interconnect>
<direct name="outpad" input="io.outpad" output="iopad.outpad">
<delay_constant max="1.394e-11" in_port="io.outpad" out_port="iopad.outpad"/>
</direct>
<direct name="inpad" input="iopad.inpad" output="io.inpad">
<delay_constant max="4.243e-11" in_port="iopad.inpad" out_port="io.inpad"/>
</direct>
</interconnect>
</mode>
<!-- IOs can operate as either inputs or outputs.
Delays below come from Ian Kuon. They are small, so they should be interpreted as
the delays to and from registers in the I/O (and generally I/Os are registered
today and that is when you timing analyze them.
-->
<mode name="inpad">
<pb_type name="inpad" blif_model=".input" num_pb="1">
<output name="inpad" num_pins="1"/>
</pb_type>
<interconnect>
<direct name="inpad" input="inpad.inpad" output="io.inpad">
<delay_constant max="4.243e-11" in_port="inpad.inpad" out_port="io.inpad"/>
</direct>
</interconnect>
</mode>
<mode name="outpad">
<pb_type name="outpad" blif_model=".output" num_pb="1">
<input name="outpad" num_pins="1"/>
</pb_type>
<interconnect>
<direct name="outpad" input="io.outpad" output="outpad.outpad">
<delay_constant max="1.394e-11" in_port="io.outpad" out_port="outpad.outpad"/>
</direct>
</interconnect>
</mode>
<power method="ignore"/>
</pb_type>
<!-- Define I/O pads ends -->
<!-- Define general purpose logic block (CLB) begin -->
<!-- -Due to the absence of local routing,
the 4 inputs of fracturable LUT4 are no longer equivalent,
because the 4th input can not be switched when the dual-LUT3 modes are used.
So pin equivalence should be applied to the first 3 inputs only
-->
<pb_type name="clb">
<input name="I0" num_pins="2" equivalent="full"/>
<input name="I0i" num_pins="2" equivalent="none"/>
<input name="I1" num_pins="2" equivalent="full"/>
<input name="I1i" num_pins="2" equivalent="none"/>
<input name="I2" num_pins="2" equivalent="full"/>
<input name="I2i" num_pins="2" equivalent="none"/>
<input name="I3" num_pins="2" equivalent="full"/>
<input name="I3i" num_pins="2" equivalent="none"/>
<input name="I4" num_pins="2" equivalent="full"/>
<input name="I4i" num_pins="2" equivalent="none"/>
<input name="I5" num_pins="2" equivalent="full"/>
<input name="I5i" num_pins="2" equivalent="none"/>
<input name="I6" num_pins="2" equivalent="full"/>
<input name="I6i" num_pins="2" equivalent="none"/>
<input name="I7" num_pins="2" equivalent="full"/>
<input name="I7i" num_pins="2" equivalent="none"/>
<input name="reg_in" num_pins="1"/>
<input name="sc_in" num_pins="1"/>
<input name="cin" num_pins="1"/>
<input name="reset" num_pins="1" is_non_clock_global="true"/>
<output name="O" num_pins="16" equivalent="none"/>
<output name="reg_out" num_pins="1"/>
<output name="sc_out" num_pins="1"/>
<output name="cout" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<!-- Describe fracturable logic element.
Each fracturable logic element has a 6-LUT that can alternatively operate as two 5-LUTs with shared inputs.
The outputs of the fracturable logic element can be optionally registered
-->
<pb_type name="fle" num_pb="8">
<input name="in" num_pins="4"/>
<input name="reg_in" num_pins="1"/>
<input name="sc_in" num_pins="1"/>
<input name="cin" num_pins="1"/>
<input name="reset" num_pins="1"/>
<output name="out" num_pins="2"/>
<output name="reg_out" num_pins="1"/>
<output name="sc_out" num_pins="1"/>
<output name="cout" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<!-- Physical mode definition begin (physical implementation of the fle) -->
<mode name="physical" disabled_in_pack="true">
<pb_type name="fabric" num_pb="1">
<input name="in" num_pins="4"/>
<input name="reg_in" num_pins="1"/>
<input name="sc_in" num_pins="1"/>
<input name="cin" num_pins="1"/>
<input name="reset" num_pins="1"/>
<output name="out" num_pins="2"/>
<output name="reg_out" num_pins="1"/>
<output name="sc_out" num_pins="1"/>
<output name="cout" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<pb_type name="frac_logic" num_pb="1">
<input name="in" num_pins="4"/>
<input name="cin" num_pins="1"/>
<output name="out" num_pins="2"/>
<output name="cout" num_pins="1"/>
<!-- Define LUT -->
<pb_type name="frac_lut4" blif_model=".subckt frac_lut4" num_pb="1">
<input name="in" num_pins="4"/>
<output name="lut2_out" num_pins="2"/>
<output name="lut3_out" num_pins="2"/>
<output name="lut4_out" num_pins="1"/>
</pb_type>
<pb_type name="carry_follower" blif_model=".subckt carry_follower" num_pb="1">
<input name="a" num_pins="1"/>
<input name="b" num_pins="1"/>
<input name="cin" num_pins="1"/>
<output name="cout" num_pins="1"/>
</pb_type>
<interconnect>
<direct name="direct1" input="frac_logic.in[0:1]" output="frac_lut4.in[0:1]"/>
<direct name="direct2" input="frac_logic.in[3:3]" output="frac_lut4.in[3:3]"/>
<direct name="direct3" input="frac_logic.cin" output="carry_follower.b"/>
<direct name="direct4" input="frac_lut4.lut2_out[1:1]" output="carry_follower.a"/>
<direct name="direct5" input="frac_lut4.lut2_out[0:0]" output="carry_follower.cin"/>
<direct name="direct6" input="carry_follower.cout" output="frac_logic.cout"/>
<direct name="direct7" input="frac_lut4.lut3_out[1]" output="frac_logic.out[1]"/>
<!-- Xifan Tang: I use out[0] because the output of lut6 in lut6 mode is wired to the out[0] -->
<mux name="mux1" input="frac_lut4.lut4_out frac_lut4.lut3_out[0]" output="frac_logic.out[0]"/>
<mux name="mux2" input="frac_logic.cin frac_logic.in[2:2]" output="frac_lut4.in[2:2]"/>
</interconnect>
</pb_type>
<!-- Define flip-flop with scan-chain capability, DI is the scan-chain data input -->
<pb_type name="ff" blif_model=".subckt scff" num_pb="2">
<input name="D" num_pins="1"/>
<input name="DI" num_pins="1"/>
<input name="reset" num_pins="1"/>
<output name="Q" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<T_setup value="66e-12" port="ff.D" clock="clk"/>
<T_setup value="66e-12" port="ff.DI" clock="clk"/>
<T_setup value="66e-12" port="ff.reset" clock="clk"/>
<T_clock_to_Q max="124e-12" port="ff.Q" clock="clk"/>
</pb_type>
<interconnect>
<direct name="direct1" input="fabric.in" output="frac_logic.in"/>
<direct name="direct2" input="fabric.sc_in" output="ff[0].DI"/>
<direct name="direct3" input="ff[0].Q" output="ff[1].DI"/>
<direct name="direct4" input="ff[1].Q" output="fabric.sc_out"/>
<direct name="direct5" input="ff[1].Q" output="fabric.reg_out"/>
<complete name="complete1" input="fabric.clk" output="ff[1:0].clk"/>
<complete name="complete2" input="fabric.reset" output="ff[1:0].reset"/>
<mux name="mux1" input="frac_logic.out[0:0] fabric.reg_in" output="ff[0:0].D">
<delay_constant max="25e-12" in_port="frac_logic.out[0:0]" out_port="ff[0:0].D"/>
<delay_constant max="45e-12" in_port="fabric.reg_in" out_port="ff[0:0].D"/>
</mux>
<mux name="mux2" input="frac_logic.out[1:1] ff[0:0].Q" output="ff[1:1].D">
<delay_constant max="25e-12" in_port="frac_logic.out[1:1]" out_port="ff[1:1].D"/>
<delay_constant max="45e-12" in_port="ff[0:0].Q" out_port="ff[1:1].D"/>
</mux>
<mux name="mux3" input="ff[0].Q frac_logic.out[0]" output="fabric.out[0]">
<!-- LUT to output is faster than FF to output on a Stratix IV -->
<delay_constant max="25e-12" in_port="frac_logic.out[0]" out_port="fabric.out[0]"/>
<delay_constant max="45e-12" in_port="ff[0].Q" out_port="fabric.out[0]"/>
</mux>
<mux name="mux4" input="ff[1].Q frac_logic.out[1]" output="fabric.out[1]">
<!-- LUT to output is faster than FF to output on a Stratix IV -->
<delay_constant max="25e-12" in_port="frac_logic.out[1]" out_port="fabric.out[1]"/>
<delay_constant max="45e-12" in_port="ff[1].Q" out_port="fabric.out[1]"/>
</mux>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="fle.in" output="fabric.in"/>
<direct name="direct2" input="fle.reg_in" output="fabric.reg_in"/>
<direct name="direct3" input="fle.sc_in" output="fabric.sc_in"/>
<direct name="direct4" input="fle.cin" output="fabric.cin"/>
<direct name="direct5" input="fabric.out" output="fle.out"/>
<direct name="direct6" input="fabric.reg_out" output="fle.reg_out"/>
<direct name="direct7" input="fabric.sc_out" output="fle.sc_out"/>
<direct name="direct8" input="fabric.cout" output="fle.cout"/>
<direct name="direct9" input="fle.clk" output="fabric.clk"/>
<direct name="direct10" input="fle.reset" output="fabric.reset"/>
</interconnect>
</mode>
<!-- Physical mode definition end (physical implementation of the fle) -->
<!-- Dual 3-LUT mode definition begin -->
<mode name="n2_lut3">
<pb_type name="lut3inter" num_pb="1">
<input name="in" num_pins="3"/>
<output name="out" num_pins="2"/>
<clock name="clk" num_pins="1"/>
<pb_type name="ble3" num_pb="2">
<input name="in" num_pins="3"/>
<output name="out" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<!-- Define the LUT -->
<pb_type name="lut3" blif_model=".names" num_pb="1" class="lut">
<input name="in" num_pins="3" port_class="lut_in"/>
<output name="out" num_pins="1" port_class="lut_out"/>
<!-- LUT timing using delay matrix -->
<!-- These are the physical delay inputs on a Stratix IV LUT but because VPR cannot do LUT rebalancing,
we instead take the average of these numbers to get more stable results
82e-12
173e-12
261e-12
263e-12
398e-12
-->
<delay_matrix type="max" in_port="lut3.in" out_port="lut3.out">
235e-12
235e-12
235e-12
</delay_matrix>
</pb_type>
<!-- Define the flip-flop -->
<pb_type name="ff" blif_model=".latch" num_pb="1" class="flipflop">
<input name="D" num_pins="1" port_class="D"/>
<output name="Q" num_pins="1" port_class="Q"/>
<clock name="clk" num_pins="1" port_class="clock"/>
<T_setup value="66e-12" port="ff.D" clock="clk"/>
<T_clock_to_Q max="124e-12" port="ff.Q" clock="clk"/>
</pb_type>
<interconnect>
<direct name="direct1" input="ble3.in[2:0]" output="lut3[0:0].in[2:0]"/>
<direct name="direct2" input="lut3[0:0].out" output="ff[0:0].D">
<!-- Advanced user option that tells CAD tool to find LUT+FF pairs in netlist -->
<pack_pattern name="ble3" in_port="lut3[0:0].out" out_port="ff[0:0].D"/>
</direct>
<direct name="direct3" input="ble3.clk" output="ff[0:0].clk"/>
<mux name="mux1" input="ff[0:0].Q lut3.out[0:0]" output="ble3.out[0:0]">
<!-- LUT to output is faster than FF to output on a Stratix IV -->
<delay_constant max="25e-12" in_port="lut3.out[0:0]" out_port="ble3.out[0:0]"/>
<delay_constant max="45e-12" in_port="ff[0:0].Q" out_port="ble3.out[0:0]"/>
</mux>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="lut3inter.in" output="ble3[0:0].in"/>
<direct name="direct2" input="lut3inter.in" output="ble3[1:1].in"/>
<direct name="direct3" input="ble3[1:0].out" output="lut3inter.out"/>
<complete name="complete1" input="lut3inter.clk" output="ble3[1:0].clk"/>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="fle.in[2:0]" output="lut3inter.in"/>
<direct name="direct2" input="lut3inter.out" output="fle.out"/>
<direct name="direct3" input="fle.clk" output="lut3inter.clk"/>
</interconnect>
</mode>
<!-- Dual 3-LUT mode definition end -->
<!-- 4-LUT mode definition begin -->
<mode name="n1_lut4">
<!-- Define 4-LUT mode -->
<pb_type name="ble4" num_pb="1">
<input name="in" num_pins="4"/>
<output name="out" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<!-- Define LUT -->
<pb_type name="lut4" blif_model=".names" num_pb="1" class="lut">
<input name="in" num_pins="4" port_class="lut_in"/>
<output name="out" num_pins="1" port_class="lut_out"/>
<!-- LUT timing using delay matrix -->
<!-- These are the physical delay inputs on a Stratix IV LUT but because VPR cannot do LUT rebalancing,
we instead take the average of these numbers to get more stable results
82e-12
173e-12
261e-12
263e-12
398e-12
397e-12
-->
<delay_matrix type="max" in_port="lut4.in" out_port="lut4.out">
261e-12
261e-12
261e-12
261e-12
</delay_matrix>
</pb_type>
<!-- Define flip-flop -->
<pb_type name="ff" blif_model=".latch" num_pb="1" class="flipflop">
<input name="D" num_pins="1" port_class="D"/>
<output name="Q" num_pins="1" port_class="Q"/>
<clock name="clk" num_pins="1" port_class="clock"/>
<T_setup value="66e-12" port="ff.D" clock="clk"/>
<T_clock_to_Q max="124e-12" port="ff.Q" clock="clk"/>
</pb_type>
<interconnect>
<direct name="direct1" input="ble4.in" output="lut4[0:0].in"/>
<direct name="direct2" input="lut4.out" output="ff.D">
<!-- Advanced user option that tells CAD tool to find LUT+FF pairs in netlist -->
<pack_pattern name="ble4" in_port="lut4.out" out_port="ff.D"/>
</direct>
<direct name="direct3" input="ble4.clk" output="ff.clk"/>
<mux name="mux1" input="ff.Q lut4.out" output="ble4.out">
<!-- LUT to output is faster than FF to output on a Stratix IV -->
<delay_constant max="25e-12" in_port="lut4.out" out_port="ble4.out"/>
<delay_constant max="45e-12" in_port="ff.Q" out_port="ble4.out"/>
</mux>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="fle.in" output="ble4.in"/>
<direct name="direct2" input="ble4.out" output="fle.out[0:0]"/>
<direct name="direct3" input="fle.clk" output="ble4.clk"/>
</interconnect>
</mode>
<!-- 4-LUT mode definition end -->
<!-- Define shift register begin -->
<mode name="shift_register">
<pb_type name="shift_reg" num_pb="1">
<input name="reg_in" num_pins="1"/>
<output name="ff_out" num_pins="2"/>
<output name="reg_out" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<pb_type name="ff" blif_model=".latch" num_pb="2" class="flipflop">
<input name="D" num_pins="1" port_class="D"/>
<output name="Q" num_pins="1" port_class="Q"/>
<clock name="clk" num_pins="1" port_class="clock"/>
<T_setup value="66e-12" port="ff.D" clock="clk"/>
<T_clock_to_Q max="124e-12" port="ff.Q" clock="clk"/>
</pb_type>
<interconnect>
<direct name="direct1" input="shift_reg.reg_in" output="ff[0].D"/>
<direct name="direct2" input="ff[0].Q" output="ff[1].D"/>
<direct name="direct3" input="ff[1].Q" output="shift_reg.reg_out"/>
<direct name="direct4" input="ff[0].Q" output="shift_reg.ff_out[0:0]"/>
<direct name="direct5" input="ff[1].Q" output="shift_reg.ff_out[1:1]"/>
<complete name="complete1" input="shift_reg.clk" output="ff.clk"/>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="fle.reg_in" output="shift_reg.reg_in"/>
<direct name="direct2" input="shift_reg.reg_out" output="fle.reg_out"/>
<direct name="direct3" input="shift_reg.ff_out" output="fle.out"/>
<direct name="direct4" input="fle.clk" output="shift_reg.clk"/>
</interconnect>
</mode>
<!-- Define shift register end -->
</pb_type>
<interconnect>
<!-- We use direct connections to reduce the area to the most
The global local routing is going to compensate the loss in routability
-->
<!-- FIXME: The implicit port definition results in I0[0] connected to
in[2]. Such twisted connection is not expected.
I[0] should be connected to in[0]
-->
<direct name="direct_fle0" input="clb.I0[0:1]" output="fle[0:0].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle0i" input="clb.I0i[0:1]" output="fle[0:0].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle1" input="clb.I1[0:1]" output="fle[1:1].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle1i" input="clb.I1i[0:1]" output="fle[1:1].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle2" input="clb.I2[0:1]" output="fle[2:2].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle2i" input="clb.I2i[0:1]" output="fle[2:2].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle3" input="clb.I3[0:1]" output="fle[3:3].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle3i" input="clb.I3i[0:1]" output="fle[3:3].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle4" input="clb.I4[0:1]" output="fle[4:4].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle4i" input="clb.I4i[0:1]" output="fle[4:4].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle5" input="clb.I5[0:1]" output="fle[5:5].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle5i" input="clb.I5i[0:1]" output="fle[5:5].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle6" input="clb.I6[0:1]" output="fle[6:6].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle6i" input="clb.I6i[0:1]" output="fle[6:6].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle7" input="clb.I7[0:1]" output="fle[7:7].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle7i" input="clb.I7i[0:1]" output="fle[7:7].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<complete name="clks" input="clb.clk" output="fle[7:0].clk">
</complete>
<complete name="resets" input="clb.reset" output="fle[7:0].reset">
</complete>
<!-- This way of specifying direct connection to clb outputs is important because this architecture uses automatic spreading of opins.
By grouping to output pins in this fashion, if a logic block is completely filled by 6-LUTs,
then the outputs those 6-LUTs take get evenly distributed across all four sides of the CLB instead of clumped on two sides (which is what happens with a more
naive specification).
-->
<direct name="clbouts1" input="fle[3:0].out[0:1]" output="clb.O[7:0]"/>
<direct name="clbouts2" input="fle[7:4].out[0:1]" output="clb.O[15:8]"/>
<!-- Shift register chain links -->
<direct name="shift_register_in" input="clb.reg_in" output="fle[0:0].reg_in">
<!-- Put all inter-block carry chain delay on this one edge -->
<delay_constant max="0.16e-9" in_port="clb.reg_in" out_port="fle[0:0].reg_in"/>
<!--pack_pattern name="chain" in_port="clb.reg_in" out_port="fle[0:0].reg_in"/-->
</direct>
<direct name="shift_register_out" input="fle[7:7].reg_out" output="clb.reg_out">
<!--pack_pattern name="chain" in_port="fle[7:7].reg_out" out_port="clb.reg_out"/-->
</direct>
<direct name="shift_register_link" input="fle[6:0].reg_out" output="fle[7:1].reg_in">
<!--pack_pattern name="chain" in_port="fle[6:0].reg_out" out_port="fle[7:1].reg_in"/-->
</direct>
<!-- Scan chain links -->
<direct name="scan_chain_in" input="clb.sc_in" output="fle[0:0].sc_in">
<!-- Put all inter-block carry chain delay on this one edge -->
<delay_constant max="0.16e-9" in_port="clb.sc_in" out_port="fle[0:0].sc_in"/>
</direct>
<direct name="scan_chain_out" input="fle[7:7].sc_out" output="clb.sc_out">
</direct>
<direct name="scan_chain_link" input="fle[6:0].sc_out" output="fle[7:1].sc_in">
</direct>
<!-- Carry chain links -->
<direct name="carry_chain_in" input="clb.cin" output="fle[0:0].cin">
<!-- Put all inter-block carry chain delay on this one edge -->
<delay_constant max="0.16e-9" in_port="clb.cin" out_port="fle[0:0].cin"/>
</direct>
<direct name="carry_chain_out" input="fle[7:7].cout" output="clb.cout">
</direct>
<direct name="carry_chain_link" input="fle[6:0].cout" output="fle[7:1].cin">
</direct>
</interconnect>
<!-- Every input pin is driven by 15% of the tracks in a channel, every output pin is driven by 10% of the tracks in a channel -->
<!-- Place this general purpose logic block in any unspecified column -->
</pb_type>
<!-- Define general purpose logic block (CLB) ends -->
</complexblocklist>
</architecture>

View File

@ -27,14 +27,14 @@
<port name="lut4_out"/>
</output_ports>
</model>
<model name="MUX2">
<model name="carry_follower">
<input_ports>
<port name="in0" />
<port name="in1" />
<port name="sel" />
</input_ports>
<port name="a"/>
<port name="b"/>
<port name="cin"/>
</input_ports>
<output_ports>
<port name="out" />
<port name="cout"/>
</output_ports>
</model>
<model name="LUT4">
@ -304,22 +304,21 @@
<output name="lut2_out" num_pins="2"/>
<output name="lut4_out" num_pins="1"/>
</pb_type>
<pb_type name="co_mux" blif_model=".subckt MUX2" num_pb="1">
<input name="in0" num_pins="1"/>
<input name="in1" num_pins="1"/>
<input name="sel" num_pins="1"/>
<output name="out" num_pins="1"/>
<pb_type name="carry_follower" blif_model=".subckt carry_follower" num_pb="1">
<input name="a" num_pins="1"/>
<input name="b" num_pins="1"/>
<input name="cin" num_pins="1"/>
<output name="cout" num_pins="1"/>
</pb_type>
<interconnect>
<direct name="direct1" input="frac_logic.LI[0]" output="frac_lut4.in[0]" />
<direct name="direct2" input="frac_logic.LI[1]" output="frac_lut4.in[1]" />
<mux name="i2_ci" input="frac_logic.LI[2] frac_logic.CI" output="frac_lut4.in[2]"/>
<direct name="direct3" input="frac_logic.LI[3]" output="frac_lut4.in[3]" />
<direct name="direct4" input="frac_lut4.lut4_out" output="frac_logic.O" />
<direct name="direct5" input="frac_lut4.lut2_out[1]" output="co_mux.in0" />
<direct name="direct6" input="frac_logic.CI" output="co_mux.in1" />
<direct name="direct7" input="frac_lut4.lut2_out[0]" output="co_mux.sel" />
<direct name="direct8" input="co_mux.out" output="frac_logic.CO" />
<direct name="direct1" input="frac_logic.LI[0:1]" output="frac_lut4.in[0:1]" />
<direct name="direct2" input="frac_logic.LI[3:3]" output="frac_lut4.in[3:3]" />
<direct name="direct3" input="frac_lut4.lut4_out" output="frac_logic.O" />
<direct name="direct4" input="frac_lut4.lut2_out[1:1]" output="carry_follower.a" />
<direct name="direct5" input="frac_logic.CI" output="carry_follower.b" />
<direct name="direct6" input="frac_lut4.lut2_out[0:0]" output="carry_follower.cin" />
<direct name="direct7" input="carry_follower.out" output="frac_logic.CO" />
<mux name="i2_ci" input="frac_logic.LI[2:2] frac_logic.CI" output="frac_lut4.in[2:2]"/>
</interconnect>
</pb_type>
<!-- Define flip-flop with scan-chain capability, DI is the scan-chain data input -->

View File

@ -33,10 +33,10 @@
</g>
</marker>
</defs>
<metadata> Produced by OmniGraffle 7.18\n2020-11-21 01:05:14 +0000</metadata>
<g id="switch" fill="none" stroke="none" stroke-opacity="1" stroke-dasharray="none" fill-opacity="1">
<title>switch</title>
<g id="switch_base">
<metadata> Produced by OmniGraffle 7.18\n2020-11-29 03:10:55 +0000</metadata>
<g id="v1_0" fill="none" stroke="none" stroke-opacity="1" stroke-dasharray="none" fill-opacity="1">
<title>v1.0</title>
<g id="v1_0_base">
<title>base</title>
<g id="Graphic_535">
<text transform="translate(120.79736 899.1797)" fill="black">
@ -319,7 +319,7 @@
</g>
<g id="Graphic_538">
<text transform="translate(761.1309 905.7734)" fill="black">
<tspan font-family="Times" font-size="16" font-weight="400" fill="black" x="0" y="15">IO_ISOL_N -&gt; Caravel GPIO[1]</tspan>
<tspan font-family="Times" font-size="16" font-weight="400" fill="black" x="0" y="15">IO_ISOL_N &lt;- Caravel GPIO[1]</tspan>
<tspan font-family="Times" font-size="16" font-weight="400" fill="black" x="12.445312" y="34">TEST_EN &lt;- Caravel GPIO[0]</tspan>
</text>
</g>

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

10
HDL/common/README.md Normal file
View File

@ -0,0 +1,10 @@
# Skywater PDK
This directory contains the HDL netlists and code generator for FPGA fabrics.
- **caravel_fpga_wrapper_hd.v**: The wrapper for FPGA fabric to interface the Caravel SoC, which is technology mapped to the Skywater 130nm Foundry High-Density Standard Cell Library. **This file is automatically generated by a Python script**
- **caravel_defines.v**: The parameters required for Caravel wrapper HDL codes
- **caravel_fpga_wrapper_hd_template.v**: The template HDL codes for the wrapper
- **digital_io_hd.v**: the I/O cell used by High-density FPGA, which is technology mapped to the Skywater 130nm Foundry High-Density Standard Cell Library.
- **sky130_fd_sc_hd_wrapper.v**: Wrapper codes for the standard cells from the Skywater 130nm Foundry High-Density Standard Cell Library
- **skywater_function_verification.v**: Include pre-processing flags to enable functional verification for FPGAs
- **wrapper_lines_generator.py**: Python script to generate the wrapper *caravel\_fpga\_wrapper\_hd.v*

BIN
HDL/common/caravel_fpga_wrapper_hd.v (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,163 @@
{
"caravel_gpio_input_name": "io_in",
"caravel_gpio_output_name": "io_out",
"caravel_gpio_direction_name": "io_oeb",
"caravel_logic_analyzer_input_name": "la_data_in",
"caravel_logic_analyzer_output_name": "la_data_out",
"caravel_logic_analyzer_direction_name": "la_oen",
"caravel_wishbone_clock_input_name": "wb_clk_i",
"caravel_wishbone_reset_input_name": "wb_rst_i",
"caravel_wishbone_ack_output_name": "wbs_ack_o",
"caravel_wishbone_cyc_input_name": "wbs_cyc_i",
"caravel_wishbone_stb_input_name": "wbs_stb_i",
"caravel_wishbone_we_input_name": "wbs_we_i",
"caravel_wishbone_sel_input_name": "wbs_sel_i",
"caravel_wishbone_address_input_name": "wbs_adr_i",
"caravel_wishbone_data_input_name": "wbs_dat_i",
"caravel_wishbone_data_output_name": "wbs_dat_o",
"fpga_gpio_input_name": "gfpga_pad_EMBEDDED_IO_HD_SOC_IN",
"fpga_gpio_output_name": "gfpga_pad_EMBEDDED_IO_HD_SOC_OUT",
"fpga_gpio_direction_name": "gfpga_pad_EMBEDDED_IO_HD_SOC_DIR",
"mode_switch_pin_name": "wb_la_switch",
"inverted_mode_switch_pin_name": "wb_la_switch_b",
"pins": [
{
"fpga_pin_type": "io",
"fpga_pin_index": "0:11",
"caravel_pin_type": ["gpio"],
"caravel_pin_index": ["24:13"]
},
{
"fpga_pin_type": "ccff_head",
"fpga_pin_index": "0:0",
"caravel_pin_type": ["input"],
"caravel_pin_index": ["12:12"]
},
{
"fpga_pin_type": "sc_tail",
"fpga_pin_index": "0:0",
"caravel_pin_type": ["output"],
"caravel_pin_index": ["11:11"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "12:20",
"caravel_pin_type": ["gpio"],
"caravel_pin_index": ["10:2"]
},
{
"fpga_pin_type": "IO_ISOL_N",
"fpga_pin_index": "0:0",
"caravel_pin_type": ["input"],
"caravel_pin_index": ["1:1"]
},
{
"fpga_pin_type": "Test_en",
"fpga_pin_index": "0:0",
"caravel_pin_type": ["input"],
"caravel_pin_index": ["0:0"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "21:23",
"caravel_pin_type": ["logic_analyzer_io"],
"caravel_pin_index": ["127:125"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "24:29",
"caravel_pin_type": ["logic_analyzer_io"],
"caravel_pin_index": ["124:119"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "30:61",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_data_output"],
"caravel_pin_index": ["118:87", "0:31"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "62:93",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_data_input"],
"caravel_pin_index": ["86:55", "0:31"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "94:125",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_address_input"],
"caravel_pin_index": ["54:23", "0:31"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "126:129",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_sel_input"],
"caravel_pin_index": ["22:19", "0:3"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "130:130",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_we_input"],
"caravel_pin_index": ["18:18", "0:0"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "131:131",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_stb_input"],
"caravel_pin_index": ["17:17", "0:0"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "132:132",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_cyc_input"],
"caravel_pin_index": ["16:16", "0:0"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "133:133",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_ack_output"],
"caravel_pin_index": ["15:15", "0:0"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "134:134",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_reset_input"],
"caravel_pin_index": ["14:14", "0:0"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "135:135",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_clock_input"],
"caravel_pin_index": ["13:13", "0:0"]
},
{
"fpga_pin_type": "prog_clk",
"fpga_pin_index": "0:0",
"caravel_pin_type": ["input"],
"caravel_pin_index": ["37:37"]
},
{
"fpga_pin_type": "clk",
"fpga_pin_index": "0:0",
"caravel_pin_type": ["input"],
"caravel_pin_index": ["36:36"]
},
{
"fpga_pin_type": "ccff_tail",
"fpga_pin_index": "0:0",
"caravel_pin_type": ["output"],
"caravel_pin_index": ["35:35"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "136:143",
"caravel_pin_type": ["gpio"],
"caravel_pin_index": ["34:27"]
},
{
"fpga_pin_type": "sc_head",
"fpga_pin_index": "0:0",
"caravel_pin_type": ["input"],
"caravel_pin_index": ["26:26"]
}
]
}

View File

@ -0,0 +1,175 @@
{
"caravel_gpio_input_name": "io_in",
"caravel_gpio_output_name": "io_out",
"caravel_gpio_direction_name": "io_oeb",
"caravel_logic_analyzer_input_name": "la_data_in",
"caravel_logic_analyzer_output_name": "la_data_out",
"caravel_logic_analyzer_direction_name": "la_oen",
"caravel_wishbone_clock_input_name": "wb_clk_i",
"caravel_wishbone_reset_input_name": "wb_rst_i",
"caravel_wishbone_ack_output_name": "wbs_ack_o",
"caravel_wishbone_cyc_input_name": "wbs_cyc_i",
"caravel_wishbone_stb_input_name": "wbs_stb_i",
"caravel_wishbone_we_input_name": "wbs_we_i",
"caravel_wishbone_sel_input_name": "wbs_sel_i",
"caravel_wishbone_address_input_name": "wbs_adr_i",
"caravel_wishbone_data_input_name": "wbs_dat_i",
"caravel_wishbone_data_output_name": "wbs_dat_o",
"fpga_gpio_input_name": "gfpga_pad_EMBEDDED_IO_HD_SOC_IN",
"fpga_gpio_output_name": "gfpga_pad_EMBEDDED_IO_HD_SOC_OUT",
"fpga_gpio_direction_name": "gfpga_pad_EMBEDDED_IO_HD_SOC_DIR",
"mode_switch_pin_name": "wb_la_switch",
"inverted_mode_switch_pin_name": "wb_la_switch_b",
"pins": [
{
"fpga_pin_type": "io",
"fpga_pin_index": "0:11",
"caravel_pin_type": ["gpio"],
"caravel_pin_index": ["24:13"]
},
{
"fpga_pin_type": "ccff_head",
"fpga_pin_index": "0:0",
"caravel_pin_type": ["input"],
"caravel_pin_index": ["12:12"]
},
{
"fpga_pin_type": "sc_tail",
"fpga_pin_index": "0:0",
"caravel_pin_type": ["output"],
"caravel_pin_index": ["11:11"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "12:18",
"caravel_pin_type": ["gpio"],
"caravel_pin_index": ["10:4"]
},
{
"fpga_pin_type": "prog_reset",
"fpga_pin_index": "0:0",
"caravel_pin_type": ["input"],
"caravel_pin_index": ["3:3"]
},
{
"fpga_pin_type": "reset",
"fpga_pin_index": "0:0",
"caravel_pin_type": ["input"],
"caravel_pin_index": ["2:2"]
},
{
"fpga_pin_type": "IO_ISOL_N",
"fpga_pin_index": "0:0",
"caravel_pin_type": ["input"],
"caravel_pin_index": ["1:1"]
},
{
"fpga_pin_type": "Test_en",
"fpga_pin_index": "0:0",
"caravel_pin_type": ["input"],
"caravel_pin_index": ["0:0"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "19:23",
"caravel_pin_type": ["logic_analyzer_io"],
"caravel_pin_index": ["127:123"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "24:29",
"caravel_pin_type": ["logic_analyzer_io"],
"caravel_pin_index": ["122:117"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "30:61",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_data_output"],
"caravel_pin_index": ["116:85", "0:31"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "62:93",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_data_input"],
"caravel_pin_index": ["84:53", "0:31"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "94:125",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_address_input"],
"caravel_pin_index": ["52:21", "0:31"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "126:129",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_sel_input"],
"caravel_pin_index": ["20:17", "0:3"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "130:130",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_we_input"],
"caravel_pin_index": ["16:16", "0:0"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "131:131",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_stb_input"],
"caravel_pin_index": ["15:15", "0:0"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "132:132",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_cyc_input"],
"caravel_pin_index": ["14:14", "0:0"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "133:133",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_ack_output"],
"caravel_pin_index": ["13:13", "0:0"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "134:134",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_reset_input"],
"caravel_pin_index": ["12:12", "0:0"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "135:135",
"caravel_pin_type": ["logic_analyzer_io", "wishbone_clock_input"],
"caravel_pin_index": ["11:11", "0:0"]
},
{
"fpga_pin_type": "prog_clk",
"fpga_pin_index": "0:0",
"caravel_pin_type": ["input"],
"caravel_pin_index": ["37:37"]
},
{
"fpga_pin_type": "clk",
"fpga_pin_index": "0:0",
"caravel_pin_type": ["input"],
"caravel_pin_index": ["36:36"]
},
{
"fpga_pin_type": "ccff_tail",
"fpga_pin_index": "0:0",
"caravel_pin_type": ["output"],
"caravel_pin_index": ["35:35"]
},
{
"fpga_pin_type": "io",
"fpga_pin_index": "136:143",
"caravel_pin_type": ["gpio"],
"caravel_pin_index": ["34:27"]
},
{
"fpga_pin_type": "sc_head",
"fpga_pin_index": "0:0",
"caravel_pin_type": ["input"],
"caravel_pin_index": ["26:26"]
}
]
}

View File

@ -12,6 +12,7 @@ import shutil
import re
import argparse
import logging
import json
#####################################################################
# Initialize logger
@ -26,111 +27,214 @@ parser = argparse.ArgumentParser(
description='Generator for technology-mapped wrapper')
parser.add_argument('--template_netlist', default='caravel_fpga_wrapper_hd_template.v',
help='Specify template verilog netlist')
parser.add_argument('--pin_assignment_file', required=True,
help='Specify the json file constaining pin assignment information')
parser.add_argument('--output_verilog', default='caravel_fpga_wrapper_hd.v',
help='Specify output verilog file path')
args = parser.parse_args()
#####################################################################
# Define Wishbone interface pin sequence
# The list start from left-side of the wrapper to the right side
# Target FPGA gpio start from 135, 134 ...
# Check options:
# - Input json file must be valid
# Otherwise, error out
#####################################################################
wishbone_pins = ['wb_clk_i', 'wb_rst_i',
'wbs_ack_o', 'wbs_cyc_i',
'wbs_stb_i', 'wbs_we_i']
wishbone_pins.extend([f"wbs_sel_i[{i}]" for i in range(4)])
wishbone_pins.extend([f"wbs_adr_i[{i}]" for i in range(32)])
wishbone_pins.extend([f"wbs_dat_i[{i}]" for i in range(32)])
wishbone_pins.extend([f"wbs_dat_o[{i}]" for i in range(32)])
if not isfile(args.pin_assignment_file):
logging.error("Invalid pin assignment file: " + args.pin_assignment_file + "\nFile does not exist!\n")
exit(1)
#####################################################################
# Define Logic Analyzer interface pin sequence
# The list start from left-side of the wrapper to the right side
# Target FPGA gpio start from 135, 134 ...
# Parse the json file
#####################################################################
logic_analyzer_pins = []
for ipin in range(13, 128):
logic_analyzer_pins.append(["la_data_in[" + str(ipin) + "]",
"la_data_out[" + str(ipin) + "]", "la_oen[" + str(ipin) + "]"])
json_file = open(args.pin_assignment_file, "r")
pin_data = json.load(json_file)
#####################################################################
# A function to parse pin range from json data
# JSON pin range format is LSB:MSB
# Return pin range format is [LSB, MSB] as a list
#####################################################################
def parse_json_pin_range(json_range) :
pin_range_str = json_range.split(':')
assert(2 == len(pin_range_str))
# If the range is in decend order, we will decrease the MSB by 1
if (int(pin_range_str[0]) > int(pin_range_str[1])) :
return range(int(pin_range_str[0]), int(pin_range_str[1]) - 1, -1)
# If the range is in acend order, we will increase the MSB by 1
return range(int(pin_range_str[0]), int(pin_range_str[1]) + 1)
#####################################################################
# Generate wrapper lines
#####################################################################
netlist_lines = []
num_wishbone_pins = len(wishbone_pins)
num_logic_analyzer_pins = len(logic_analyzer_pins)
num_gpio_pins = 135 - 21 + 1
print("Number of Wishbone pins: " + str(num_wishbone_pins))
print("Number of logic analyzer pins: " + str(num_logic_analyzer_pins))
print("Number of gpio pins: " + str(num_gpio_pins))
# Walk through the array containing the pin information
for pin_info in pin_data['pins']:
# Deposit a tab to respect the HDL coding indent
curr_line = ""
# TODO: Check codes that ensure the pin index should match
assert(0 < len(pin_info['caravel_pin_type']))
assert(0 < len(pin_info['caravel_pin_index']))
#
# Branch on the types of connnections:
# - FPGA I/O to Caravel GPIO
if (("io" == pin_info['fpga_pin_type']) \
and (1 == len(pin_info['caravel_pin_type'])) \
and ("gpio" == pin_info['caravel_pin_type'][0])):
# Should have only 1 port in caravel
assert(1 == len(pin_info['caravel_pin_type']))
assert(1 == len(pin_info['caravel_pin_index']))
# Get pin range
fpga_io_pin_range = parse_json_pin_range(pin_info['fpga_pin_index'])
caravel_io_pin_range = parse_json_pin_range(pin_info['caravel_pin_index'][0])
assert(len(list(fpga_io_pin_range)) == len(list(caravel_io_pin_range)))
for indices in zip(list(fpga_io_pin_range), list(caravel_io_pin_range)) :
# Connect all the input, output and direction port
# FPGA input <- Caravel input
curr_line = "assign " + pin_data['fpga_gpio_input_name'] + "[" + str(indices[0]) + "] = " \
+ pin_data['caravel_gpio_input_name'] + "[" + str(indices[1]) + "];";
netlist_lines.append(" " + curr_line + "\n")
# FPGA output -> Caravel output
curr_line = "assign " + pin_data['caravel_gpio_output_name'] + "[" + str(indices[1]) + "] = " \
+ pin_data['fpga_gpio_output_name'] + "[" + str(indices[0]) + "];";
netlist_lines.append(" " + curr_line + "\n")
# FPGA direction -> Caravel direction
curr_line = "assign " + pin_data['caravel_gpio_direction_name'] + "[" + str(indices[1]) + "] = " \
+ pin_data['fpga_gpio_direction_name'] + "[" + str(indices[0]) + "];";
netlist_lines.append(" " + curr_line + "\n")
assert num_wishbone_pins < num_logic_analyzer_pins
assert num_logic_analyzer_pins == num_gpio_pins
# - FPGA control input ports to Caravel GPIO
if (("io" != pin_info['fpga_pin_type']) \
and (1 == len(pin_info['caravel_pin_type'])) \
and ("input" == pin_info['caravel_pin_type'][0])):
# Should have only 1 port in caravel
assert(1 == len(pin_info['caravel_pin_type']))
assert(1 == len(pin_info['caravel_pin_index']))
# Get pin range
fpga_io_pin_range = parse_json_pin_range(pin_info['fpga_pin_index'])
caravel_io_pin_range = parse_json_pin_range(pin_info['caravel_pin_index'][0])
assert(len(list(fpga_io_pin_range)) == len(list(caravel_io_pin_range)))
for indices in zip(list(fpga_io_pin_range), list(caravel_io_pin_range)) :
# Connect the FPGA input port to the Caravel input
curr_line = "assign " + pin_info['fpga_pin_type'] + "[" + str(indices[0]) + "] = " \
+ pin_data['caravel_gpio_input_name'] + "[" + str(indices[1]) + "];";
netlist_lines.append(" " + curr_line + "\n")
# Tie Caravel output port to logic '0'
curr_line = "assign " + pin_data['caravel_gpio_output_name'] + "[" + str(indices[1]) + "] = 1'b0;"
netlist_lines.append(" " + curr_line + "\n")
# Tie Caravel direction port to logic '1'
curr_line = "assign " + pin_data['caravel_gpio_direction_name'] + "[" + str(indices[1]) + "] = 1'b1;"
netlist_lines.append(" " + curr_line + "\n")
for ipin in range(0, num_gpio_pins):
curr_line = ""
if ((ipin < num_wishbone_pins) and (ipin < num_logic_analyzer_pins)):
# If this is an input pin of wishbone interface, whose postfix is '_i', we use MUX
# otherwise, this is an output pin, we just wire the input to logic analyzer
if ((wishbone_pins[ipin].endswith("_i")) or (re.search(r'_i\[\d+\]$', wishbone_pins[ipin], re.M | re.I))):
##############################################################
# SOC INPUT will be directly driven by either
# - the Wishbone input
# or
# - the logic analyzer input
# through a multiplexer controlled by the signal 'wb_la_switch
curr_line = " " + "sky130_fd_sc_hd__mux2_1 FPGA2SOC_IN_" + str(135 - ipin) + "_MUX (.S(wb_la_switch), .A1(" + str(
wishbone_pins[ipin]) + "), .A0(" + str(logic_analyzer_pins[ipin][0]) + "), .X(gfpga_pad_EMBEDDED_IO_HD_SOC_IN[" + str(135 - ipin) + "]));"
netlist_lines.append(curr_line + "\n")
##############################################################
# SOC OUTPUT will drive an output of logic analyzer
# since this I/O is going to interface a Wishbone input only
curr_line = " " + "assign " + \
str(logic_analyzer_pins[ipin][1]) + \
" = gfpga_pad_EMBEDDED_IO_HD_SOC_OUT[" + str(135 - ipin) + "];"
netlist_lines.append(curr_line + "\n")
elif ((wishbone_pins[ipin].endswith("_o")) or (re.search(r'_o\[\d+\]$', wishbone_pins[ipin], re.M | re.I))):
##############################################################
# SOC INPUT will be directly driven by logic analyzer
# since this I/O is going to interface a Wishbone output only
curr_line = " " + "assign gfpga_pad_EMBEDDED_IO_HD_SOC_IN[" + str(
135 - ipin) + "] = " + str(logic_analyzer_pins[ipin][0]) + ";"
netlist_lines.append(curr_line + "\n")
##############################################################
# SOC OUTPUT will drive the Wishbone output through a tri-state buffer
# As the buffer is enabled by logic '0', we use the inverted 'wb_la_switch'
curr_line = " " + "sky130_fd_sc_hd__ebufn_4 FPGA2SOC_OUT_" + str(135 - ipin) + "_DEMUX_WB (" + \
".TE_B(wb_la_switch_b), " + \
".A(" + "gfpga_pad_EMBEDDED_IO_HD_SOC_OUT[" + str(135 - ipin) + "]), " + \
".Z(" + str(wishbone_pins[ipin]) + ")" + \
");"
netlist_lines.append(curr_line + "\n")
##############################################################
# SOC OUTPUT will also drive the Logic Analyzer output through a tri-state buffer
# As the buffer is enabled by logic '0', we use the 'wb_la_switch'
curr_line = " " + "sky130_fd_sc_hd__ebufn_4 FPGA2SOC_OUT_" + str(135 - ipin) + "_DEMUX_LA (" + \
".TE_B(wb_la_switch), " + \
".A(" + "gfpga_pad_EMBEDDED_IO_HD_SOC_OUT[" + str(135 - ipin) + "]), " + \
".Z(" + str(logic_analyzer_pins[ipin][1]) + ")" + \
");"
netlist_lines.append(curr_line + "\n")
# - FPGA control output ports to Caravel GPIO
if (("io" != pin_info['fpga_pin_type']) \
and (1 == len(pin_info['caravel_pin_type'])) \
and ("output" == pin_info['caravel_pin_type'][0])):
# Should have only 1 port in caravel
assert(1 == len(pin_info['caravel_pin_type']))
assert(1 == len(pin_info['caravel_pin_index']))
# Get pin range
fpga_io_pin_range = parse_json_pin_range(pin_info['fpga_pin_index'])
caravel_io_pin_range = parse_json_pin_range(pin_info['caravel_pin_index'][0])
assert(len(list(fpga_io_pin_range)) == len(list(caravel_io_pin_range)))
for indices in zip(list(fpga_io_pin_range), list(caravel_io_pin_range)) :
# Bypass the Caravel input
# Connect Caravel output port to FPGA control output
curr_line = "assign " + pin_data['caravel_gpio_output_name'] + "[" + str(indices[1]) + "] = " \
+ pin_info['fpga_pin_type'] + "[" + str(indices[0]) + "];";
netlist_lines.append(" " + curr_line + "\n")
# Tie Caravel direction port to logic '0'
curr_line = "assign " + pin_data['caravel_gpio_direction_name'] + "[" + str(indices[1]) + "] = 1'b0;"
netlist_lines.append(" " + curr_line + "\n")
elif ((ipin >= num_wishbone_pins) and (ipin < num_logic_analyzer_pins)):
# - FPGA I/O ports to Caravel logic analyzer I/O only
if (("io" == pin_info['fpga_pin_type']) \
and (1 == len(pin_info['caravel_pin_type'])) \
and ("logic_analyzer_io" == pin_info['caravel_pin_type'][0])):
# Should have only 1 port in caravel
assert(1 == len(pin_info['caravel_pin_type']))
assert(1 == len(pin_info['caravel_pin_index']))
# Get pin range
fpga_io_pin_range = parse_json_pin_range(pin_info['fpga_pin_index'])
caravel_io_pin_range = parse_json_pin_range(pin_info['caravel_pin_index'][0])
assert(len(list(fpga_io_pin_range)) == len(list(caravel_io_pin_range)))
for indices in zip(list(fpga_io_pin_range), list(caravel_io_pin_range)) :
##############################################################
# SOC INPUT will be directly driven by logic analyzer
# since this I/O is going to interface logic analyzer input only
curr_line = "assign " + pin_data['fpga_gpio_input_name'] + "[" + str(indices[0]) + "] = " \
+ pin_data['caravel_logic_analyzer_input_name'] + "[" + str(indices[1]) + "]" + ";"
netlist_lines.append(" " + curr_line + "\n")
##############################################################
# SOC OUTPUT will directly drive logic analyzer
# since this I/O is going to interface logic analyzer output only
curr_line = "assign " + pin_data['caravel_logic_analyzer_output_name'] + "[" + str(indices[1]) + "]" \
+ " = " + pin_data['fpga_gpio_output_name'] + "[" + str(indices[0]) + "];"
netlist_lines.append(" " + curr_line + "\n")
# - FPGA I/O ports to Caravel logic analyzer I/O and Wishbone interface
if (("io" == pin_info['fpga_pin_type']) \
and (2 == len(pin_info['caravel_pin_type'])) \
and ("logic_analyzer_io" == pin_info['caravel_pin_type'][0]) \
and (pin_info['caravel_pin_type'][1].startswith("wishbone"))):
# Should have only 2 port in caravel
assert(2 == len(pin_info['caravel_pin_type']))
assert(2 == len(pin_info['caravel_pin_index']))
# Get pin range
fpga_io_pin_range = parse_json_pin_range(pin_info['fpga_pin_index'])
la_io_pin_range = parse_json_pin_range(pin_info['caravel_pin_index'][0])
wb_io_pin_range = parse_json_pin_range(pin_info['caravel_pin_index'][1])
assert(len(list(fpga_io_pin_range)) == len(list(la_io_pin_range)))
assert(len(list(fpga_io_pin_range)) == len(list(wb_io_pin_range)))
# If this is an input pin of wishbone interface, whose postfix is '_i', we use MUX
# otherwise, this is an output pin, we just wire the input to logic analyzer
if (pin_info['caravel_pin_type'][1].endswith("_input")):
for indices in zip(list(fpga_io_pin_range), list(la_io_pin_range), list(wb_io_pin_range)) :
##############################################################
# SOC INPUT will be directly driven by either
# - the Wishbone input
# or
# - the logic analyzer input
# through a multiplexer controlled by the signal 'wb_la_switch
curr_line = "sky130_fd_sc_hd__mux2_1 FPGA2SOC_IN_" + str(indices[0]) + "_MUX (" \
+ ".S(" + pin_data['mode_switch_pin_name'] + "), " \
+ ".A1(" + pin_data['caravel_' + pin_info['caravel_pin_type'][1] + '_name'] + "[" + str(indices[2]) + "]), " \
+ ".A0(" + pin_data['caravel_logic_analyzer_input_name'] + "[" + str(indices[1]) + "]), " \
+ ".X(" + pin_data['fpga_gpio_input_name'] + "[" + str(indices[0]) + "])" \
+ ");"
netlist_lines.append(" " + curr_line + "\n")
##############################################################
# SOC OUTPUT will drive an output of logic analyzer
# since this I/O is going to interface a Wishbone input only
curr_line = "assign " + pin_data['caravel_logic_analyzer_output_name'] + "[" + str(indices[1]) + "]" \
+ " = " + pin_data['fpga_gpio_output_name'] + "[" + str(indices[0]) + "];"
netlist_lines.append(" " + curr_line + "\n")
elif (pin_info['caravel_pin_type'][1].endswith("_output")):
for indices in zip(list(fpga_io_pin_range), list(la_io_pin_range), list(wb_io_pin_range)) :
##############################################################
# SOC INPUT will be directly driven by logic analyzer
# since this I/O is going to interface logic analyzer input only
curr_line = " " + "assign gfpga_pad_EMBEDDED_IO_HD_SOC_IN[" + str(
135 - ipin) + "] = " + str(logic_analyzer_pins[ipin][0]) + ";"
netlist_lines.append(curr_line + "\n")
# since this I/O is going to interface a Wishbone output only
curr_line = "assign " + pin_data['fpga_gpio_input_name'] + "[" + str(indices[0]) + "] = " \
+ pin_data['caravel_logic_analyzer_input_name'] + "[" + str(indices[1]) + "];"
netlist_lines.append(" " + curr_line + "\n")
##############################################################
# SOC OUTPUT will directly drive logic analyzer
# since this I/O is going to interface logic analyzer output only
curr_line = " " + "assign " + \
str(logic_analyzer_pins[ipin][1]) + \
" = gfpga_pad_EMBEDDED_IO_HD_SOC_OUT[" + str(135 - ipin) + "];"
netlist_lines.append(curr_line + "\n")
# SOC OUTPUT will drive the Wishbone output through a tri-state buffer
# As the buffer is enabled by logic '0', we use the inverted 'wb_la_switch'
curr_line = "sky130_fd_sc_hd__ebufn_4 FPGA2SOC_OUT_" + str(indices[0]) + "_DEMUX_WB (" \
+ ".TE_B(" + pin_data['inverted_mode_switch_pin_name'] + "), " \
+ ".A(" + pin_data['fpga_gpio_output_name'] + "[" + str(indices[0]) + "]), " \
+ ".Z(" + pin_data['caravel_' + pin_info['caravel_pin_type'][1] + '_name'] + "[" + str(indices[2]) + "])" \
+ ");"
netlist_lines.append(" " + curr_line + "\n")
##############################################################
# SOC OUTPUT will also drive the Logic Analyzer output through a tri-state buffer
# As the buffer is enabled by logic '0', we use the 'wb_la_switch'
curr_line = "sky130_fd_sc_hd__ebufn_4 FPGA2SOC_OUT_" + str(indices[0]) + "_DEMUX_LA (" \
+ ".TE_B(" + pin_data['mode_switch_pin_name'] + "), " \
+ ".A(" + pin_data['fpga_gpio_output_name'] + "[" + str(indices[0]) + "]), " \
+ ".Z(" + pin_data['caravel_logic_analyzer_output_name'] + "[" + str(indices[1]) + "])" \
+ ");"
netlist_lines.append(" " + curr_line + "\n")
if isfile(args.output_verilog):
os.remove(args.output_verilog)

12
MSIM/README.md Normal file
View File

@ -0,0 +1,12 @@
# Skywater PDK
This directory is the workspace for running Mentor Modelsim simulations for FPGA fabrics
Please keep this directory clean and organize as follows:
- Each task-run should be placed in a separated directory
- **common**: include commonly used scripts for post-PnR verification
- READMD is the only file allowed in the directory, others should be sub-directories.
* Quick Example to run simulations for task-run
```
python3 run_post_pnr_msim_task.py --testbench_dir_name ../../TESTBENCH/k4_N8_caravel_io_FPGA_12x12_fdhd_cc --task_name k4_N8_caravel_io_FPGA_12x12_fdhd_cc
```

View File

@ -9,14 +9,14 @@ proc create_project_with_close {projectname modelsim_path} {
#Get the current project name
set project_env [project env]
if {$project_env eq ""} {
#If string empty (no project)
create_project $projectname $modelsim_path
} else {
#If string not empty (a project is loaded so clsoe it first)
project close
create_project $projectname $modelsim_path
}
#If string empty (no project)
create_project $projectname $modelsim_path
} else {
#If string not empty (a project is loaded so clsoe it first)
project close
create_project $projectname $modelsim_path
}
}
proc add_files_project {verilog_files} {
#Get the length of the list
@ -30,11 +30,9 @@ proc add_files_project {verilog_files} {
proc add_waves {top_tb} {
add wave -position insertpoint sim:/$top_tb/*
}
proc runsim {simtime unit} {
run $simtime $unit
}
#Top procedure to create enw project
proc top_create_new_project {projectname verilog_files modelsim_path simtime unit top_tb} {
proc top_create_new_project {projectname verilog_files modelsim_path top_tb} {
#Create the project
create_project_with_close $projectname $modelsim_path
#Add the verilog files
@ -42,30 +40,12 @@ proc top_create_new_project {projectname verilog_files modelsim_path simtime uni
#Compile all the files
set myFiles [project filenames]
foreach x $myFiles {
vlog +define+ENABLE_TIMING +define+ENABLE_SIGNAL_INITIALIZATION $x
vlog +define+ENABLE_SIGNAL_INITIALIZATION $x
}
#Start the simulation
vsim $projectname.$top_tb -voptargs=+acc
#Add the waves
add_waves $top_tb
#run the simulation
runsim $simtime $unit
#Fit the window view
wave zoom full
}
#Top proc to recompile files and re run the simulation
proc top_rerun_sim {simtime unit top_tb} {
#Save actual format
set myLoc [pwd]
write format wave -window .main_pane.wave.interior.cs.body.pw.wf $myLoc/relaunch.do
quit -sim
#Compile updated verilog files
set myFiles [project filenames]
foreach x $myFiles {
vlog +define+ENABLE_TIMING +define+ENABLE_SIGNAL_INITIALIZATION $x
}
set projectname K4n4_test_fpga_msim
vsim $projectname.$top_tb -voptargs=+acc -do relaunch.do
#run the simulation
run $simtime $unit
run -all
}

View File

@ -0,0 +1,76 @@
#####################################################################
# Python script to run ModelSim simulations for all the post-pnr testbenches
# in a project directory
# This script will
# - Collect all the testbenches in a given directory
# For instance:
# ../k4_arch/pre_pnr/verilog_testbenches/and2_post_pnr_include_netlist.v
# - Use run_post_pnr_msim_test.py to run Modelsim simulations and check results
#####################################################################
import os
from os.path import dirname, abspath
import shutil
import re
import argparse
import logging
import subprocess
import glob
#####################################################################
# Initialize logger
#####################################################################
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
#####################################################################
# Parse the options
#####################################################################
parser = argparse.ArgumentParser(description='Run a ModelSim verification task for a tape-out FPGA')
parser.add_argument('--testbench_dir_name', required=True,
help='Specify the directory path for the Verilog testbenches')
parser.add_argument('--task_name', required=True,
help='Specify the directory path for the Verilog testbenches')
args = parser.parse_args()
#####################################################################
# Walk through the parent directory and find all the pre-PnR testbenches
#####################################################################
logging.info("Finding testbenches...");
testbench_dir_abspath = abspath(args.testbench_dir_name) + "/postpnr/verilog_testbench";
testbench_files = []
for globbed_file in glob.glob(testbench_dir_abspath + "/*_include_netlists.v"):
testbench_files.append(globbed_file)
logging.info("Found " + str(len(testbench_files)) + " testbenches")
#####################################################################
# Try to create the directory of Modelsim projects
#####################################################################
parent_dir_abspath = dirname(dirname(abspath(__file__)))
msim_task_dir_abspath = abspath(parent_dir_abspath + "/" + args.task_name) + "/postpnr/verilog_testbench";
os.makedirs(msim_task_dir_abspath, exist_ok=True)
#####################################################################
# Run ModelSim simulations for each testbench
#####################################################################
logging.info("Running Modelsim simulations...");
num_sim_finished = 0
msim_testrun_script_abspath = os.path.abspath(__file__)
msim_testrun_script_abspath = re.sub(os.path.basename(msim_testrun_script_abspath), "run_post_pnr_msim_test.py", msim_testrun_script_abspath)
for testbench_file in testbench_files:
# Find testbench name
testbench_name = re.findall("(\w+)_include_netlists.v", os.path.basename(testbench_file))[0]
cmd = "python3 " + msim_testrun_script_abspath \
+ " --verilog_testbench " + testbench_file \
+ " --project_path " + msim_task_dir_abspath + "/" + testbench_name \
+ " --testbench_name " + testbench_name + "_autocheck_top_tb"
subprocess.run(cmd, shell=True, check=True)
num_sim_finished += 1
logging.info("Done")
logging.info("Finish " + str(num_sim_finished) + " ModelSim simulations")

View File

@ -0,0 +1,147 @@
#####################################################################
# Python script to execute modelsim simulation for a given testbench netlist
# This script will
# - Create the tcl script to enable modelsim simulation
# - Run modelsim simulation
# - Analyze output log files and return succeed or failure
#####################################################################
import os
from os.path import dirname, abspath, isfile
import shutil
import re
import argparse
import logging
import subprocess
#####################################################################
# Initialize logger
#####################################################################
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
#####################################################################
# Parse the options
#####################################################################
parser = argparse.ArgumentParser(description='Run ModelSim verification for a testbench')
parser.add_argument('--verilog_testbench', required=True,
help='Specify the file path for the Verilog testbench as input')
parser.add_argument('--project_path', required=True,
help='Specify the file path to create the ModelSim project')
parser.add_argument('--testbench_name', required=True,
help='Specify the top-level module of the testbench')
args = parser.parse_args()
#####################################################################
# Check options:
# - Input testbench file must be valid
# Otherwise, error out
# - If the modelsim project path does not exist, create it
#####################################################################
if not isfile(args.verilog_testbench):
logging.error("Invalid Verilog testbench: " + args.verilog_testbench + "\nFile does not exist!\n")
exit(1)
project_abs_path = os.path.abspath(args.project_path)
if not os.path.isdir(project_abs_path):
logging.debug("Creating ModelSim project directory : " + project_abs_path + " ...\n")
os.makedirs(project_abs_path, exist_ok=True)
logging.debug("Done\n")
#####################################################################
# Create the Tcl script for Modelsim
#####################################################################
# Get modelsim process tcl file path
msim_proc_tcl_path = os.path.abspath(__file__)
msim_proc_tcl_path = re.sub(os.path.basename(msim_proc_tcl_path), "modelsim_proc.tcl", msim_proc_tcl_path)
if not isfile(msim_proc_tcl_path):
logging.error("Invalid process script for ModelSim: " + msim_proc_tcl_path + "\nFile does not exist!\n")
exit(1)
# Create output file handler
tcl_file_path = project_abs_path + "/" + os.path.basename(args.testbench_name) + ".tcl"
logging.debug("Generating Tcl script for ModelSim: " + tcl_file_path)
tcl_file = open(tcl_file_path, "w")
# A string buffer to write tcl content
tcl_lines = []
tcl_lines.append("echo \"==============================\"")
tcl_lines.append("pwd")
tcl_lines.append("echo \"==============================\"")
tcl_lines.append("\n")
tcl_lines.append("set project_name " + args.testbench_name)
tcl_lines.append("set top_tb " + args.testbench_name)
tcl_lines.append("\n")
tcl_lines.append("set project_path \"" + project_abs_path + "\"")
tcl_lines.append("set verilog_files \"" + os.path.abspath(args.verilog_testbench) + "\"")
tcl_lines.append("\n")
tcl_lines.append("source " + msim_proc_tcl_path)
tcl_lines.append("\n")
tcl_lines.append("try {")
tcl_lines.append("\ttop_create_new_project $project_name $verilog_files $project_path $top_tb")
tcl_lines.append("} finally {")
tcl_lines.append("\tquit")
tcl_lines.append("}")
for line in tcl_lines:
tcl_file.write(line + "\n")
tcl_file.close()
logging.debug("Done")
#####################################################################
# Run ModelSim simulation
#####################################################################
curr_dir = os.getcwd()
# Change to the project directory
os.chdir(project_abs_path)
logging.debug("Changed to directory: " + project_abs_path)
# Run ModelSim
vsim_log_file_path = project_abs_path + "/vsim_run_log"
vsim_bin = "/uusoc/facility/cad_tools/Mentor/modelsim10.7b/modeltech/bin/vsim"
vsim_cmd = vsim_bin + " -c -do " + os.path.abspath(tcl_file_path) + " > " + vsim_log_file_path
logging.debug("Running modelsim by : " + vsim_cmd)
subprocess.run(vsim_cmd, shell=True, check=True)
# Go back to current directory
os.chdir(curr_dir)
#####################################################################
# Parse log files and report any errors
#####################################################################
vsim_log_file = open(vsim_log_file_path, "r")
# Error counter
num_err = 0
num_err_lines_found = 0
verification_passed = False
for line in vsim_log_file:
# Check errors from self-testing testbench output
if line.startswith("# Simulation finish with") :
num_sim_err = int(re.findall("# Simulation finish with(\s+)(\d+) errors", line)[0][1])
num_err_lines_found = num_err_lines_found + 1
if (0 < num_sim_err) :
logging.error("Simulation failed with " + str(num_sim_err) + " errors!\n")
# Add to total errors
num_err = num_err + num_sim_err
# Check total errors by Modelsim
if line.startswith("# Errors:") :
num_msim_err = int(re.findall("# Errors:(\s)(\d+),", line)[0][1])
num_err_lines_found = num_err_lines_found + 1
num_err = num_err + num_msim_err
vsim_log_file.close()
if (0 == num_err_lines_found) :
logging.error("No error lines found!Something wrong in setting up modelsim simulation\n")
elif (0 < num_err) :
logging.error("ModelSim failed with " + str(num_err) + " errors!\n")
else :
verification_passed = True
if (verification_passed) :
logging.info(args.testbench_name + "...[Passed]\n")
else :
logging.error(args.testbench_name + "...[Failed]\n")

View File

@ -1,4 +1,9 @@
# skywater-openfpga
# Skywater + OpenFPGA: Open-Source FPGAs
[![linux_build](https://github.com/LNIS-Projects/skywater-openfpga/workflows/linux_build/badge.svg)](https://github.com/LNIS-Projects/skywater-openfpga/actions)
[![Documentation Status](https://readthedocs.org/projects/skywater-openfpga/badge/?version=latest)](https://skywater-openfpga.readthedocs.io/en/latest/?badge=latest)
## Introduction
FPGA tape-outs using the open-source Skywater 130nm PDK and OpenFPGA
## Quick Start

View File

@ -0,0 +1,38 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# 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]
run_engine=openfpga_shell
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 = 1*60
fpga_flow=yosys_vpr
[OpenFPGA_SHELL]
openfpga_shell_template=${SKYWATER_OPENFPGA_HOME}/SCRIPT/openfpga_shell_script/skywater_generate_fabric_using_key_example_script.openfpga
openfpga_arch_file=${SKYWATER_OPENFPGA_HOME}/ARCH/openfpga_arch/k4_frac_N8_reset_softadder_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
openfpga_sim_setting_file=${SKYWATER_OPENFPGA_HOME}/SCRIPT/openfpga_simulation_setting/efpga_12x12_sim_openfpga.xml
openfpga_vpr_device_layout=12x12
openfpga_vpr_route_chan_width=40
openfpga_verilog_output_dir=${SKYWATER_OPENFPGA_HOME}/HDL/k4_N8_reset_softadder_caravel_io_FPGA_12x12_fdhd_cc
openfpga_sdc_output_dir=${SKYWATER_OPENFPGA_HOME}/SDC/k4_N8_reset_softadder_caravel_io_FPGA_12x12_fdhd_cc
external_fabric_key_file=${SKYWATER_OPENFPGA_HOME}/ARCH/fabric_key/fabric_key_12x12.xml
[ARCHITECTURES]
arch0=${SKYWATER_OPENFPGA_HOME}/ARCH/vpr_arch/k4_frac_N8_tileable_reset_softadder_register_scan_chain_nonLR_caravel_io_skywater130nm.xml
[BENCHMARKS]
bench0=${SKYWATER_OPENFPGA_HOME}/BENCHMARK/and2/and2.v
[SYNTHESIS_PARAM]
bench0_top = and2
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
#end_flow_with_test=

View File

@ -0,0 +1,37 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# 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]
run_engine=openfpga_shell
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 = 1*60
fpga_flow=yosys_vpr
[OpenFPGA_SHELL]
openfpga_shell_template=${SKYWATER_OPENFPGA_HOME}/SCRIPT/openfpga_shell_script/skywater_generate_sdc_using_key_example_script.openfpga
openfpga_arch_file=${SKYWATER_OPENFPGA_HOME}/ARCH/openfpga_arch/k4_frac_N8_reset_softadder_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
openfpga_sim_setting_file=${SKYWATER_OPENFPGA_HOME}/SCRIPT/openfpga_simulation_setting/efpga_12x12_sim_openfpga.xml
openfpga_vpr_device_layout=12x12
openfpga_vpr_route_chan_width=40
openfpga_sdc_output_dir=${SKYWATER_OPENFPGA_HOME}/SDC/k4_N8_reset_softadder_caravel_io_FPGA_12x12_fdhd_cc
external_fabric_key_file=${SKYWATER_OPENFPGA_HOME}/ARCH/fabric_key/fabric_key_12x12.xml
[ARCHITECTURES]
arch0=${SKYWATER_OPENFPGA_HOME}/ARCH/vpr_arch/k4_frac_N8_tileable_reset_softadder_register_scan_chain_nonLR_caravel_io_skywater130nm.xml
[BENCHMARKS]
bench0=${SKYWATER_OPENFPGA_HOME}/BENCHMARK/and2/and2.v
[SYNTHESIS_PARAM]
bench0_top = and2
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
#end_flow_with_test=

View File

@ -0,0 +1,54 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# 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]
run_engine=openfpga_shell
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 = 1*60
fpga_flow=yosys_vpr
[OpenFPGA_SHELL]
openfpga_shell_template=${SKYWATER_OPENFPGA_HOME}/SCRIPT/openfpga_shell_script/skywater_generate_testbench_using_key_example_script.openfpga
openfpga_arch_file=${SKYWATER_OPENFPGA_HOME}/ARCH/openfpga_arch/k4_frac_N8_reset_softadder_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
openfpga_sim_setting_file=${SKYWATER_OPENFPGA_HOME}/SCRIPT/openfpga_simulation_setting/efpga_12x12_sim_openfpga.xml
openfpga_vpr_device_layout=12x12
openfpga_vpr_route_chan_width=40
openfpga_verilog_output_dir=${SKYWATER_OPENFPGA_HOME}/TESTBENCH/k4_N8_reset_softadder_caravel_io_FPGA_12x12_fdhd_cc/prepnr
openfpga_fabric_verilog_netlist=${SKYWATER_OPENFPGA_HOME}/HDL/k4_N8_reset_softadder_caravel_io_FPGA_12x12_fdhd_cc/SRC/fabric_netlists.v
external_fabric_key_file=${SKYWATER_OPENFPGA_HOME}/ARCH/fabric_key/fabric_key_12x12.xml
[ARCHITECTURES]
arch0=${SKYWATER_OPENFPGA_HOME}/ARCH/vpr_arch/k4_frac_N8_tileable_reset_softadder_register_scan_chain_nonLR_caravel_io_skywater130nm.xml
[BENCHMARKS]
bench0=${SKYWATER_OPENFPGA_HOME}/BENCHMARK/and2/and2.v
bench1=${SKYWATER_OPENFPGA_HOME}/BENCHMARK/and2_latch/and2_latch.v
bench2=${SKYWATER_OPENFPGA_HOME}/BENCHMARK/bin2bcd/bin2bcd.v
bench3=${SKYWATER_OPENFPGA_HOME}/BENCHMARK/counter/counter.v
bench4=${SKYWATER_OPENFPGA_HOME}/BENCHMARK/routing_test/routing_test.v
# RS decoder needs 1.5k LUT4, exceeding device capacity
#bench5=${SKYWATER_OPENFPGA_HOME}/BENCHMARK/rs_decoder/rtl/rs_decoder.v
bench6=${SKYWATER_OPENFPGA_HOME}/BENCHMARK/simon_bit_serial/rtl/*.v
bench7=${SKYWATER_OPENFPGA_HOME}/BENCHMARK/and2_or2/and2_or2.v
[SYNTHESIS_PARAM]
bench0_top = and2
bench1_top = and2_latch
bench2_top = bin2bcd
bench3_top = counter
bench4_top = routing_test
# RS decoder needs 1.5k LUT4, exceeding device capacity
#bench5_top = rs_decoder_top
bench6_top = top_module
bench7_top = and2_or2
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
#end_flow_with_test=

BIN
TESTBENCH/common/ccff_test_post_pnr.v (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -25,56 +25,75 @@ import glob
#####################################################################
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG)
#####################################################################
# Parse the options
#####################################################################
parser = argparse.ArgumentParser(description='Generate post-PnR testbenches for a given directory')
parser.add_argument('--pre_pnr_testbench_dir_name', required=True,
help='Specify the directory path for the pre-PnR Verilog testbenches')
parser.add_argument('--pin_assignment_file', required=True,
help='Specify the file path to the pin assignment JSON description as input')
args = parser.parse_args()
#####################################################################
# Walk through the parent directory and find all the pre-PnR testbenches
#####################################################################
logging.info("Finding pre-PnR testbenches...");
parent_dirpath = dirname(dirname(abspath(__file__)))
script_base_dir_abspath = dirname(os.path.abspath(__file__))
pre_pnr_testbench_dir_abspath = abspath(args.pre_pnr_testbench_dir_name) + "/prepnr/verilog_testbench";
# Count how many testbenches have been converted
num_converted_testbenches = 0
# Collect the pre-PnR testbenches to be converted
pre_pnr_testbench_files = []
post_pnr_testbench_dirs = []
for root, dirs, files in os.walk(parent_dirpath):
for dir_name in dirs:
# Skip 'common' directory as the testbenches inside are already converted
# Also skip any hidden directories
if ((dir_name == "common") or (dir_name.startswith("."))):
continue;
# Find the testbenches in the fixed location of the tree
curr_pre_pnr_testbench_dir_path = os.path.join(root, dir_name + "/prepnr/verilog_testbench")
# Add to list
logging.info("Checking directory: " + str(curr_pre_pnr_testbench_dir_path))
for globbed_file in glob.glob(curr_pre_pnr_testbench_dir_path + "/*_autocheck_top_tb.v"):
pre_pnr_testbench_files.append(globbed_file)
# If we have testbenches to convert, try to create the directory of post-pnr testbenches
curr_post_pnr_testbench_dir_path = os.path.join(root, dir_name + "/postpnr/verilog_testbench")
post_pnr_testbench_dirs.append(curr_post_pnr_testbench_dir_path)
# Add to list
for globbed_file in glob.glob(pre_pnr_testbench_dir_abspath + "/*_autocheck_top_tb.v"):
pre_pnr_testbench_files.append(globbed_file)
# If we have testbenches to convert, try to create the directory of post-pnr testbenches
post_pnr_testbench_dir_abspath = abspath(args.pre_pnr_testbench_dir_name) + "/postpnr/verilog_testbench";
logging.info("Found " + str(len(pre_pnr_testbench_files)) + " pre-PnR testbenches")
#####################################################################
# Try to create the directory of post-pnr testbenches
#####################################################################
for post_pnr_testbench_dir in post_pnr_testbench_dirs:
os.makedirs(curr_post_pnr_testbench_dir_path, exist_ok=True)
os.makedirs(post_pnr_testbench_dir_abspath, exist_ok=True)
#####################################################################
# Convert pre-PnR testbenches to post-PnR testbenches
#####################################################################
logging.info("Converting pre-PnR testbench to post-PnR testbench...");
for curr_pre_pnr_testbench_file in pre_pnr_testbench_files:
logging.info("\nProcessing " + curr_pre_pnr_testbench_file + " testbench:\n")
logging.info("Processing " + curr_pre_pnr_testbench_file + " testbench:")
curr_post_pnr_testbench_file = re.sub("_autocheck_top_tb.v$", "_post_pnr_autocheck_top_tb.v", curr_pre_pnr_testbench_file)
curr_post_pnr_testbench_file = re.sub("\/prepnr\/", "\/postpnr\/", curr_post_pnr_testbench_file)
cmd = "python3 ./post_pnr_testbench_converter.py " \
cmd = "python3 " + script_base_dir_abspath + "/post_pnr_testbench_converter.py " \
+ " --pre_pnr_testbench " + curr_pre_pnr_testbench_file \
+ " --post_pnr_testbench " + curr_post_pnr_testbench_file
subprocess.run(cmd, shell=True, check=True)
num_converted_testbenches += 1
logging.info("Done")
logging.info("\nConverted " + str(num_converted_testbenches) + " testbenches.")
#####################################################################
# Convert post-PnR testbenches to wrapper testbenches
#####################################################################
logging.info("Converting pre-PnR testbench to post-PnR testbench...");
for curr_pre_pnr_testbench_file in pre_pnr_testbench_files:
curr_post_pnr_testbench_file = re.sub("_autocheck_top_tb.v$", "_post_pnr_autocheck_top_tb.v", curr_pre_pnr_testbench_file)
curr_post_pnr_testbench_file = re.sub("\/prepnr\/", "\/postpnr\/", curr_post_pnr_testbench_file)
curr_wrapper_testbench_file = re.sub("_autocheck_top_tb.v$", "_wrapper_autocheck_top_tb.v", curr_post_pnr_testbench_file)
logging.info("Processing " + curr_post_pnr_testbench_file + " testbench:")
cmd = "python3 " + script_base_dir_abspath + "/post_pnr_wrapper_testbench_converter.py " \
+ " --post_pnr_testbench " + curr_post_pnr_testbench_file \
+ " --pin_assignment_file " + args.pin_assignment_file \
+ " --wrapper_testbench " + curr_wrapper_testbench_file
subprocess.run(cmd, shell=True, check=True)
num_converted_testbenches += 1
logging.info("Done")
logging.info("Done")
logging.info("\nConverted " + str(num_converted_testbenches) + " testbenches.")

View File

@ -1,197 +0,0 @@
//-------------------------------------------
// Verilog Testbench for Verifying
// Configuration Chain of a FPGA
// Description: This test is applicable to FPGAs which have 1 configuration
// chain. It will feed a pulse to the head of the configuration chain and
// check if the pulse is outputted by the tail of the configuration chain
// in a given time period
//
// Note: This test bench is tuned for the post PnR netlists
// Author: Xifan TANG
// Organization: University of Utah
//-------------------------------------------
//----- Time scale -----
`timescale 1ns / 1ps
// Design parameter for FPGA I/O sizes
//`define FPGA_IO_SIZE 144
//
// Design parameter for FPGA bitstream sizes
//`define FPGA_BITSTREAM_SIZE 65656
module post_pnr_ccff_test;
// ----- Local wires for global ports of FPGA fabric -----
wire [0:0] prog_clk;
wire [0:0] Test_en;
wire [0:0] clk;
// ----- Local wires for I/Os of FPGA fabric -----
wire [0:`FPGA_IO_SIZE - 1] gfpga_pad_EMBEDDED_IO_SOC_IN;
wire [0:`FPGA_IO_SIZE - 1] gfpga_pad_EMBEDDED_IO_SOC_OUT;
wire [0:`FPGA_IO_SIZE - 1] gfpga_pad_EMBEDDED_IO_SOC_DIR;
wire [0:0] prog_clock;
reg [0:0] prog_clock_reg;
wire [0:0] op_clock;
reg [0:0] op_clock_reg;
reg [0:0] prog_reset;
reg [0:0] prog_set;
reg [0:0] greset;
reg [0:0] gset;
// ---- Configuration-chain head -----
reg [0:0] ccff_head;
// ---- Configuration-chain tail -----
wire [0:0] ccff_tail;
// ---- Scan-chain head -----
wire [0:0] sc_head;
// ---- Scan-chain tail -----
wire [0:0] sc_tail;
wire [0:0] IO_ISOL_N;
// ----- Counters for error checking -----
integer num_prog_cycles = 0;
integer num_errors = 0;
integer num_checked_points = 0;
// Indicate when configuration should be finished
reg config_done = 0;
initial
begin
config_done = 1'b0;
end
// ----- Begin raw programming clock signal generation -----
initial
begin
prog_clock_reg[0] = 1'b0;
end
always
begin
#5 prog_clock_reg[0] = ~prog_clock_reg[0];
end
// ----- End raw programming clock signal generation -----
// ----- Actual programming clock is triggered only when config_done and prog_reset are disabled -----
assign prog_clock[0] = prog_clock_reg[0] & (~prog_reset[0]);
// ----- Begin raw operating clock signal generation -----
initial
begin
op_clock_reg[0] = 1'b0;
end
// ----- End raw operating clock signal generation -----
// ----- Actual operating clock is triggered only when config_done is enabled -----
assign op_clock[0] = op_clock_reg[0];
// ----- Begin programming reset signal generation -----
initial
begin
prog_reset[0] = 1'b1;
#10 prog_reset[0] = 1'b0;
end
// ----- End programming reset signal generation -----
// ----- Begin programming set signal generation -----
initial
begin
prog_set[0] = 1'b1;
#10 prog_set[0] = 1'b0;
end
// ----- End programming set signal generation -----
// ----- Begin operating reset signal generation -----
// ----- Reset signal is disabled always -----
initial
begin
greset[0] = 1'b1;
end
// ----- End operating reset signal generation -----
// ----- Begin operating set signal generation: always disabled -----
initial
begin
gset[0] = 1'b0;
end
// ----- End operating set signal generation: always disabled -----
// ----- Begin connecting global ports of FPGA fabric to stimuli -----
assign clk[0] = op_clock[0];
assign prog_clk[0] = prog_clock[0];
assign Test_en[0] = 1'b0;
assign sc_head[0] = 1'b0;
assign IO_ISOL_N[0] = 1'b0;
// ----- End connecting global ports of FPGA fabric to stimuli -----
// ----- FPGA top-level module to be capsulated -----
fpga_core FPGA_DUT (
.prog_clk(prog_clk[0]),
.Test_en(Test_en[0]),
.clk(clk[0]),
.gfpga_pad_EMBEDDED_IO_HD_SOC_IN(gfpga_pad_EMBEDDED_IO_SOC_IN[0:`FPGA_IO_SIZE - 1]),
.gfpga_pad_EMBEDDED_IO_HD_SOC_OUT(gfpga_pad_EMBEDDED_IO_SOC_OUT[0:`FPGA_IO_SIZE - 1]),
.gfpga_pad_EMBEDDED_IO_HD_SOC_DIR(gfpga_pad_EMBEDDED_IO_SOC_DIR[0:`FPGA_IO_SIZE - 1]),
.ccff_head(ccff_head[0]),
.ccff_tail(ccff_tail[0]),
.sc_head(sc_head[0]),
.sc_tail(sc_tail[0]),
.IO_ISOL_N(IO_ISOL_N)
);
// ----- Force constant '0' to FPGA I/O as this testbench only check
// programming phase -----
assign gfpga_pad_EMBEDDED_IO_SOC_IN[0:`FPGA_IO_SIZE - 1] = {`FPGA_IO_SIZE {1'b0}};
assign gfpga_pad_EMBEDDED_IO_SOC_OUT[0:`FPGA_IO_SIZE - 1] = {`FPGA_IO_SIZE {1'b0}};
// Generate a pulse after programming reset is disabled (in the 2nd clock
// cycle). Then the head of configuration chain should be always zero
always @(negedge prog_clock[0]) begin
ccff_head = 1'b1;
if (0 != num_prog_cycles) begin
ccff_head = 1'b0;
end
end
// ----- Count the number of programming cycles -------
always @(posedge prog_clock[0]) begin
num_prog_cycles = num_prog_cycles + 1;
// Indicate when configuration is suppose to end
if (`FPGA_BITSTREAM_SIZE + 1 == num_prog_cycles) begin
config_done = 1'b1;
end
// Check the ccff_tail when configuration is done
if (1'b1 == config_done) begin
// The tail should spit a pulse after configuration is done
// So it should be at logic '1' and then pulled down to logic '0'
if (0 == num_checked_points) begin
if (ccff_tail !== 1'b1) begin
$display("Error: ccff_tail = %b", sc_tail);
num_errors = num_errors + 1;
end
end
if (1 <= num_checked_points) begin
if (ccff_tail !== 1'b0) begin
$display("Error: ccff_tail = %b", sc_tail);
num_errors = num_errors + 1;
end
end
num_checked_points = num_checked_points + 1;
end
if (2 < num_checked_points) begin
$display("Simulation finish with %d errors", num_errors);
// End simulation
$finish;
end
end
endmodule

BIN
TESTBENCH/common/post_pnr_fpga_cells.v (Stored with Git LFS)

Binary file not shown.

View File

@ -1,193 +0,0 @@
//-------------------------------------------
// Verilog Testbench for Verifying
// Scan Chain of a FPGA
// Description: This test is applicable to FPGAs which have a built-in scan
// chain. It will feed a pulse to the head of the scan chain and
// check if the pulse is outputted by the tail of the can chain
// in a given time period
//
// Note: This test bench is tuned for the pre PnR netlists
// Author: Xifan TANG
// Organization: University of Utah
//-------------------------------------------
//----- Time scale -----
`timescale 1ns / 1ps
// Design parameter for FPGA I/O sizes
//`define FPGA_IO_SIZE 144
//
// Design parameter for FPGA scan-chain sizes
//`define FPGA_SCANCHAIN_SIZE 2304
module post_pnr_scff_test;
// ----- Local wires for global ports of FPGA fabric -----
wire [0:0] prog_clk;
wire [0:0] Test_en;
wire [0:0] clk;
// ----- Local wires for I/Os of FPGA fabric -----
wire [0:`FPGA_IO_SIZE - 1] gfpga_pad_EMBEDDED_IO_HD_SOC_IN;
wire [0:`FPGA_IO_SIZE - 1] gfpga_pad_EMBEDDED_IO_HD_SOC_OUT;
wire [0:`FPGA_IO_SIZE - 1] gfpga_pad_EMBEDDED_IO_HD_SOC_DIR;
reg [0:0] prog_clock_reg;
wire [0:0] prog_clock;
wire [0:0] op_clock;
reg [0:0] op_clock_reg;
reg [0:0] prog_reset;
reg [0:0] prog_set;
reg [0:0] greset;
reg [0:0] gset;
// ---- Configuration-chain head -----
wire [0:0] ccff_head;
// ---- Configuration-chain tail -----
wire [0:0] ccff_tail;
// ---- Scan-chain head -----
reg [0:0] sc_head;
// ---- Scan-chain tail -----
wire [0:0] sc_tail;
wire [0:0] IO_ISOL_N;
// ----- Counters for error checking -----
integer num_clock_cycles = 0;
integer num_errors = 0;
integer num_checked_points = 0;
// Indicate when configuration should be finished
reg scan_done = 0;
initial
begin
scan_done = 1'b0;
end
// ----- Begin raw programming clock signal generation -----
initial
begin
prog_clock_reg[0] = 1'b0;
end
// ----- End raw programming clock signal generation -----
// ----- Begin raw operating clock signal generation -----
initial
begin
op_clock_reg[0] = 1'b0;
end
always
begin
#5 op_clock_reg[0] = ~op_clock_reg[0];
end
// ----- End raw operating clock signal generation -----
// ----- Actual operating clock is triggered only when scan_done is enabled -----
assign prog_clock[0] = prog_clock_reg[0] & ~greset;
assign op_clock[0] = op_clock_reg[0] & ~greset;
// ----- Begin programming reset signal generation -----
initial
begin
prog_reset[0] = 1'b0;
end
// ----- End programming reset signal generation -----
// ----- Begin programming set signal generation -----
initial
begin
prog_set[0] = 1'b0;
end
// ----- End programming set signal generation -----
// ----- Begin operating reset signal generation -----
// ----- Reset signal is disabled always -----
initial
begin
greset[0] = 1'b1;
#10 greset[0] = 1'b0;
end
// ----- End operating reset signal generation -----
// ----- Begin operating set signal generation: always disabled -----
initial
begin
gset[0] = 1'b0;
end
// ----- End operating set signal generation: always disabled -----
// ----- Begin connecting global ports of FPGA fabric to stimuli -----
assign clk[0] = op_clock[0];
assign prog_clk[0] = prog_clock[0];
assign Test_en[0] = ~greset;
assign ccff_head[0] = 1'b0;
assign IO_ISOL_N[0] = 1'b0;
// ----- End connecting global ports of FPGA fabric to stimuli -----
// ----- FPGA top-level module to be capsulated -----
fpga_core FPGA_DUT (
.prog_clk(prog_clk[0]),
.Test_en(Test_en[0]),
.clk(clk[0]),
.gfpga_pad_EMBEDDED_IO_HD_SOC_IN(gfpga_pad_EMBEDDED_IO_HD_SOC_IN[0:`FPGA_IO_SIZE - 1]),
.gfpga_pad_EMBEDDED_IO_HD_SOC_OUT(gfpga_pad_EMBEDDED_IO_HD_SOC_OUT[0:`FPGA_IO_SIZE - 1]),
.gfpga_pad_EMBEDDED_IO_HD_SOC_DIR(gfpga_pad_EMBEDDED_IO_HD_SOC_DIR[0:`FPGA_IO_SIZE - 1]),
.ccff_head(ccff_head[0]),
.ccff_tail(ccff_tail[0]),
.sc_head(sc_head[0]),
.sc_tail(sc_tail[0]),
.IO_ISOL_N(IO_ISOL_N)
);
// ----- Force constant '0' to FPGA I/O as this testbench only check
// programming phase -----
assign gfpga_pad_EMBEDDED_IO_HD_SOC_IN[0:`FPGA_IO_SIZE - 1] = {`FPGA_IO_SIZE {1'b0}};
assign gfpga_pad_EMBEDDED_IO_HD_SOC_OUT[0:`FPGA_IO_SIZE - 1] = {`FPGA_IO_SIZE {1'b0}};
// Generate a pulse after operating reset is disabled (in the 2nd clock
// cycle). Then the head of scan chain should be always zero
always @(negedge op_clock[0]) begin
sc_head = 1'b1;
if (0 != num_clock_cycles) begin
sc_head = 1'b0;
end
end
// ----- Count the number of programming cycles -------
always @(posedge op_clock[0]) begin
num_clock_cycles = num_clock_cycles + 1;
// Indicate when scan chain loading is suppose to end
if (`FPGA_SCANCHAIN_SIZE + 1 == num_clock_cycles) begin
scan_done = 1'b1;
end
// Check the tail of scan-chain when configuration is done
if (1'b1 == scan_done) begin
// The tail should spit a pulse after configuration is done
// So it should be at logic '1' and then pulled down to logic '0'
if (0 == num_checked_points) begin
if (sc_tail !== 1'b1) begin
$display("Error: sc_tail = %b", sc_tail);
num_errors = num_errors + 1;
end
end
if (1 <= num_checked_points) begin
if (sc_tail !== 1'b0) begin
$display("Error: sc_tail = %b", sc_tail);
num_errors = num_errors + 1;
end
end
num_checked_points = num_checked_points + 1;
end
if (2 < num_checked_points) begin
$display("Simulation finish with %d errors", num_errors);
// End simulation
$finish;
end
end
endmodule

View File

@ -61,6 +61,11 @@ with open(args.pre_pnr_testbench, "r") as wp:
# Other lines can be directly copied to post-PnR Verilog testbenches
line2output = curr_line \
# Condition A:
# Add post_pnr to top-level module name
if (curr_line.startswith("module")):
line2output = re.sub("autocheck_top_tb;$", "post_pnr_autocheck_top_tb;", curr_line)
# Add sc_head and sc_tail wire definition after ccff tail definition
# Condition B:
# Add sc_head and sc_tail wire definition after ccff tail definition
if (curr_line == "wire [0:0] ccff_tail;\n"):
line2output = line2output \
@ -68,16 +73,16 @@ with open(args.pre_pnr_testbench, "r") as wp:
+ "wire [0:0] sc_head;\n" \
+ "// ---- Scan-chain tail ----\n" \
+ "wire [0:0] sc_tail;\n"
# Condition B:
# Condition C:
# Assign an initial value to sc_head after other ports
elif (curr_line == "\tassign IO_ISOL_N[0] = 1'b1;\n"):
line2output = line2output \
+ "\tassign sc_head[0] = 1'b0;\n"
# Condition C:
# Condition D:
# Replace fpga_top with fpga_core in DUT instanciation
elif (curr_line == "\tfpga_top FPGA_DUT (\n"):
line2output = "\tfpga_core FPGA_DUT (\n"
# Condition D:
# Condition E:
# Add sc_head and sc_tail to the port mapping of FPGA core instance
elif (curr_line == "\t\t.ccff_tail(ccff_tail[0]));\n"):
line2output = "\t\t.ccff_tail(ccff_tail[0]),\n" \

View File

@ -0,0 +1,300 @@
#####################################################################
# Python script to convert a post-PnR Verilog testbench
# to a post-PnR Verilog testbench based on Caravel Wrapper
# This script will
# - Replace the FPGA instance with a Caravel wrapper instance
# - Generate wrapper input ports based on a pin assignment json file
#####################################################################
import os
from os.path import dirname, abspath, isfile
import shutil
import re
import argparse
import logging
import json
#####################################################################
# Initialize logger
#####################################################################
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG)
#####################################################################
# Parse the options
#####################################################################
parser = argparse.ArgumentParser(description='Converter for post-PnR wrapper Verilog testbench')
parser.add_argument('--post_pnr_testbench', required=True,
help='Specify the file path for the post-PnR Verilog testbench as input')
parser.add_argument('--pin_assignment_file', required=True,
help='Specify the file path to the pin assignment JSON description as input')
parser.add_argument('--wrapper_testbench', required=True,
help='Specify the file path for the post-PnR wrapper Verilog testbench to be outputted')
args = parser.parse_args()
#####################################################################
# Check options:
# - Input file must be valid
# Otherwise, error out
# - Remove any output file if already exist
# TODO: give a warning when remove files
#####################################################################
if not isfile(args.post_pnr_testbench):
logging.error("Invalid pre-PnR testbench: " + args.post_pnr_testbench + "\nFile does not exist!\n")
exit(1)
if not isfile(args.pin_assignment_file):
logging.error("Invalid pin assignment file: " + args.pin_assignment_file + "\nFile does not exist!\n")
exit(1)
if isfile(args.wrapper_testbench):
logging.warn("Remove existing post-PnR testbench: " + args.wrapper_testbench + "!\n")
os.remove(args.wrapper_testbench)
#####################################################################
# Parse the json file
#####################################################################
json_file = open(args.pin_assignment_file, "r")
pin_data = json.load(json_file)
#####################################################################
# TODO: This is a duplicated function from the wrapper_lines_generator.py
# Should merge them and make it shareable between scripts
# A function to parse pin range from json data
# JSON pin range format is LSB:MSB
# Return pin range format is [LSB, MSB] as a list
#####################################################################
def parse_json_pin_range(json_range) :
pin_range_str = json_range.split(':')
assert(2 == len(pin_range_str))
# If the range is in decend order, we will decrease the MSB by 1
if (int(pin_range_str[0]) > int(pin_range_str[1])) :
return range(int(pin_range_str[0]), int(pin_range_str[1]) - 1, -1)
# If the range is in acend order, we will increase the MSB by 1
return range(int(pin_range_str[0]), int(pin_range_str[1]) + 1)
#####################################################################
# Write the connections between wrapper ports and existing stimuli
# to the testbench file
#####################################################################
def write_testbench_wrapper_connection(tb_file, pin_data, mode_switch_io_index):
# Switch to the logic analyzer mode for io[25] which is reserved for mode-switch purpose
mode_switch_line = "assign " + pin_data['caravel_gpio_input_name'] + "[" + str(mode_switch_io_index) + "] = " \
+ "1'b0;";
tb_file.write(" " + mode_switch_line + "\n")
for pin_info in pin_data['pins']:
#######################################################
# For FPGA INPUTs,
# wrapper inputs should be driven these existing wires
# For instance:
# assign wrapper_input = FPGA_INPUT;
#
# For FPGA OUTPUTs,
# wrapper outputs should drive these existing wires
# For instance:
# assign FPGA_OUTPUT = wrapper_output;
# - FPGA I/O ports to Caravel GPIO
if (("io" == pin_info['fpga_pin_type']) \
and (1 == len(pin_info['caravel_pin_type'])) \
and ("gpio" == pin_info['caravel_pin_type'][0])):
# Should have only 1 port in caravel
assert(1 == len(pin_info['caravel_pin_type']))
assert(1 == len(pin_info['caravel_pin_index']))
# Get pin range
fpga_io_pin_range = parse_json_pin_range(pin_info['fpga_pin_index'])
caravel_io_pin_range = parse_json_pin_range(pin_info['caravel_pin_index'][0])
assert(len(list(fpga_io_pin_range)) == len(list(caravel_io_pin_range)))
for indices in zip(list(fpga_io_pin_range), list(caravel_io_pin_range)) :
# FPGA input <- Caravel input
curr_line = "assign " + pin_data['caravel_gpio_input_name'] + "[" + str(indices[1]) + "] = " \
+ pin_data['fpga_gpio_input_name'] + "[" + str(indices[0]) + "];";
tb_file.write(" " + curr_line + "\n")
# FPGA output -> Caravel output
curr_line = "assign " + pin_data['fpga_gpio_output_name'] + "[" + str(indices[0]) + "] = " \
+ pin_data['caravel_gpio_output_name'] + "[" + str(indices[1]) + "];";
tb_file.write(" " + curr_line + "\n")
# FPGA direction -> Caravel direction
curr_line = "assign " + pin_data['fpga_gpio_direction_name'] + "[" + str(indices[0]) + "] = " \
+ pin_data['caravel_gpio_direction_name'] + "[" + str(indices[1]) + "];";
tb_file.write(" " + curr_line + "\n")
# - FPGA control input ports to Caravel GPIO
if (("io" != pin_info['fpga_pin_type']) \
and (1 == len(pin_info['caravel_pin_type'])) \
and ("input" == pin_info['caravel_pin_type'][0])):
# Should have only 1 port in caravel
assert(1 == len(pin_info['caravel_pin_type']))
assert(1 == len(pin_info['caravel_pin_index']))
# Get pin range
fpga_io_pin_range = parse_json_pin_range(pin_info['fpga_pin_index'])
caravel_io_pin_range = parse_json_pin_range(pin_info['caravel_pin_index'][0])
assert(len(list(fpga_io_pin_range)) == len(list(caravel_io_pin_range)))
for indices in zip(list(fpga_io_pin_range), list(caravel_io_pin_range)) :
# Connect the FPGA input port to the Caravel input
curr_line = "assign " + pin_data['caravel_gpio_input_name'] + "[" + str(indices[1]) + "] = " \
+ pin_info['fpga_pin_type'] + "[" + str(indices[0]) + "];";
tb_file.write(" " + curr_line + "\n")
# - FPGA control output ports to Caravel GPIO
if (("io" != pin_info['fpga_pin_type']) \
and (1 == len(pin_info['caravel_pin_type'])) \
and ("output" == pin_info['caravel_pin_type'][0])):
# Should have only 1 port in caravel
assert(1 == len(pin_info['caravel_pin_type']))
assert(1 == len(pin_info['caravel_pin_index']))
# Get pin range
fpga_io_pin_range = parse_json_pin_range(pin_info['fpga_pin_index'])
caravel_io_pin_range = parse_json_pin_range(pin_info['caravel_pin_index'][0])
assert(len(list(fpga_io_pin_range)) == len(list(caravel_io_pin_range)))
for indices in zip(list(fpga_io_pin_range), list(caravel_io_pin_range)) :
# Tie the Caravel input to logic '0'
curr_line = "assign " + pin_data['caravel_gpio_input_name'] + "[" + str(indices[1]) + "] = 1'b0;"
tb_file.write(" " + curr_line + "\n")
# Connect Caravel output port to FPGA control output
curr_line = "assign " + pin_info['fpga_pin_type'] + "[" + str(indices[0]) + "] = " \
+ pin_data['caravel_gpio_output_name'] + "[" + str(indices[1]) + "];";
tb_file.write(" " + curr_line + "\n")
# - We always try to use the logic analyzer to connect FPGA I/O ports
if (("io" == pin_info['fpga_pin_type']) \
and ("logic_analyzer_io" == pin_info['caravel_pin_type'][0])):
# Get pin range
fpga_io_pin_range = parse_json_pin_range(pin_info['fpga_pin_index'])
caravel_io_pin_range = parse_json_pin_range(pin_info['caravel_pin_index'][0])
assert(len(list(fpga_io_pin_range)) == len(list(caravel_io_pin_range)))
for indices in zip(list(fpga_io_pin_range), list(caravel_io_pin_range)) :
##############################################################
# SOC INPUT will be directly driven by logic analyzer
# since this I/O is going to interface logic analyzer input only
curr_line = "assign " + pin_data['caravel_logic_analyzer_input_name'] + "[" + str(indices[1]) + "] = " \
+ pin_data['fpga_gpio_input_name'] + "[" + str(indices[0]) + "]" + ";"
tb_file.write(" " + curr_line + "\n")
##############################################################
# SOC OUTPUT will directly drive logic analyzer
# since this I/O is going to interface logic analyzer output only
curr_line = "assign " + pin_data['fpga_gpio_output_name'] + "[" + str(indices[0]) + "]" \
+ " = " + pin_data['caravel_logic_analyzer_output_name'] + "[" + str(indices[1]) + "];"
tb_file.write(" " + curr_line + "\n")
#####################################################################
# Open the post-pnr Verilog testbench and start modification
#####################################################################
logging.info("Converting post-PnR testbench:"+ args.post_pnr_testbench)
logging.info("To post-PnR wrapper testbench:"+ args.wrapper_testbench)
# Create output file handler
tb_file = open(args.wrapper_testbench, "w")
#################################
# Control signals to output lines
# Skip current line: when raised, current line will not be outputted
skip_current_line = False
fpga_instance_lines = False
# Read line by line from pre-PnR testbench
with open(args.post_pnr_testbench, "r") as wp:
template_netlist = wp.readlines()
for line_num, curr_line in enumerate(template_netlist):
# If the current line satisfy the following conditions
# It should be modified and outputted to post-PnR Verilog testbenches
# Other lines can be directly copied to post-PnR Verilog testbenches
line2output = curr_line
#
# Add post_pnr to top-level module name
if (curr_line.startswith("module")):
line2output = re.sub("autocheck_top_tb;$", "wrapper_autocheck_top_tb;", curr_line)
# Add the wires required by the wrapper
if (curr_line == "wire [0:0] sc_tail;\n"):
line2output = line2output \
+ "// ---- Wrapper I/O wires ----\n" \
+ "// ---- Power pins ----\n" \
+ "wire [0:0] vdda1;\n" \
+ "wire [0:0] vdda2;\n" \
+ "wire [0:0] vssa1;\n" \
+ "wire [0:0] vssa2;\n" \
+ "wire [0:0] vccd1;\n" \
+ "wire [0:0] vccd2;\n" \
+ "wire [0:0] vssd1;\n" \
+ "wire [0:0] vssd2;\n" \
+ "// ---- Wishbone pins ----\n" \
+ "wire [0:0] wb_clk_i;\n" \
+ "wire [0:0] wb_rst_i;\n" \
+ "wire [0:0] wbs_stb_i;\n" \
+ "wire [0:0] wbs_cyc_i;\n" \
+ "wire [0:0] wbs_we_i;\n" \
+ "wire [3:0] wbs_sel_i;\n" \
+ "wire [31:0] wbs_dat_i;\n" \
+ "wire [31:0] wbs_adr_i;\n" \
+ "wire [0:0] wbs_ack_o;\n" \
+ "wire [31:0] wbs_dat_o;\n" \
+ "// ---- Logic analyzer pins ----\n" \
+ "wire [127:0] la_data_in;\n" \
+ "wire [127:0] la_data_out;\n" \
+ "wire [127:0] la_oen;\n" \
+ "// ---- GPIO pins ----\n" \
+ "wire [`MPRJ_IO_PADS-1:0] io_in;\n" \
+ "wire [`MPRJ_IO_PADS-1:0] io_out;\n" \
+ "wire [`MPRJ_IO_PADS-1:0] io_oeb;\n" \
+ "// ---- Analog I/O pins ----\n" \
+ "wire [`MPRJ_IO_PADS-8:0] analog_io;\n" \
+ "// ---- User clock pin ----\n" \
+ "wire [0:0] user_clock2;\n"
# TODO: This is a temporary fix for the flattened analog io port
# SHOULD BE REMOVED ABOUT UPDATED WRAPPER
for ipin in range(31):
line2output += "wire [0:0] analog_io_" + str(ipin) + "_;\n"
# Skip all the lines about FPGA instanciation
if (curr_line == "\tfpga_core FPGA_DUT (\n"):
skip_current_line = True
fpga_instance_lines = True
# When FPGA instance are skipped, add the wrapper instance
if ((True == fpga_instance_lines) and (curr_line.endswith(");\n"))):
skip_current_line = False
fpga_instance_lines = False
line2output = "\tfpga_top FPGA_DUT(\n" \
+ "\t\t\t.vdda1(vdda1),\n" \
+ "\t\t\t.vdda2(vdda2),\n" \
+ "\t\t\t.vssa1(vssa1),\n" \
+ "\t\t\t.vssa2(vssa2),\n" \
+ "\t\t\t.vccd1(vccd1),\n" \
+ "\t\t\t.vccd2(vccd2),\n" \
+ "\t\t\t.vssd1(vssd1),\n" \
+ "\t\t\t.vssd2(vssd2),\n" \
+ "\t\t\t.wb_clk_i(wb_clk_i),\n" \
+ "\t\t\t.wb_rst_i(wb_rst_i),\n" \
+ "\t\t\t.wbs_stb_i(wbs_stb_i),\n" \
+ "\t\t\t.wbs_we_i(wbs_we_i),\n" \
+ "\t\t\t.wbs_cyc_i(wbs_cyc_i),\n" \
+ "\t\t\t.wbs_sel_i(wbs_sel_i),\n" \
+ "\t\t\t.wbs_dat_i(wbs_dat_i),\n" \
+ "\t\t\t.wbs_adr_i(wbs_adr_i),\n" \
+ "\t\t\t.wbs_ack_o(wbs_ack_o),\n" \
+ "\t\t\t.wbs_dat_o(wbs_dat_o),\n" \
+ "\t\t\t.la_data_in(la_data_in),\n" \
+ "\t\t\t.la_data_out(la_data_out),\n" \
+ "\t\t\t.la_oen(la_oen),\n" \
+ "\t\t\t.io_in(io_in),\n" \
+ "\t\t\t.io_out(io_out),\n" \
+ "\t\t\t.io_oeb(io_oeb),\n" \
#+ "\t\t\t.analog_io(analog_io),\n" \
#+ "\t\t\t);\n";
# TODO: This is a temporary fix for the flattened analog io port
# SHOULD BE REMOVED ABOUT UPDATED WRAPPER
for ipin in range(31):
line2output += ".analog_io_" + str(ipin) + "_(analog_io_" + str(ipin) + "_),\n"
line2output += "\t\t\t.user_clock2(user_clock2)\n"
line2output += "\t\t\t);\n";
# Wire the stimuli according to pin assignment
write_testbench_wrapper_connection(tb_file, pin_data, 25)
# Correct the path in signal initialization
if (re.search(r'\$deposit\(FPGA_DUT', curr_line)):
line2output = re.sub(r'\$deposit\(FPGA_DUT', '$deposit(FPGA_DUT.fpga_core_uut', curr_line)
if (False == skip_current_line):
tb_file.write(line2output)
tb_file.close()
logging.info("Done")

BIN
TESTBENCH/common/scff_test_post_pnr.v (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -1,30 +0,0 @@
//-------------------------------------------
// FPGA Synthesizable Verilog Netlist
// Description: Netlist Summary
// Author: Xifan TANG
// Organization: University of Utah
// Date: Fri Nov 20 15:48:46 2020
//-------------------------------------------
//----- Time scale -----
`timescale 1ns / 1ps
// ------ Include simulation defines -----
`include "/research/ece/lnis/USERS/tang/github/skywater-openfpga/TESTBENCH/k4_N8_caravel_io_FPGA_12x12_fdhd_cc/prepnr/verilog_testbench/define_simulation.v"
`include "/research/ece/lnis/USERS/tang/github/skywater-openfpga/HDL/common/skywater_function_verification.v"
// ------ Include Skywater cell netlists -----
`include "/research/ece/lnis/USERS/tang/github/skywater-openfpga/TESTBENCH/common/post_pnr_fpga_cells.v"
// ------ Include fabric top-level netlists -----
//`include "/research/ece/lnis/USERS/tang/github/skywater-openfpga/FPGA1212_FC_HD_SKY_PNR/fpga_core/fpga_core_icv_in_design.pt.v"
`include "/research/ece/lnis/USERS/DARPA_ERI/Tapeout/Nov2020_Skywater/FPGA1212_FLAT_HD_SKY_PNR/fpga_top/fpga_top_icv_in_design.pt.v"
`ifdef AUTOCHECKED_SIMULATION
`include "bin2bcd_output_verilog.v"
`endif
`ifdef AUTOCHECKED_SIMULATION
`include "/research/ece/lnis/USERS/tang/github/skywater-openfpga/TESTBENCH/k4_N8_caravel_io_FPGA_12x12_fdhd_cc/postpnr/verilog_testbench/bin2bcd_post_pnr_autocheck_top_tb.v"
`endif

View File

@ -1,29 +0,0 @@
//-------------------------------------------
// FPGA Synthesizable Verilog Netlist
// Description: Netlist Summary
// Author: Xifan TANG
// Organization: University of Utah
// Date: Fri Nov 20 15:48:45 2020
//-------------------------------------------
//----- Time scale -----
`timescale 1ns / 1ps
// ------ Include simulation defines -----
`include "/research/ece/lnis/USERS/tang/github/skywater-openfpga/TESTBENCH/k4_N8_caravel_io_FPGA_12x12_fdhd_cc/prepnr/verilog_testbench/define_simulation.v"
`include "/research/ece/lnis/USERS/tang/github/skywater-openfpga/HDL/common/skywater_function_verification.v"
// ------ Include Skywater cell netlists -----
`include "/research/ece/lnis/USERS/tang/github/skywater-openfpga/TESTBENCH/common/post_pnr_fpga_cells.v"
// ------ Include fabric top-level netlists -----
//`include "/research/ece/lnis/USERS/tang/github/skywater-openfpga/FPGA1212_FC_HD_SKY_PNR/fpga_core/fpga_core_icv_in_design.pt.v"
`include "/research/ece/lnis/USERS/DARPA_ERI/Tapeout/Nov2020_Skywater/FPGA1212_FLAT_HD_SKY_PNR/fpga_top/fpga_top_icv_in_design.pt.v"
`ifdef AUTOCHECKED_SIMULATION
`include "counter_output_verilog.v"
`endif
`ifdef AUTOCHECKED_SIMULATION
`include "/research/ece/lnis/USERS/tang/github/skywater-openfpga/TESTBENCH/k4_N8_caravel_io_FPGA_12x12_fdhd_cc/postpnr/verilog_testbench/counter_post_pnr_autocheck_top_tb.v"
`endif

View File

@ -1,30 +0,0 @@
//-------------------------------------------
// FPGA Synthesizable Verilog Netlist
// Description: Netlist Summary
// Author: Xifan TANG
// Organization: University of Utah
// Date: Fri Nov 20 15:49:05 2020
//-------------------------------------------
//----- Time scale -----
`timescale 1ns / 1ps
// ------ Include simulation defines -----
`include "/research/ece/lnis/USERS/tang/github/skywater-openfpga/TESTBENCH/k4_N8_caravel_io_FPGA_12x12_fdhd_cc/prepnr/verilog_testbench/define_simulation.v"
`include "/research/ece/lnis/USERS/tang/github/skywater-openfpga/HDL/common/skywater_function_verification.v"
// ------ Include Skywater cell netlists -----
`include "/research/ece/lnis/USERS/tang/github/skywater-openfpga/TESTBENCH/common/post_pnr_fpga_cells.v"
// ------ Include fabric top-level netlists -----
//`include "/research/ece/lnis/USERS/tang/github/skywater-openfpga/FPGA1212_FC_HD_SKY_PNR/fpga_core/fpga_core_icv_in_design.pt.v"
`include "/research/ece/lnis/USERS/DARPA_ERI/Tapeout/Nov2020_Skywater/FPGA1212_FLAT_HD_SKY_PNR/fpga_top/fpga_top_icv_in_design.pt.v"
`ifdef AUTOCHECKED_SIMULATION
`include "top_module_output_verilog.v"
`endif
`ifdef AUTOCHECKED_SIMULATION
`include "/research/ece/lnis/USERS/tang/github/skywater-openfpga/TESTBENCH/k4_N8_caravel_io_FPGA_12x12_fdhd_cc/postpnr/verilog_testbench/top_module_post_pnr_autocheck_top_tb.v"
`endif