├── .gitignore ├── .gitmodules ├── COPYING ├── README.md ├── devices.json ├── docs ├── bels │ ├── OXIDE_COMB.md │ ├── OXIDE_FF.md │ └── SEIO33_CORE.md ├── first_notes.md ├── general │ └── bitstream.md └── tiles │ ├── CIB.md │ ├── CIB_LR.md │ ├── PLC.md │ └── cib_common.md ├── environment.sh ├── examples ├── .gitignore ├── blinky_evn │ ├── Makefile │ ├── blinky.v │ └── evn.pdc ├── blinky_vip │ ├── Makefile │ ├── blinky.v │ └── vip.pdc ├── blinky_vvml │ ├── Makefile │ ├── blinky.v │ └── vvml.pdc ├── common.mk └── lram_evn │ ├── Makefile │ ├── blinky.v │ └── evn.pdc ├── fuzzers ├── .gitignore ├── LFCPNX │ ├── 001-plc-routing │ │ └── fuzzer.py │ ├── 002-cib-routing │ │ └── fuzzer.py │ ├── 010-lut-init │ │ ├── fuzzer.py │ │ └── lut.v │ ├── 011-reg-config │ │ ├── ff.v │ │ └── fuzzer.py │ ├── 012-plc-modes │ │ ├── fuzzer.py │ │ └── slice.v │ ├── 020-plc_tap │ │ └── fuzzer.py │ ├── 021-cmux │ │ └── fuzzer.py │ ├── 022-midmux │ │ └── fuzzer.py │ ├── 023-trunk-spine │ │ └── fuzzer.py │ ├── 030-io_route │ │ └── fuzzer.py │ ├── 110-global-structure │ │ └── fuzzer.py │ └── shared │ │ ├── empty_100.v │ │ └── route_100.v └── LIFCL │ ├── 001-plc-routing │ └── fuzzer.py │ ├── 002-cib-routing │ └── fuzzer.py │ ├── 010-lut-init │ ├── fuzzer.py │ └── lut.v │ ├── 011-reg-config │ ├── ff.v │ └── fuzzer.py │ ├── 012-plc-modes │ ├── fuzzer.py │ └── slice.v │ ├── 020-plc_tap │ └── fuzzer.py │ ├── 021-cmux │ └── fuzzer.py │ ├── 022-midmux │ └── fuzzer.py │ ├── 023-trunk-spine │ └── fuzzer.py │ ├── 024-dcc-dcs │ ├── dcc.v │ ├── dcs.v │ └── fuzzer.py │ ├── 030-io_route │ └── fuzzer.py │ ├── 031-io_mode │ ├── fuzzer.py │ ├── iob_17.v │ └── iob_40.v │ ├── 032-hsio_mode │ ├── fuzzer.py │ └── iob_40.v │ ├── 035-bankref │ └── fuzzer.py │ ├── 039-copy-io │ └── fuzzer.py │ ├── 040-speed │ ├── fuzzer.py │ └── speed_40.v │ ├── 050-cib-special │ ├── cib_iomux_40.v │ └── fuzzer.py │ ├── 060-ebr-config │ ├── ebr.v │ └── fuzzer.py │ ├── 061-ebr-routing │ └── fuzzer.py │ ├── 062-lram-config │ ├── fuzzer.py │ └── lram.v │ ├── 063-lram-routing │ └── fuzzer.py │ ├── 067-copy-ebr │ └── fuzzer.py │ ├── 070-iologic_mode │ ├── fuzzer.py │ ├── iologic_17.v │ └── iologic_40.v │ ├── 071-iodelay │ ├── fuzzer.py │ └── iodelay.v │ ├── 080-dsp-config │ ├── dsp.v │ └── fuzzer.py │ ├── 081-dsp-routing │ └── fuzzer.py │ ├── 090-sysconfig │ └── fuzzer.py │ ├── 091-osc │ ├── fuzzer.py │ ├── osc.v │ └── osc_17.v │ ├── 092-gsr │ ├── fuzzer.py │ └── gsr.v │ ├── 100-ip-base │ ├── fuzzer.py │ └── ip.v │ ├── 110-global-structure │ └── fuzzer.py │ ├── 120-pll-routing │ └── fuzzer.py │ ├── 121-pll-ipconfig │ ├── fuzzer.py │ ├── pll.v │ └── pll_2.v │ ├── 122-pll-config │ ├── fuzzer.py │ ├── pll.v │ └── pll_17.v │ ├── 130-config-ip-routing │ └── fuzzer.py │ ├── 131-config-ip │ ├── fuzzer.py │ └── ip.v │ ├── 140-bram-init │ ├── ebr.v │ └── fuzzer.py │ ├── 141-lram-init │ ├── fuzzer.py │ └── lram.v │ ├── 150-eclkroute │ └── fuzzer.py │ ├── 151-eclkprim │ ├── eclkprim.v │ └── fuzzer.py │ ├── 152-dqsroute │ └── fuzzer.py │ ├── 153-dqsbuf │ ├── dqsbuf.v │ └── fuzzer.py │ ├── 154-ddrll │ ├── ddrdll.v │ └── fuzzer.py │ ├── 155-dlldel │ ├── dlldel.v │ └── fuzzer.py │ ├── 160-hard-ip-routing │ └── fuzzer.py │ ├── 161-dphy-ipconfig │ ├── dphy.v │ └── fuzzer.py │ ├── 162-pcie-ipconfig │ ├── fuzzer.py │ └── pcie.v │ ├── 900-always-on │ └── fuzzer.py │ └── shared │ ├── empty_17.v │ ├── empty_40.v │ ├── empty_presyn_40.v │ ├── route_17.v │ └── route_40.v ├── libprjoxide ├── Cargo.toml ├── prjoxide │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── bba │ │ ├── bbafile.rs │ │ ├── bbastruct.rs │ │ ├── idstring.rs │ │ ├── idxset.rs │ │ ├── tileloc.rs │ │ ├── tiletype.rs │ │ └── timing.rs │ │ ├── bels.rs │ │ ├── bin │ │ └── prjoxide.rs │ │ ├── bitstream.rs │ │ ├── chip.rs │ │ ├── database.rs │ │ ├── database_html.rs │ │ ├── docs.rs │ │ ├── fasmparse.rs │ │ ├── fuzz.rs │ │ ├── interchange_gen │ │ ├── bel_pin_map.rs │ │ ├── routing_graph.rs │ │ └── writer.rs │ │ ├── ipfuzz.rs │ │ ├── lib.rs │ │ ├── nodecheck.rs │ │ ├── pip_classes.rs │ │ ├── schema.rs │ │ ├── sites.rs │ │ └── wires.rs └── pyprjoxide │ ├── Cargo.toml │ └── src │ └── lib.rs ├── minitests ├── .gitignore ├── interchange │ ├── archcheck.sh │ └── nexus_device_config.yaml ├── pcie │ ├── coef5_one.v │ └── coef5_zero.v └── simple │ ├── io.v │ └── wire.v ├── radiant.sh ├── radiant_cmd.sh ├── timing ├── .gitignore ├── fuzzers │ └── LIFCL │ │ ├── 01-dff │ │ ├── Makefile │ │ └── gen_dff.py │ │ ├── 02-ram │ │ ├── Makefile │ │ └── gen_ram.py │ │ ├── 03-picorv32 │ │ ├── Makefile │ │ └── gen_picorv32.py │ │ ├── 04-dsp │ │ ├── Makefile │ │ └── gen_dsp.py │ │ ├── 05-clock │ │ ├── Makefile │ │ └── gen_clk.py │ │ ├── 06-carry │ │ ├── Makefile │ │ └── gen_carry.py │ │ ├── 07-lutram │ │ ├── Makefile │ │ └── gen_lutram.py │ │ └── 08-io │ │ ├── Makefile │ │ └── gen_io.py ├── tools │ ├── fuzzer.mk │ ├── pickle_sdf.py │ ├── postprocess.mk │ ├── run-fuzzers.mk │ ├── verilog_to_json.sh │ └── yosysify_verilog.py └── util │ ├── extract_cell_timings.py │ ├── extract_route.py │ ├── parse_sdf.py │ ├── solve_interconnect.py │ └── timing_config.py ├── tools ├── .gitignore ├── bitstreamcache.py ├── extract_tilegrid.py ├── fixup_io_tilegrid.py ├── get_device_tilegrid.sh ├── html_all.py ├── html_tilebits.py ├── html_tilegrid.py ├── parse_pins.py ├── test_sites.py └── tilegrid_all.py └── util ├── common ├── __init__.py ├── database.py ├── lapie.py ├── radiant.py └── tiles.py └── fuzz ├── fuzzconfig.py ├── fuzzloops.py ├── get_params.py ├── interconnect.py └── nonrouting.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | *.o 3 | *.bit 4 | *.bin 5 | *.config 6 | *.dump 7 | *.rbt 8 | *.sdf 9 | *.vo 10 | /user_environment.sh 11 | libprjoxide/target 12 | Cargo.lock 13 | .bitstreamcache/ 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "database"] 2 | path = database 3 | url = https://github.com/gatecat/prjoxide-db 4 | [submodule "3rdparty/fpga-interchange-schema"] 5 | path = 3rdparty/fpga-interchange-schema 6 | url = https://github.com/SymbiFlow/fpga-interchange-schema 7 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2020-21 gatecat 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Project Oxide - documenting Lattice's 28nm "Nexus" FPGA parts 2 | 3 | ## Current Status 4 | 5 | A framework is in place to parse bitstreams and fuzz bitstream changes. Currently the logic tile (PLC) config and interconnect; basic IO and IOLOGIC config; EBR config; global routing ; DSP and PLL config have been fuzzed. Remaining work includes finishing IO, PCIe and SGMII fuzzing. 6 | 7 | prjoxide may also need to be updated to support the production silicon. Most of the current testing has been done with LIFCL-40 devices, with limited testing on the LIFCL-17. There has also been some early investigations into Certus-Pro NX support. 8 | 9 | prjoxide is also aiming to support the [SymbiFlow FPGA interchange format](https://github.com/SymbiFlow/fpga-interchange-schema) and includes support for generating (currently incomplete) device resource data. This is not yet a working end to end flow and currently the direct nextpnr based flow described below should be used. 10 | 11 | ## Links 12 | 13 | - [HTML documentation](https://gatecat.github.io/prjoxide-html/) 14 | 15 | ## Getting Started - Complete Flow 16 | 17 | ### Prerequisites 18 | 19 | - Install the nextpnr and Yosys prerequisites (example for Ubuntu): 20 | ``` 21 | sudo apt-get install build-essential clang bison flex libreadline-dev \ 22 | gawk tcl-dev libffi-dev git mercurial graphviz \ 23 | xdot pkg-config python python3 libftdi-dev \ 24 | qt5-default python3-dev libboost-all-dev cmake libeigen3-dev 25 | ``` 26 | - Build and install latest git [Yosys](https://github.com/YosysHQ/yosys) 27 | - Install a Rust toolchain using [rustup](https://rustup.rs/) 28 | - Build and install [ecpprog](https://github.com/gregdavill/ecpprog) 29 | 30 | ### Building the prjoxide tool 31 | 32 | Clone prjoxide recursively, so you get a copy of the database too: 33 | 34 | git clone --recursive https://github.com/gatecat/prjoxide 35 | 36 | A single command line tool `prjoxide` supports subcommands for bitstream packing and unpacking as well as BBA generation for the nextpnr build process. To build and install it, run: 37 | 38 | cd libprjoxide 39 | cargo install --path prjoxide 40 | 41 | This will, by default, install to `~/.cargo/bin` which you may need to add to your `PATH`. You can use `--root` or the `CARGO_INSTALL_ROOT` environment variable to override the installation root. 42 | 43 | This executable contains all data embedded in it; so it can be freely moved to another location on your system if required. Consequently, however, you will need to rebuild prjoxide after a database update. 44 | 45 | ### Building nextpnr-nexus 46 | 47 | Clone nextpnr: 48 | 49 | git clone --recursive https://github.com/YosysHQ/nextpnr 50 | cd nextpnr 51 | 52 | Build nextpnr-nexus, making sure to point it to the correct path for the prjoxide tool: 53 | 54 | cmake -DARCH=nexus -DOXIDE_INSTALL_PREFIX=$HOME/.cargo . 55 | make -j8 56 | 57 | ### Running the example designs 58 | 59 | There are currently examples for the CrossLink-NX EVN and VIP boards in prjoxide. 60 | 61 | cd prjoxide/examples/blinky_evn 62 | make prog 63 | 64 | For more advanced test designs; [LiteX](https://github.com/enjoy-digital/litex) supports the CrossLink-NX device using prjoxide. For example: 65 | 66 | python litex-boards/litex_boards/targets/crosslink_nx_vip.py --toolchain oxide --nexus-es-device --build 67 | 68 | ## Getting Started - Developers 69 | 70 | The main framework (libprjoxide) is written in Rust. As the development side includes Python bindings using pyo3 for fuzzers and miscellaneous utilities, nightly Rust will be required. It is strongly recommended to use [rustup](https://rustup.rs/) to install this. 71 | 72 | Once installed, run the following to build libprjoxide: 73 | 74 | cd libprjoxide 75 | cargo build --release 76 | 77 | To run the Python scripts, add all of the needed libraries to `PYTHONPATH` using: 78 | 79 | source environment.sh 80 | 81 | If running fuzzers, you might also need to adjust the path to Radiant in `user_environment.sh` (which will be created by the above script). 82 | -------------------------------------------------------------------------------- /devices.json: -------------------------------------------------------------------------------- 1 | { 2 | "families": { 3 | "LIFCL": { 4 | "devices": { 5 | "LIFCL-40": { 6 | "packages": ["QFN72", "csfBGA289", "caBGA400"], 7 | "frames": 9172, 8 | "bits_per_frame": 662, 9 | "pad_bits_after_frame": 0, 10 | "pad_bits_before_frame": 4, 11 | "frame_ecc_bits": 14, 12 | "max_row" : 56, 13 | "max_col" : 87, 14 | "col_bias" : 0, 15 | "fuzz": true, 16 | "variants": { 17 | "": {"idcode": 286199875}, 18 | "ES": {"idcode": 17764419} 19 | } 20 | }, 21 | "LFD2NX-40": { 22 | "packages": ["caBGA256"], 23 | "idcode": 823070787, 24 | "frames": 9172, 25 | "bits_per_frame": 662, 26 | "pad_bits_after_frame": 0, 27 | "pad_bits_before_frame": 4, 28 | "frame_ecc_bits": 14, 29 | "max_row" : 56, 30 | "max_col" : 87, 31 | "col_bias" : 0, 32 | "fuzz": true, 33 | "variants": { 34 | "": {"idcode": 823070787} 35 | } 36 | }, 37 | "LIFCL-17": { 38 | "packages": ["QFN72", "csfBGA121", "caBGA256"], 39 | "idcode": 17760323, 40 | "frames": 7900, 41 | "bits_per_frame": 338, 42 | "pad_bits_after_frame": 0, 43 | "pad_bits_before_frame": 0, 44 | "frame_ecc_bits": 14, 45 | "max_row" : 29, 46 | "max_col" : 75, 47 | "col_bias" : 0, 48 | "fuzz": true, 49 | "variants": { 50 | "": {"idcode": 17760323} 51 | } 52 | } 53 | } 54 | }, 55 | "LFCPNX": { 56 | "devices": { 57 | "LFCPNX-100": { 58 | "packages": ["ASG256", "CBG256", "BBG484", "BFG484", "LFG672"], 59 | "idcode": 17776707, 60 | "frames": 16822, 61 | "bits_per_frame": 878, 62 | "pad_bits_after_frame": 0, 63 | "pad_bits_before_frame": 4, 64 | "frame_ecc_bits": 14, 65 | "max_row" : 74, 66 | "max_col" : 159, 67 | "col_bias" : 0, 68 | "fuzz": true, 69 | "variants": { 70 | "": {"idcode": 17776707} 71 | } 72 | } 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /docs/bels/OXIDE_COMB.md: -------------------------------------------------------------------------------- 1 | **OXIDE_COMB** bels are half the combinational part of a **SLICE**. They implement 2 | a LUT4 and some surrounding logic. They can be used as a LUT4; LUT4 with carry (½CCU2); 3 | LUT4 with MUX2 ("0" half bels only). Bels in **SLICEA** and **SLICEB** can also be 4 | used as a 16-bit distributed RAM. 5 | -------------------------------------------------------------------------------- /docs/bels/OXIDE_FF.md: -------------------------------------------------------------------------------- 1 | **OXIDE_FF** bels are half the sequential part of a **SLICE**. They implement 2 | a single flip flop. 3 | -------------------------------------------------------------------------------- /docs/bels/SEIO33_CORE.md: -------------------------------------------------------------------------------- 1 | **SEIO33_CORE** bels implement the buffer side of the wide range (3.3V capable) IOs. Note that the logical parts of these pins (registers, delay and DDR) are implemented using the **SIOLOGIC** bel. These pins can be used as single ended input/inout/output; or two outputs can be used in "pseudo differential" mode - differential input is not possible. 2 | -------------------------------------------------------------------------------- /docs/first_notes.md: -------------------------------------------------------------------------------- 1 | # First LIFCL-40 notes 2 | - preamble, and first commands same as ECP5 3 | - IDCODE 0x010f1043 4 | - Seems to use frame addresses to write frames out of order, 5 | first writes some frames at 0x8000, rather than all at once like ECP5? 6 | - new 0x56 command - "Power Control Frame" according to programming file utility 7 | - 16-bit frame CRC is BUYPASS, same as ECP5 8 | - Documentation mentions "14 parity bits" per frame. These seem to be before 16-bit frame CRC. Unsure if actually checked or not 9 | - Hard IP like PCIe configured outside of main bitstream 10 | `F6 000000 address` writes a 32-bit address 11 | `72 D00001 data CRC` writes a 32-bit data word with 16-bit CRC 12 | -------------------------------------------------------------------------------- /docs/general/bitstream.md: -------------------------------------------------------------------------------- 1 | # Bitstream Format 2 | 3 | The format of the bitstream has many similarities to ECP5 and previous Lattice devices. It is still a command-based format with many similar commands, albeit with changes for some of the new features. 4 | 5 | ## "Magic" and comments 6 | 7 | The first four bytes of the bitstream are `0x4C 0x53 0x43 0x43` (**LSCC**, i.e. Lattice SemiConductor Corporation). *(TODO: test - this may be needed for SPI flash boot to work.)* 8 | 9 | This the follows an option comment section, which is bounded by `0xFF 0x00` and `0x00 0xFF`. It contains several null-terminated strings used by tools like Radiant Programmer to determine the device, package, build date/time etc. It is not parsed by the chip. 10 | 11 | ## Preamble 12 | 13 | The four bytes marking the start of an actual bitstream are `0xFF 0xFF 0xBD 0xB3`, the same as the ECP5. 14 | 15 | ## Commands 16 | 17 | All commands (except the `0xFF` dummy command) are followed by three "parameter" bytes and then zero or more bytes of payload. All multi-byte integers are big endian. 18 | 19 | - **LSC_RESET_CRC** (`0x3B`): resets the internal CRC16 counter 20 | - **VERIFY_ID** (`0xE2`): after th 3 param bytes; followed by the 32-bit device IDCODE. Config ends if IDCODE does not match 21 | - **LSC_PROG_CNTRL0** (`0x22`): sets the value of control register 0, which contains various settings such as config clock frequency and multiboot mode 22 | - **LSC_INIT_ADDRESS** (`0x46`): sets the frame address counter to 0 23 | - **LSC_WRITE_ADDRESS** (`0xB4`): sets the frame address counter to the 32-bit payload 24 | - **LSC_PROG_INCR_RTI** (`0x82`): programs configuration frames at incrementing addresses. First param byte contains general settings and next two contain 16-bit frame count. See **Config Frames** section for more info 25 | - **ISC_PROGRAM_USERCODE** (`0xC2`): sets the usercode to the 32-bit payload 26 | - **LSC_BUS_ADDRESS** (`0xF6`): sets the IP/RAM bus address to the 32-bit payload 27 | - **LSC_BUS_WRITE** (`0x72`): writes to the IP/RAM bus at incrementing addresses. First param byte contains general settings and next two contain 16-bit word count 28 | - **ISC_PROGRAM_DONE** (`0x5E`): ends configuration and starts FPGA fabric running 29 | - **LSC_POWER_CTRL** (`0x56`): third param byte configures internal power switches (detail unknown) 30 | 31 | ## Config Frames 32 | 33 | Config frames are written in three chunks (numbers for LIFCL): 34 | 35 | - 32 frames at address 0x8000 set up left and right side IO/IP 36 | - 9116 at address 0x0000 set up general fabric (the vast majority of the device) 37 | - 24 frames at address 0x8020 set up global clocking "tap"s 38 | 39 | It is believed this ordering is for the "early IO release" feature. 40 | 41 | The final 14 bits of each config frame are used for an error correcting code ("parity"). 42 | This uses the typical CRC algorithm with polynomial 0x202D. 43 | 44 | The error correcting code does not include LUT RAM initialisation bits, 45 | these are masked with zeroes, because they can change at runtime. 46 | 47 | Following each frame is the standard packet CRC16, which uses the common 0x8005 polynomial. 48 | 49 | ## IP/RAM bus 50 | 51 | IP and RAM configuration and initialisation is not done using general configuration frames but using a special bus, which for IP mirrors the LMMI bus exposed to fabric. 52 | 53 | The first byte of the 32-bit bus address is used to determine the destination type, and the word size for **LSC_BUS_WRITE**: 54 | 55 | - **0x0** is for non-PCIe IP cores (PLL, DPHY, etc) config. Words are 8 bits. 56 | - **0x2** is for BRAM and LRAM initialisation. Words are 40 bits. 57 | - **0x3** is for PCIe IP config. Words are 32 bits 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /docs/tiles/CIB.md: -------------------------------------------------------------------------------- 1 | .include cib_common.md 2 | -------------------------------------------------------------------------------- /docs/tiles/CIB_LR.md: -------------------------------------------------------------------------------- 1 | .include cib_common.md 2 | -------------------------------------------------------------------------------- /docs/tiles/PLC.md: -------------------------------------------------------------------------------- 1 | **PLC** tiles form the main fabric of the FPGA, containing both general interconnect and four logic slices. Interconnect connects between horizontal and vertical routing (H/V 0/1/2/6 wires); and slice inputs/outputs. Each slice contains two LUT4s, two FFs and a MUX2. All slices can also be used as carry logic (CCU2), and the bottom three slices can be combined to a 16x4 LUT RAM. 2 | -------------------------------------------------------------------------------- /docs/tiles/cib_common.md: -------------------------------------------------------------------------------- 1 | CIB tiles provide interconnect between general routing and special functions (such as IO, block RAM, DSPs etc). Outputs to the special functions are named as if they are LUT or FF inputs (`JCIBMUXOUT[ABCD][0-7]`, `J(CLK|CE|LSR)[0-1]`), inputs from special function outputs back to general routing are named as if they are LUT or FF outputs (`J[FQ][0-7]`). 2 | -------------------------------------------------------------------------------- /environment.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Set up PYTHONPATH and other needed environment variables 4 | # This script will also source user_environment.sh where you can specify 5 | # overrides if required for your system 6 | 7 | if [ "$0" = "$_" ]; then 8 | echo This script is intended to be invoked using \"source environment.sh\" 9 | echo Calling it as a standalone script will have no effect. 10 | exit 1 11 | fi 12 | 13 | SCRIPT_PATH=$(readlink -f "${BASH_SOURCE:-$0}") 14 | SCRIPT_DIR=$(dirname "$SCRIPT_PATH") 15 | PYTHONLIBS_DIR="${SCRIPT_DIR}/util:${SCRIPT_DIR}/util/common:${SCRIPT_DIR}/util/fuzz:${SCRIPT_DIR}/timing/util:${SCRIPT_DIR}/libprjoxide/target/${TARGET:-release}" 16 | export PYTHONPATH="${PYTHONLIBS_DIR}:${PYTHONPATH}" 17 | export RADIANTDIR=$HOME/lscc/radiant/3.1 18 | USER_ENV="${SCRIPT_DIR}/user_environment.sh" 19 | 20 | if [ ! -f "$USER_ENV" ]; then 21 | cat > "${USER_ENV}" << EOT 22 | #!/usr/bin/env bash 23 | # This file allows you to set up custom settings that are applied when you 24 | # run `source environment.sh` 25 | 26 | # Changes to this file will be automatically ignored by Git 27 | 28 | # export RADIANTDIR=$HOME/lscc/radiant/2.0 29 | EOT 30 | fi 31 | 32 | source "$USER_ENV" 33 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | *.json 2 | *.fasm 3 | *.bit 4 | *.log 5 | -------------------------------------------------------------------------------- /examples/blinky_evn/Makefile: -------------------------------------------------------------------------------- 1 | PROJ=blinky 2 | DEVICE=LIFCL-40-9BG400CES 3 | PDC=evn.pdc 4 | 5 | include ../common.mk 6 | 7 | -------------------------------------------------------------------------------- /examples/blinky_evn/blinky.v: -------------------------------------------------------------------------------- 1 | // Simple blinky example for the LIFCL-40-EVN board 2 | 3 | module top(input gsrn, output [13:0] led); 4 | wire clk; 5 | 6 | // Internal oscillator 7 | OSC_CORE #( 8 | .HF_CLK_DIV("16") 9 | ) osc_i ( 10 | .HFOUTEN(1'b1), 11 | .HFCLKOUT(clk) 12 | ); 13 | 14 | reg [13:0] shift = 0; 15 | reg [20:0] div; 16 | reg clkdiv; 17 | reg dir = 0; 18 | 19 | always @(posedge clk) begin 20 | // Generate a slow clock 21 | {clkdiv, div} <= div + 1'b1; 22 | // Scan the LED back and forth 23 | if (clkdiv) begin 24 | if (shift[13]) 25 | dir = 1'b1; 26 | else if (shift[0]) 27 | dir = 1'b0; 28 | 29 | if (!(|shift)) 30 | shift <= 14'b1; 31 | else if (dir) 32 | shift <= {shift[0], shift[13:1]}; 33 | else 34 | shift <= {shift[12:0], shift[13]}; 35 | end 36 | if (!gsrn) begin 37 | // Reset 38 | dir <= 1'b0; 39 | shift <= 14'b0; 40 | div <= 21'b0; 41 | clkdiv <= 1'b0; 42 | end 43 | end 44 | 45 | // LEDs are active low 46 | assign led = ~shift; 47 | 48 | endmodule 49 | -------------------------------------------------------------------------------- /examples/blinky_evn/evn.pdc: -------------------------------------------------------------------------------- 1 | ldc_set_location -site {E17} [get_ports {led[0]}] 2 | ldc_set_location -site {F13} [get_ports {led[1]}] 3 | ldc_set_location -site {G13} [get_ports {led[2]}] 4 | ldc_set_location -site {F14} [get_ports {led[3]}] 5 | ldc_set_location -site {L16} [get_ports {led[4]}] 6 | ldc_set_location -site {L15} [get_ports {led[5]}] 7 | ldc_set_location -site {L20} [get_ports {led[6]}] 8 | ldc_set_location -site {L19} [get_ports {led[7]}] 9 | ldc_set_location -site {R17} [get_ports {led[8]}] 10 | ldc_set_location -site {R18} [get_ports {led[9]}] 11 | ldc_set_location -site {U20} [get_ports {led[10]}] 12 | ldc_set_location -site {T20} [get_ports {led[11]}] 13 | ldc_set_location -site {W20} [get_ports {led[12]}] 14 | ldc_set_location -site {V20} [get_ports {led[13]}] 15 | ldc_set_location -site {G19} [get_ports gsrn] 16 | 17 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[0]}] 18 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[1]}] 19 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[2]}] 20 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[3]}] 21 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[4]}] 22 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[5]}] 23 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[6]}] 24 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[7]}] 25 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[8]}] 26 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[9]}] 27 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[10]}] 28 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[11]}] 29 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[12]}] 30 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[13]}] 31 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports gsrn] 32 | -------------------------------------------------------------------------------- /examples/blinky_vip/Makefile: -------------------------------------------------------------------------------- 1 | PROJ=blinky 2 | DEVICE=LIFCL-40-9BG400CES 3 | PDC=vip.pdc 4 | 5 | include ../common.mk 6 | 7 | -------------------------------------------------------------------------------- /examples/blinky_vip/blinky.v: -------------------------------------------------------------------------------- 1 | // Simple blinky example for the LIFCL-40-EVN board 2 | 3 | module top(input gsrn, output [3:0] led); 4 | wire clk; 5 | 6 | // Internal oscillator 7 | OSC_CORE #( 8 | .HF_CLK_DIV("16") 9 | ) osc_i ( 10 | .HFOUTEN(1'b1), 11 | .HFCLKOUT(clk) 12 | ); 13 | 14 | reg [3:0] shift = 0; 15 | reg [20:0] div; 16 | reg clkdiv; 17 | reg dir = 0; 18 | 19 | always @(posedge clk) begin 20 | // Generate a slow clock 21 | {clkdiv, div} <= div + 1'b1; 22 | // Scan the LED back and forth 23 | if (clkdiv) begin 24 | if (shift[3]) 25 | dir = 1'b1; 26 | else if (shift[0]) 27 | dir = 1'b0; 28 | 29 | if (!(|shift)) 30 | shift <= 4'b1; 31 | else if (dir) 32 | shift <= {shift[0], shift[3:1]}; 33 | else 34 | shift <= {shift[2:0], shift[3]}; 35 | end 36 | if (!gsrn) begin 37 | // Reset 38 | dir <= 1'b0; 39 | shift <= 4'b0; 40 | div <= 21'b0; 41 | clkdiv <= 1'b0; 42 | end 43 | end 44 | 45 | // LEDs are active low 46 | assign led = ~shift; 47 | 48 | endmodule 49 | -------------------------------------------------------------------------------- /examples/blinky_vip/vip.pdc: -------------------------------------------------------------------------------- 1 | ldc_set_location -site {G14} [get_ports {led[0]}] 2 | ldc_set_location -site {G15} [get_ports {led[1]}] 3 | ldc_set_location -site {L13} [get_ports {led[2]}] 4 | ldc_set_location -site {L14} [get_ports {led[3]}] 5 | ldc_set_location -site {G13} [get_ports gsrn] 6 | 7 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[0]}] 8 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[1]}] 9 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[2]}] 10 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[3]}] 11 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports gsrn] 12 | -------------------------------------------------------------------------------- /examples/blinky_vvml/Makefile: -------------------------------------------------------------------------------- 1 | PROJ=blinky 2 | DEVICE=LIFCL-40-8MG289 3 | PDC=vvml.pdc 4 | 5 | include ../common.mk 6 | 7 | -------------------------------------------------------------------------------- /examples/blinky_vvml/blinky.v: -------------------------------------------------------------------------------- 1 | // Simple blinky example for the LIFCL-40-VVML board 2 | 3 | module top(input gsrn, output [3:0] led); 4 | wire clk; 5 | 6 | // Internal oscillator 7 | OSC_CORE #( 8 | .HF_CLK_DIV("16") 9 | ) osc_i ( 10 | .HFOUTEN(1'b1), 11 | .HFCLKOUT(clk) 12 | ); 13 | 14 | reg [3:0] shift = 0; 15 | reg [20:0] div; 16 | reg clkdiv; 17 | reg dir = 0; 18 | 19 | always @(posedge clk) begin 20 | // Generate a slow clock 21 | {clkdiv, div} <= div + 1'b1; 22 | // Scan the LED back and forth 23 | if (clkdiv) begin 24 | if (shift[3]) 25 | dir = 1'b1; 26 | else if (shift[0]) 27 | dir = 1'b0; 28 | 29 | if (!(|shift)) 30 | shift <= 4'b1; 31 | else if (dir) 32 | shift <= {shift[0], shift[3:1]}; 33 | else 34 | shift <= {shift[2:0], shift[3]}; 35 | end 36 | if (!gsrn) begin 37 | // Reset 38 | dir <= 1'b0; 39 | shift <= 4'b0; 40 | div <= 21'b0; 41 | clkdiv <= 1'b0; 42 | end 43 | end 44 | 45 | // LEDs are active low 46 | assign led = ~shift; 47 | 48 | endmodule 49 | -------------------------------------------------------------------------------- /examples/blinky_vvml/vvml.pdc: -------------------------------------------------------------------------------- 1 | ldc_set_location -site {H1} [get_ports {led[0]}] 2 | ldc_set_location -site {J1} [get_ports {led[1]}] 3 | ldc_set_location -site {H5} [get_ports {led[2]}] 4 | ldc_set_location -site {H6} [get_ports {led[3]}] 5 | ldc_set_location -site {L2} [get_ports gsrn] 6 | 7 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[0]}] 8 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[1]}] 9 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[2]}] 10 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[3]}] 11 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports gsrn] 12 | -------------------------------------------------------------------------------- /examples/common.mk: -------------------------------------------------------------------------------- 1 | # Common Makefile for Nexus examples 2 | 3 | SYNTH_ARGS=-flatten 4 | 5 | YOSYS?=yosys 6 | NEXTPNR?=nextpnr-nexus 7 | PRJOXIDE?=prjoxide 8 | ECPPROG?=ecpprog 9 | 10 | all: $(PROJ).bit 11 | 12 | $(PROJ).json: $(PROJ).v $(EXTRA_VERILOG) $(MEM_INIT_FILES) 13 | $(YOSYS) -ql $(PROJ)_syn.log -p "synth_nexus $(SYNTH_ARGS) -top top -json $(PROJ).json" $(PROJ).v $(EXTRA_VERILOG) 14 | 15 | $(PROJ).fasm: $(PROJ).json $(PDC) 16 | $(NEXTPNR) --device $(DEVICE) --pdc $(PDC) --json $(PROJ).json --fasm $(PROJ).fasm 17 | 18 | $(PROJ).bit: $(PROJ).fasm 19 | $(PRJOXIDE) pack $(PROJ).fasm $(PROJ).bit 20 | 21 | prog: $(PROJ).bit 22 | $(ECPPROG) -S $(PROJ).bit 23 | 24 | prog-flash: $(PROJ).bit 25 | $(ECPPROG) $(PROJ).bit 26 | 27 | clean: 28 | rm -f $(PROJ).json $(PROJ).fasm $(PROJ)_syn.log $(PROJ).bit 29 | 30 | .SECONDARY: 31 | .PHONY: prog prog-flash clean 32 | -------------------------------------------------------------------------------- /examples/lram_evn/Makefile: -------------------------------------------------------------------------------- 1 | PROJ=blinky 2 | DEVICE=LIFCL-40-8BG400C 3 | PDC=evn.pdc 4 | 5 | include ../common.mk 6 | 7 | -------------------------------------------------------------------------------- /examples/lram_evn/blinky.v: -------------------------------------------------------------------------------- 1 | // Simple lram + blinky example for the LIFCL-40-EVN board 2 | 3 | module top(input gsrn, clk, addr_en, wr_en, 4 | output [13:0] led); 5 | 6 | (* ram_style="huge" *) reg [15:0] ram [0:1023]; // or use (* lram *) 7 | reg [15:0] rd_lram; 8 | 9 | reg [13:0] shift = 0; 10 | reg [20:0] div; 11 | reg clkdiv; 12 | reg dir = 0; 13 | reg [9:0] addr; 14 | 15 | always @(posedge clk) begin 16 | // Generate a slow clock 17 | {clkdiv, div} <= div + 1'b1; 18 | // Scan the LED back and forth 19 | if (clkdiv) begin 20 | if (shift[13]) 21 | dir = 1'b1; 22 | else if (shift[0]) 23 | dir = 1'b0; 24 | 25 | if (!(|shift)) 26 | shift <= 14'b1; 27 | else if (dir) 28 | shift <= {shift[0], shift[13:1]}; 29 | else 30 | shift <= {shift[12:0], shift[13]}; 31 | 32 | if (~wr_en) begin // SW 3 (default high, low when pressed) 33 | rd_lram <= ram[addr]; 34 | end else begin 35 | ram[addr] <= {shift[13:12], shift}; 36 | end 37 | if (~addr_en) begin // SW 2 38 | addr <= addr + 1'b1; 39 | end 40 | end 41 | 42 | if (!gsrn) begin 43 | rd_lram <= 16'b0; 44 | addr <= 10'b0; 45 | dir <= 1'b0; 46 | shift <= 14'b0; 47 | div <= 21'b0; 48 | clkdiv <= 1'b0; 49 | end 50 | end 51 | 52 | // LEDs are active low 53 | assign led = ~(shift | addr | rd_lram[13:0]); 54 | 55 | endmodule 56 | -------------------------------------------------------------------------------- /examples/lram_evn/evn.pdc: -------------------------------------------------------------------------------- 1 | ldc_set_location -site {E17} [get_ports {led[0]}] 2 | ldc_set_location -site {F13} [get_ports {led[1]}] 3 | ldc_set_location -site {G13} [get_ports {led[2]}] 4 | ldc_set_location -site {F14} [get_ports {led[3]}] 5 | ldc_set_location -site {L16} [get_ports {led[4]}] 6 | ldc_set_location -site {L15} [get_ports {led[5]}] 7 | ldc_set_location -site {L20} [get_ports {led[6]}] 8 | ldc_set_location -site {L19} [get_ports {led[7]}] 9 | ldc_set_location -site {R17} [get_ports {led[8]}] 10 | ldc_set_location -site {R18} [get_ports {led[9]}] 11 | ldc_set_location -site {U20} [get_ports {led[10]}] 12 | ldc_set_location -site {T20} [get_ports {led[11]}] 13 | ldc_set_location -site {W20} [get_ports {led[12]}] 14 | ldc_set_location -site {V20} [get_ports {led[13]}] 15 | 16 | ldc_set_location -site {G19} [get_ports gsrn] 17 | ldc_set_location -site {L13} [get_ports clk] 18 | ldc_set_location -site {G14} [get_ports addr_en] 19 | ldc_set_location -site {G15} [get_ports wr_en] 20 | 21 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[0]}] 22 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[1]}] 23 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[2]}] 24 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[3]}] 25 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[4]}] 26 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[5]}] 27 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[6]}] 28 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[7]}] 29 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[8]}] 30 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[9]}] 31 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[10]}] 32 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[11]}] 33 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[12]}] 34 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {led[13]}] 35 | 36 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {gsrn}] 37 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {clk}] 38 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {addr_en}] 39 | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports {wr_en}] 40 | -------------------------------------------------------------------------------- /fuzzers/.gitignore: -------------------------------------------------------------------------------- 1 | work* 2 | -------------------------------------------------------------------------------- /fuzzers/LFCPNX/001-plc-routing/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import re 4 | 5 | cfg = FuzzConfig(job="PLCROUTE", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["R16C22:PLC"]) 6 | 7 | def main(): 8 | cfg.setup() 9 | r = 16 10 | c = 22 11 | nodes = ["R{}C{}_J*".format(r, c)] 12 | extra_sources = [] 13 | extra_sources += ["R{}C{}_H02E{:02}01".format(r, c+1, i) for i in range(8)] 14 | extra_sources += ["R{}C{}_H06E{:02}03".format(r, c+3, i) for i in range(4)] 15 | extra_sources += ["R{}C{}_V02N{:02}01".format(r-1, c, i) for i in range(8)] 16 | extra_sources += ["R{}C{}_V06N{:02}03".format(r-3, c, i) for i in range(4)] 17 | extra_sources += ["R{}C{}_V02S{:02}01".format(r+1, c, i) for i in range(8)] 18 | extra_sources += ["R{}C{}_V06S{:02}03".format(r+3, c, i) for i in range(4)] 19 | extra_sources += ["R{}C{}_H02W{:02}01".format(r, c-1, i) for i in range(8)] 20 | extra_sources += ["R{}C{}_H06W{:02}03".format(r, c-3, i) for i in range(4)] 21 | fuzz_interconnect(config=cfg, nodenames=nodes, regex=True, bidir=True, ignore_tiles=set(["TAP_PLC_R16C14:TAP_PLC"])) 22 | fuzz_interconnect(config=cfg, nodenames=extra_sources, regex=False, bidir=False, ignore_tiles=set(["TAP_PLC_R16C14:TAP_PLC"])) 23 | 24 | if __name__ == "__main__": 25 | main() 26 | -------------------------------------------------------------------------------- /fuzzers/LFCPNX/002-cib-routing/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import re 4 | 5 | configs = [ 6 | ((1, 18), FuzzConfig(job="CIBTROUTE", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R1C18:CIB_T"]), set(["TAP_CIBT_R1C14:TAP_CIBT"])), 7 | ((18, 1), FuzzConfig(job="CIBLRROUTE", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R18C1:CIB_LR"]), set(["TAP_PLC_R18C14:TAP_PLC"])), 8 | ((28, 17), FuzzConfig(job="CIBROUTE", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R28C17:CIB"]), set(["TAP_CIB_R28C14:TAP_CIB"])), 9 | ((28, 1), FuzzConfig(job="CIBLRAROUTE", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R28C1:CIB_LR_A"]), set(["TAP_CIB_R28C14:TAP_CIB"])), 10 | ] 11 | 12 | def main(): 13 | for rc, cfg, ignore in configs: 14 | cfg.setup() 15 | r, c = rc 16 | nodes = ["R{}C{}_J*".format(r, c)] 17 | extra_sources = [] 18 | extra_sources += ["R{}C{}_H02E{:02}01".format(r, c+1, i) for i in range(8)] 19 | extra_sources += ["R{}C{}_H06E{:02}03".format(r, c+3, i) for i in range(4)] 20 | if r != 1: 21 | extra_sources += ["R{}C{}_V02N{:02}01".format(r-1, c, i) for i in range(8)] 22 | extra_sources += ["R{}C{}_V06N{:02}03".format(r-3, c, i) for i in range(4)] 23 | else: 24 | extra_sources += ["R{}C{}_V02N{:02}00".format(r, c, i) for i in range(8)] 25 | extra_sources += ["R{}C{}_V06N{:02}00".format(r, c, i) for i in range(4)] 26 | extra_sources += ["R{}C{}_V02S{:02}01".format(r+1, c, i) for i in range(8)] 27 | extra_sources += ["R{}C{}_V06S{:02}03".format(r+3, c, i) for i in range(4)] 28 | if c != 1: 29 | extra_sources += ["R{}C{}_H02W{:02}01".format(r, c-1, i) for i in range(8)] 30 | extra_sources += ["R{}C{}_H06W{:02}03".format(r, c-3, i) for i in range(4)] 31 | else: 32 | extra_sources += ["R{}C{}_H02W{:02}00".format(r, c, i) for i in range(8)] 33 | extra_sources += ["R{}C{}_H06W{:02}00".format(r, c, i) for i in range(4)] 34 | def pip_filter(pip, nodes): 35 | from_wire, to_wire = pip 36 | return not ("_CORE" in from_wire or "_CORE" in to_wire or "JCIBMUXOUT" in to_wire) 37 | def fc_filter(to_wire): 38 | return "CIBMUX" in to_wire or "CIBTEST" in to_wire or to_wire.startswith("R{}C{}_J".format(r, c)) 39 | fuzz_interconnect(config=cfg, nodenames=nodes, regex=True, bidir=True, ignore_tiles=ignore, 40 | pip_predicate=pip_filter, fc_filter=fc_filter) 41 | fuzz_interconnect(config=cfg, nodenames=extra_sources, regex=False, bidir=False, ignore_tiles=ignore, 42 | pip_predicate=pip_filter, fc_filter=fc_filter) 43 | 44 | if __name__ == "__main__": 45 | main() 46 | -------------------------------------------------------------------------------- /fuzzers/LFCPNX/010-lut-init/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | import nonrouting 3 | import fuzzloops 4 | import re 5 | 6 | cfg = FuzzConfig(job="PLCINIT", device="LFCPNX-100", sv="../shared/empty_100.v", tiles=["R2C2:PLC"]) 7 | 8 | def get_lut_function(init_bits): 9 | sop_terms = [] 10 | lut_inputs = ["A", "B", "C", "D"] 11 | for i in range(16): 12 | if init_bits[i]: 13 | p_terms = [] 14 | for j in range(4): 15 | if i & (1 << j) != 0: 16 | p_terms.append(lut_inputs[j]) 17 | else: 18 | p_terms.append("~" + lut_inputs[j]) 19 | sop_terms.append("({})".format("*".join(p_terms))) 20 | if len(sop_terms) == 0: 21 | lut_func = "0" 22 | else: 23 | lut_func = "+".join(sop_terms) 24 | return lut_func 25 | 26 | 27 | def main(): 28 | cfg.setup() 29 | cfg.sv = "lut.v" 30 | 31 | def per_slice(slicen): 32 | for k in range(2): 33 | def get_substs(bits): 34 | return dict(z=slicen, k=str(k), func=get_lut_function(bits)) 35 | nonrouting.fuzz_word_setting(cfg, "SLICE{}.K{}.INIT".format(slicen, k), 16, get_substs, 36 | desc="SLICE {} LUT{} init value".format(slicen, k)) 37 | 38 | fuzzloops.parallel_foreach(["A", "B", "C", "D"], per_slice) 39 | 40 | 41 | if __name__ == "__main__": 42 | main() 43 | -------------------------------------------------------------------------------- /fuzzers/LFCPNX/010-lut-init/lut.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LFCPNX", \db:device ="LFCPNX-100", \db:package ="LFG672", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \dm:cellmodel_primitives ="K${k}=i48_3_lut", \dm:primitive ="SLICE", \dm:programming ="MODE:LOGIC F${k}:F${k} K${k}::Z=${func} ", \dm:site ="R2C2${z}" *) 7 | SLICE SLICE_I ( ); 8 | endmodule 9 | -------------------------------------------------------------------------------- /fuzzers/LFCPNX/011-reg-config/ff.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LFCPNX", \db:device ="LFCPNX-100", \db:package ="LFG672", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \xref:LOG ="q_c@0@9", \dm:arcs ="${arc}" *) 7 | wire q; 8 | 9 | (* \dm:cellmodel_primitives ="REG${k}=i48_3_lut", \dm:primitive ="SLICE", \dm:programming ="MODE:LOGIC ${mux} REG${k}:::REGSET=${regset},SEL=${sel},LSRMODE=${lsrmode} GSR:${gsr} SRMODE:${srmode} Q0:Q0 Q1:Q1 ", \dm:site ="R2C2${z}" *) 10 | SLICE SLICE_I ( .A0(q)${used} ); 11 | endmodule 12 | -------------------------------------------------------------------------------- /fuzzers/LFCPNX/012-plc-modes/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | import nonrouting 3 | import fuzzloops 4 | import re 5 | 6 | cfg = FuzzConfig(job="SLICEMODE", device="LFCPNX-100", sv="../shared/empty_100.v", tiles=["R2C2:PLC"]) 7 | 8 | def main(): 9 | cfg.setup() 10 | empty = cfg.build_design(cfg.sv, {}) 11 | cfg.sv = "slice.v" 12 | 13 | def per_slice(slicen): 14 | def get_substs(mode="LOGIC", kv=None): 15 | if kv is None: 16 | config = "" 17 | else: 18 | config = "{}:::{}={}".format(mode, kv[0], kv[1]) 19 | return dict(z=slicen, mode=mode, config=config) 20 | modes = ["LOGIC", "CCU2"] 21 | if slicen in ("A", "B"): 22 | modes.append("DPRAM") 23 | if slicen == "C": 24 | modes.append("RAMW") 25 | nonrouting.fuzz_enum_setting(cfg, empty, "SLICE{}.MODE".format(slicen), modes, 26 | lambda x: get_substs(x), False) 27 | nonrouting.fuzz_enum_setting(cfg, empty, "SLICE{}.CCU2.INJECT".format(slicen), ["YES", "NO"], 28 | lambda x: get_substs("CCU2", ("INJECT", x)), False) 29 | fuzzloops.parallel_foreach(["A", "B", "C", "D"], per_slice) 30 | 31 | if __name__ == "__main__": 32 | main() 33 | -------------------------------------------------------------------------------- /fuzzers/LFCPNX/012-plc-modes/slice.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LFCPNX", \db:device ="LFCPNX-100", \db:package ="LFG672", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \dm:cellmodel_primitives ="K0=i48_3_lut", \dm:primitive ="SLICE", \dm:programming ="MODE:${mode} ${config}", \dm:site ="R2C2${z}" *) 7 | SLICE SLICE_I ( ); 8 | endmodule 9 | -------------------------------------------------------------------------------- /fuzzers/LFCPNX/020-plc_tap/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import re 4 | 5 | configs = [ 6 | ([(11, 7), (11, 19)], [], FuzzConfig(job="TAPROUTE", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["TAP_PLC_R11C14:TAP_PLC"])), 7 | ([(10, 7), (10, 19)], [], FuzzConfig(job="TAPROUTECIB", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["TAP_CIB_R10C14:TAP_CIB"])), 8 | ([(1, 7), (1, 19)], [], FuzzConfig(job="TAPROUTECIBT", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["TAP_CIBT_R1C14:TAP_CIBT"])), 9 | ([(11, 152)], [], FuzzConfig(job="TAPROUTE_1S", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["TAP_PLC_1S_R11C146:TAP_PLC_1S"])), 10 | ([(10, 152)], [], FuzzConfig(job="TAPROUTECIB_1S", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["TAP_CIB_1S_R10C146:TAP_CIB_1S"])), 11 | ([(1, 152)], [], FuzzConfig(job="TAPROUTECIBT_1S", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["TAP_CIBT_1S_R1C146:TAP_CIBT_1S"])), 12 | ] 13 | 14 | def main(): 15 | for locs, rlocs, cfg in configs: 16 | cfg.setup() 17 | nodes = [] 18 | for r, c in locs: 19 | nodes += ["R{}C{}_HPBX{:02}00".format(r, c, i) for i in range(8)] 20 | for r, c in rlocs: 21 | nodes += ["R{}C{}_RHPBX{:02}00".format(r, c, i) for i in range(8)] 22 | fuzz_interconnect(config=cfg, nodenames=nodes, regex=False, bidir=False, full_mux_style=True) 23 | 24 | if __name__ == "__main__": 25 | main() 26 | -------------------------------------------------------------------------------- /fuzzers/LFCPNX/021-cmux/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import re 4 | 5 | cfg = FuzzConfig(job="CMUXROUTE", device="LFCPNX-100", sv="../shared/route_100.v", 6 | tiles=["CIB_R38C73:CMUX_0", "CIB_R38C74:CMUX_1_GSR", 7 | "CIB_R47C73:CMUX_2_TRUNK_LL", "CIB_R47C74:CMUX_3_TRUNK_LR", 8 | "CIB_R29C73:CMUX_4_TRUNK_UL", "CIB_R29C74:CMUX_5_TRUNK_UR", 9 | "CIB_R56C73:CMUX_6", "CIB_R56C74:CMUX_7"]) 10 | 11 | def main(): 12 | cfg.setup() 13 | nodes = ["R37C73_JHPRX{}_CMUX_CORE_CMUX3".format(i) for i in range(16)] + \ 14 | ["R37C73_JHPRX{}_CMUX_CORE_CMUX2".format(i) for i in range(16)] + \ 15 | ["R37C73_JHPRX{}_CMUX_CORE_CMUX1".format(i) for i in range(16)] + \ 16 | ["R37C73_JHPRX{}_CMUX_CORE_CMUX0".format(i) for i in range(16)] + \ 17 | ["R37C73_JDCSMUXOUT_DCSMUX_CORE_DCSMUX{}".format(i) for i in range(4)] 18 | fuzz_interconnect(config=cfg, nodenames=nodes, regex=False, bidir=False, full_mux_style=True) 19 | misc_nodes = [] 20 | for i in range(4): 21 | misc_nodes.append("R37C73_JCLKI_DCC_DCC{}".format(i)) 22 | misc_nodes.append("R37C73_JCE_DCC_DCC{}".format(i)) 23 | misc_nodes.append("R37C73_JCLKO_DCC_DCC{}".format(i)) 24 | for q in ("UL", "UR", "LL", "LR"): 25 | for i in range(4): 26 | misc_nodes.append(f"R37C73_JJCLK{q}_CMUX_CORE_CMUX{i}") 27 | misc_nodes.append(f"R37C73_JJCLK{q}_DCSMUX_CORE_DCSMUX{i}") 28 | for i in range(4): 29 | misc_nodes.append(f"R37C73_JCLK0_DCS_DCSIP{i}") 30 | misc_nodes.append(f"R37C73_JCLK1_DCS_DCSIP{i}") 31 | misc_nodes.append(f"R37C73_JDCS{i}_CMUX_CORE_CMUX0") 32 | misc_nodes.append(f"R37C73_JDCS{i}_CMUX_CORE_CMUX1") 33 | misc_nodes.append(f"R37C73_JDCS{i}_CMUX_CORE_CMUX2") 34 | misc_nodes.append(f"R37C73_JDCS{i}_CMUX_CORE_CMUX3") 35 | misc_nodes.append(f"R37C73_JDCSOUT_DCS_DCSIP{i}") 36 | misc_nodes.append(f"R37C73_JSEL_DCS_DCSIP{i}") 37 | misc_nodes.append(f"R37C73_JSELFORCE_DCS_DCSIP{i}") 38 | for i in range(2): 39 | misc_nodes.append(f"R37C73_JCLKOUT_PCLKDIV_PCLKDIV{i}") 40 | misc_nodes.append(f"R37C73_JLSRPDIV_PCLKDIV_PCLKDIV{i}") 41 | for j in range(3): 42 | misc_nodes.append(f"R37C73_JPCLKDIVTESTINP{j}_PCLKDIV_PCLKDIV{i}") 43 | misc_nodes.append(f"R37C73_JCLKIN_PCLKDIV_PCLKDIV{i}") 44 | 45 | for i in range(4): 46 | for j in range(7): 47 | misc_nodes.append("R37C73_JTESTINP{}_DCSMUX_CORE_DCSMUX{}".format(j, i)) 48 | for j in range(5): 49 | misc_nodes.append("R37C73_JTESTINP{}_CMUX_CORE_CMUX{}".format(j, i)) 50 | misc_nodes.append("R37C73_JGSR_N_GSR_CORE_GSR_CENTER") 51 | misc_nodes.append("R37C73_JCLK_GSR_CORE_GSR_CENTER") 52 | fuzz_interconnect(config=cfg, nodenames=misc_nodes, regex=False, bidir=False, full_mux_style=False) 53 | if __name__ == "__main__": 54 | main() 55 | -------------------------------------------------------------------------------- /fuzzers/LFCPNX/022-midmux/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | 4 | cr, cc = (37, 73) 5 | 6 | configs = [ 7 | ("HPFE", (37, 0), 12, "L", 8 | FuzzConfig(job="LMIDROUTE", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R37C0:LMID"])), 9 | ("HPFW", (37, 158), 12, "R", 10 | FuzzConfig(job="RMIDROUTE", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R37C159:RMID"])), 11 | ("VPFN", (73, 73), 18, "B", 12 | FuzzConfig(job="BMIDROUTE", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R74C73:BMID_0_ECLK_1", "CIB_R74C74:BMID_1_ECLK_2"])), 13 | ("VPFS", (0, 73), 16, "T", 14 | FuzzConfig(job="TMIDROUTE", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R0C73:TMID_0", "CIB_R0C74:TMID_1"])), 15 | ] 16 | 17 | def main(): 18 | for feed, rc, ndcc, side, cfg in configs: 19 | cfg.setup() 20 | r, c = rc 21 | nodes = [] 22 | mux_nodes = [] 23 | for i in range(ndcc): 24 | for j in range(4): 25 | nodes.append("R{}C{}_J{}{}_CMUX_CORE_CMUX{}".format(cr, cc, feed, i, j)) 26 | nodes.append("R{}C{}_J{}{}_CMUX_CORE_CMUX{}".format(cr, cc, feed, i, j)) 27 | nodes.append("R{}C{}_J{}{}_DCSMUX_CORE_DCSMUX{}".format(cr, cc, feed, i, j)) 28 | nodes.append("R{}C{}_J{}{}_DCSMUX_CORE_DCSMUX{}".format(cr, cc, feed, i, j)) 29 | nodes.append("R{}C{}_JCLKO_DCC_DCC{}".format(r, c, i)) 30 | nodes.append("R{}C{}_JCE_DCC_DCC{}".format(r, c, i)) 31 | nodes.append("R{}C{}_JCLKI_DCC_DCC{}".format(r, c, i)) 32 | mux_nodes.append("R{}C{}_J{}{}_{}MID_CORE_{}MIDMUX".format(r, c, feed, i, side, side)) 33 | for i in range(4): 34 | nodes.append("R{}C{}_JTESTINP{}_{}MID_CORE_{}MIDMUX".format(r, c, i, side, side)) 35 | fuzz_interconnect(config=cfg, nodenames=nodes, regex=False, bidir=False, full_mux_style=False) 36 | fuzz_interconnect(config=cfg, nodenames=mux_nodes, regex=False, bidir=False, full_mux_style=True) 37 | def pip_filter(pip, nodes): 38 | from_wire, to_wire = pip 39 | return "PCLKT" in to_wire or "PCLKCIB" in to_wire 40 | fuzz_interconnect(config=cfg, nodenames=["R{}C{}_J*".format(r, c)], regex=True, bidir=False, full_mux_style=False, 41 | pip_predicate=pip_filter) 42 | 43 | if __name__ == "__main__": 44 | main() 45 | -------------------------------------------------------------------------------- /fuzzers/LFCPNX/023-trunk-spine/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import re 4 | 5 | spine_cfgs = { 6 | ("CIB_R29C13:SPINE_UL2", "R19C13"), 7 | ("CIB_R29C37:SPINE_UL1", "R19C37"), 8 | ("CIB_R29C61:SPINE_UL0", "R19C61"), 9 | ("CIB_R29C86:SPINE_UR0", "R19C85"), 10 | ("CIB_R29C110:SPINE_UR1", "R19C109"), 11 | ("CIB_R29C134:SPINE_UR2", "R19C133"), 12 | ("CIB_R29C146:SPINE_UR3", "R19C145"), 13 | 14 | ("CIB_R47C13:SPINE_LL2", "R56C13"), 15 | ("CIB_R47C37:SPINE_LL1", "R56C37"), 16 | ("CIB_R47C61:SPINE_LL0", "R56C61"), 17 | ("CIB_R47C86:SPINE_LR0", "R56C85"), 18 | ("CIB_R47C110:SPINE_LR1", "R56C109"), 19 | ("CIB_R47C134:SPINE_LR2", "R56C133"), 20 | ("CIB_R47C146:SPINE_LR3", "R56C145"), 21 | 22 | } 23 | 24 | hrow_cfgs = { 25 | ("CIB_R29C61:SPINE_UL0", "R28C43"), 26 | ("CIB_R29C86:SPINE_UR0", "R28C109"), 27 | ("CIB_R47C61:SPINE_LL0", "R46C44"), 28 | ("CIB_R47C86:SPINE_LR0", "R46C109"), 29 | } 30 | 31 | trunk_cfgs = { 32 | ("CIB_R29C73:CMUX_4_TRUNK_UL", "R33C73_TL"), 33 | ("CIB_R29C74:CMUX_5_TRUNK_UR", "R33C73_TR"), 34 | ("CIB_R47C73:CMUX_2_TRUNK_LL", "R42C73_BL"), 35 | ("CIB_R47C74:CMUX_3_TRUNK_LR", "R42C73_BR"), 36 | } 37 | 38 | def main(): 39 | for tile, rc in spine_cfgs: 40 | cfg = FuzzConfig(job="TAPROUTE", device="LFCPNX-100", sv="../shared/route_100.v", tiles=[tile]) 41 | cfg.setup() 42 | nodes = ["{}_VPSX{:02}00".format(rc, i) for i in range(16)] 43 | fuzz_interconnect(config=cfg, nodenames=nodes, regex=False, bidir=False, full_mux_style=False) 44 | for tile, rc in hrow_cfgs: 45 | cfg = FuzzConfig(job="ROWROUTE", device="LFCPNX-100", sv="../shared/route_100.v", tiles=[tile]) 46 | cfg.setup() 47 | nodes = ["{}_HPRX{:02}00".format(rc, i) for i in range(16)] 48 | fuzz_interconnect(config=cfg, nodenames=nodes, regex=False, bidir=False, full_mux_style=False) 49 | for tile, rcs in trunk_cfgs: 50 | cfg = FuzzConfig(job="TRUNKROUTE", device="LFCPNX-100", sv="../shared/route_100.v", tiles=[tile]) 51 | cfg.setup() 52 | nodes = ["{}HPRX{}".format(rcs, i) for i in range(16)] 53 | fuzz_interconnect(config=cfg, nodenames=nodes, regex=False, bidir=False, full_mux_style=False) 54 | 55 | 56 | 57 | 58 | if __name__ == "__main__": 59 | main() 60 | -------------------------------------------------------------------------------- /fuzzers/LFCPNX/030-io_route/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import re 4 | 5 | configs = [ 6 | { 7 | "cfg": FuzzConfig(job="IOROUTE5", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R74C10:SYSIO_B5_0", "CIB_R74C11:SYSIO_B5_1"]), 8 | "rc": (74, 10), 9 | }, 10 | { 11 | "cfg": FuzzConfig(job="IOROUTE4", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R74C58:SYSIO_B4_0", "CIB_R74C59:SYSIO_B4_1"]), 12 | "rc": (74, 58), 13 | }, 14 | { 15 | "cfg": FuzzConfig(job="IOROUTE3", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R74C118:SYSIO_B3_0", "CIB_R74C119:SYSIO_B3_1"]), 16 | "rc": (74, 118), 17 | }, 18 | { 19 | "cfg": FuzzConfig(job="IOROUTE2E", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R44C159:SYSIO_B2_0_EVEN"]), 20 | "rc": (44, 159), 21 | }, 22 | { 23 | "cfg": FuzzConfig(job="IOROUTE2O", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R42C159:SYSIO_B2_0_ODD"]), 24 | "rc": (42, 159), 25 | }, 26 | { 27 | "cfg": FuzzConfig(job="IOROUTE1O", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R8C159:SYSIO_B1_0_ODD"]), 28 | "rc": (8, 159), 29 | }, 30 | { 31 | "cfg": FuzzConfig(job="IOROUTE1E", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R6C159:SYSIO_B1_0_EVEN"]), 32 | "rc": (6, 159), 33 | }, 34 | { 35 | "cfg": FuzzConfig(job="IOROUTE0O", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R0C140:SYSIO_B0_0_ODD"]), 36 | "rc": (0, 140), 37 | }, 38 | { 39 | "cfg": FuzzConfig(job="IOROUTE0E", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R0C142:SYSIO_B0_0_EVEN"]), 40 | "rc": (0, 142), 41 | }, 42 | { 43 | "cfg": FuzzConfig(job="IOROUTE7E", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R3C0:SYSIO_B7_0_EVEN"]), 44 | "rc": (3, 0), 45 | }, 46 | { 47 | "cfg": FuzzConfig(job="IOROUTE7O", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R4C0:SYSIO_B7_0_ODD"]), 48 | "rc": (4, 0), 49 | }, 50 | { 51 | "cfg": FuzzConfig(job="IOROUTE6O", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R49C0:SYSIO_B6_0_ODD"]), 52 | "rc": (49, 0), 53 | }, 54 | { 55 | "cfg": FuzzConfig(job="IOROUTE6E", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R44C0:SYSIO_B6_0_EVEN"]), 56 | "rc": (44, 0), 57 | }, 58 | { 59 | "cfg": FuzzConfig(job="IOROUTE1D", device="LFCPNX-100", sv="../shared/route_100.v", tiles=["CIB_R3C159:SYSIO_B1_DED"]), 60 | "rc": (3, 159), 61 | }, 62 | ] 63 | 64 | ignore_tiles = set([ 65 | "CIB_R{}C1:CIB_LR".format(c) for c in range(2, 74) 66 | ] + [ 67 | "CIB_R{}C158:CIB_LR".format(c) for c in range(2, 74) 68 | ] + [ 69 | "CIB_R1C{}:CIB_T".format(c) for c in range(1, 159) 70 | ] + [ 71 | "CIB_R73C{}:CIB".format(c) for c in range(1, 159) 72 | ] + [ 73 | "CIB_R10C1:CIB_LR_A", 74 | "CIB_R19C1:CIB_LR_A", 75 | "CIB_R28C1:CIB_LR_A", 76 | "CIB_R37C1:CIB_LR_A", 77 | "CIB_R46C1:CIB_LR_A", 78 | "CIB_R55C1:CIB_LR_A", 79 | "CIB_R64C1:CIB_LR_A", 80 | "CIB_R10C158:CIB_LR_A", 81 | "CIB_R19C158:CIB_LR_A", 82 | "CIB_R28C158:CIB_LR_A", 83 | "CIB_R37C158:CIB_LR_A", 84 | "CIB_R46C158:CIB_LR_A", 85 | "CIB_R55C158:CIB_LR_A", 86 | "CIB_R64C158:CIB_LR_A", 87 | ]) 88 | 89 | 90 | def main(): 91 | for config in configs: 92 | cfg = config["cfg"] 93 | cfg.setup() 94 | r, c = config["rc"] 95 | nodes = ["R{}C{}_*".format(r, c)] 96 | def nodename_filter(x, nodes): 97 | return ("R{}C{}_".format(r, c) in x) and ("_GEARING_PIC_TOP_" in x or "SEIO18_CORE" in x or "DIFFIO18_CORE" in x or "I217" in x or "I218" in x or "SEIO33_CORE" in x or "SIOLOGIC_CORE" in x) 98 | def pip_filter(pip, nodes): 99 | from_wire, to_wire = pip 100 | return not ("ADC_CORE" in to_wire or "ECLKBANK_CORE" in to_wire or "MID_CORE" in to_wire 101 | or "REFMUX_CORE" in to_wire or "CONFIG_JTAG_CORE" in to_wire or "CONFIG_JTAG_CORE" in from_wire 102 | or "REFCLOCK_MUX_CORE" in to_wire) 103 | fuzz_interconnect(config=cfg, nodenames=nodes, nodename_predicate=nodename_filter, pip_predicate=pip_filter, regex=True, bidir=True, 104 | ignore_tiles=ignore_tiles) 105 | 106 | if __name__ == "__main__": 107 | main() 108 | -------------------------------------------------------------------------------- /fuzzers/LFCPNX/shared/empty_100.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LFCPNX", \db:device ="LFCPNX-100", \db:package ="LFG672", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | // A primitive is needed, but VHI should be harmless 7 | (* \xref:LOG ="q_c@0@9" *) 8 | VHI vhi_i(); 9 | endmodule 10 | -------------------------------------------------------------------------------- /fuzzers/LFCPNX/shared/route_100.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LFCPNX", \db:device ="LFCPNX-100", \db:package ="LFG672", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \xref:LOG ="q_c@0@9"${arcs_attr} *) 7 | wire q; 8 | 9 | (* \dm:cellmodel_primitives ="REG0=reg", \dm:primitive ="SLICE", \dm:programming ="MODE:LOGIC Q0:Q0 ", \dm:site ="R2C2A" *) 10 | SLICE SLICE_I ( .A0(q), .Q0(q) ); 11 | endmodule 12 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/001-plc-routing/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import re 4 | 5 | cfg = FuzzConfig(job="PLCROUTE", device="LIFCL-40", sv="../shared/route_40.v", tiles=["R16C22:PLC"]) 6 | 7 | def main(): 8 | cfg.setup() 9 | r = 16 10 | c = 22 11 | nodes = ["R{}C{}_J*".format(r, c)] 12 | extra_sources = [] 13 | extra_sources += ["R{}C{}_H02E{:02}01".format(r, c+1, i) for i in range(8)] 14 | extra_sources += ["R{}C{}_H06E{:02}03".format(r, c+3, i) for i in range(4)] 15 | extra_sources += ["R{}C{}_V02N{:02}01".format(r-1, c, i) for i in range(8)] 16 | extra_sources += ["R{}C{}_V06N{:02}03".format(r-3, c, i) for i in range(4)] 17 | extra_sources += ["R{}C{}_V02S{:02}01".format(r+1, c, i) for i in range(8)] 18 | extra_sources += ["R{}C{}_V06S{:02}03".format(r+3, c, i) for i in range(4)] 19 | extra_sources += ["R{}C{}_H02W{:02}01".format(r, c-1, i) for i in range(8)] 20 | extra_sources += ["R{}C{}_H06W{:02}03".format(r, c-3, i) for i in range(4)] 21 | fuzz_interconnect(config=cfg, nodenames=nodes, regex=True, bidir=True, ignore_tiles=set(["TAP_PLC_R16C14:TAP_PLC"])) 22 | fuzz_interconnect(config=cfg, nodenames=extra_sources, regex=False, bidir=False, ignore_tiles=set(["TAP_PLC_R16C14:TAP_PLC"])) 23 | 24 | if __name__ == "__main__": 25 | main() 26 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/002-cib-routing/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import re 4 | 5 | configs = [ 6 | ((1, 18), FuzzConfig(job="CIBTROUTE", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R1C18:CIB_T"]), set(["TAP_CIBT_R1C14:TAP_CIBT"])), 7 | ((18, 1), FuzzConfig(job="CIBLRROUTE", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R18C1:CIB_LR"]), set(["TAP_PLC_R18C14:TAP_PLC"])), 8 | ((28, 17), FuzzConfig(job="CIBROUTE", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R28C17:CIB"]), set(["TAP_CIB_R28C14:TAP_CIB"])), 9 | ((28, 1), FuzzConfig(job="CIBLRAROUTE", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R28C1:CIB_LR_A"]), set(["TAP_CIB_R28C14:TAP_CIB"])), 10 | ] 11 | 12 | def main(): 13 | for rc, cfg, ignore in configs: 14 | cfg.setup() 15 | r, c = rc 16 | nodes = ["R{}C{}_J*".format(r, c)] 17 | extra_sources = [] 18 | extra_sources += ["R{}C{}_H02E{:02}01".format(r, c+1, i) for i in range(8)] 19 | extra_sources += ["R{}C{}_H06E{:02}03".format(r, c+3, i) for i in range(4)] 20 | if r != 1: 21 | extra_sources += ["R{}C{}_V02N{:02}01".format(r-1, c, i) for i in range(8)] 22 | extra_sources += ["R{}C{}_V06N{:02}03".format(r-3, c, i) for i in range(4)] 23 | else: 24 | extra_sources += ["R{}C{}_V02N{:02}00".format(r, c, i) for i in range(8)] 25 | extra_sources += ["R{}C{}_V06N{:02}00".format(r, c, i) for i in range(4)] 26 | extra_sources += ["R{}C{}_V02S{:02}01".format(r+1, c, i) for i in range(8)] 27 | extra_sources += ["R{}C{}_V06S{:02}03".format(r+3, c, i) for i in range(4)] 28 | if c != 1: 29 | extra_sources += ["R{}C{}_H02W{:02}01".format(r, c-1, i) for i in range(8)] 30 | extra_sources += ["R{}C{}_H06W{:02}03".format(r, c-3, i) for i in range(4)] 31 | else: 32 | extra_sources += ["R{}C{}_H02W{:02}00".format(r, c, i) for i in range(8)] 33 | extra_sources += ["R{}C{}_H06W{:02}00".format(r, c, i) for i in range(4)] 34 | def pip_filter(pip, nodes): 35 | from_wire, to_wire = pip 36 | return not ("_CORE" in from_wire or "_CORE" in to_wire or "JCIBMUXOUT" in to_wire) 37 | def fc_filter(to_wire): 38 | return "CIBMUX" in to_wire or "CIBTEST" in to_wire or to_wire.startswith("R{}C{}_J".format(r, c)) 39 | fuzz_interconnect(config=cfg, nodenames=nodes, regex=True, bidir=True, ignore_tiles=ignore, 40 | pip_predicate=pip_filter, fc_filter=fc_filter) 41 | fuzz_interconnect(config=cfg, nodenames=extra_sources, regex=False, bidir=False, ignore_tiles=ignore, 42 | pip_predicate=pip_filter, fc_filter=fc_filter) 43 | 44 | if __name__ == "__main__": 45 | main() 46 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/010-lut-init/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | import nonrouting 3 | import fuzzloops 4 | import re 5 | 6 | cfg = FuzzConfig(job="PLCINIT", device="LIFCL-40", sv="../shared/empty_40.v", tiles=["R2C2:PLC"]) 7 | 8 | def get_lut_function(init_bits): 9 | sop_terms = [] 10 | lut_inputs = ["A", "B", "C", "D"] 11 | for i in range(16): 12 | if init_bits[i]: 13 | p_terms = [] 14 | for j in range(4): 15 | if i & (1 << j) != 0: 16 | p_terms.append(lut_inputs[j]) 17 | else: 18 | p_terms.append("~" + lut_inputs[j]) 19 | sop_terms.append("({})".format("*".join(p_terms))) 20 | if len(sop_terms) == 0: 21 | lut_func = "0" 22 | else: 23 | lut_func = "+".join(sop_terms) 24 | return lut_func 25 | 26 | 27 | def main(): 28 | cfg.setup() 29 | cfg.sv = "lut.v" 30 | 31 | def per_slice(slicen): 32 | for k in range(2): 33 | def get_substs(bits): 34 | return dict(z=slicen, k=str(k), func=get_lut_function(bits)) 35 | nonrouting.fuzz_word_setting(cfg, "SLICE{}.K{}.INIT".format(slicen, k), 16, get_substs, 36 | desc="SLICE {} LUT{} init value".format(slicen, k)) 37 | 38 | fuzzloops.parallel_foreach(["A", "B", "C", "D"], per_slice) 39 | 40 | 41 | if __name__ == "__main__": 42 | main() 43 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/010-lut-init/lut.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \dm:cellmodel_primitives ="K${k}=i48_3_lut", \dm:primitive ="SLICE", \dm:programming ="MODE:LOGIC F${k}:F${k} K${k}::Z=${func} ", \dm:site ="R2C2${z}" *) 7 | SLICE SLICE_I ( ); 8 | endmodule 9 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/011-reg-config/ff.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \xref:LOG ="q_c@0@9", \dm:arcs ="${arc}" *) 7 | wire q; 8 | 9 | (* \dm:cellmodel_primitives ="REG${k}=i48_3_lut", \dm:primitive ="SLICE", \dm:programming ="MODE:LOGIC ${mux} REG${k}:::REGSET=${regset},SEL=${sel},LSRMODE=${lsrmode} GSR:${gsr} SRMODE:${srmode} Q0:Q0 Q1:Q1 ", \dm:site ="R2C2${z}" *) 10 | SLICE SLICE_I ( .A0(q)${used} ); 11 | endmodule 12 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/011-reg-config/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | import nonrouting 3 | import fuzzloops 4 | import re 5 | 6 | cfg = FuzzConfig(job="REGCFG", device="LIFCL-40", sv="../shared/empty_40.v", tiles=["R2C2:PLC"]) 7 | 8 | def main(): 9 | cfg.setup() 10 | empty = cfg.build_design(cfg.sv, {}) 11 | cfg.sv = "ff.v" 12 | 13 | def per_slice(slicen): 14 | for r in range(2): 15 | def get_substs(regset="SET", sel="DL", lsrmode="LSR", srmode="LSR_OVER_CE", gsr="DISABLED", mux="", used="", arc=""): 16 | return dict(z=slicen, k=str(r), mux=mux, regset=regset, 17 | sel=sel, lsrmode=lsrmode, srmode=srmode, gsr=gsr, used=used, arc=arc) 18 | def get_used_substs(used): 19 | u = "" 20 | arc = "" 21 | if used == "YES": 22 | u = ", .Q{}(q) ".format(r) 23 | arc = "R2C2_JQ{}.R2C2_JQ{}_SLICE{}".format(str(("ABCD".index(slicen)*2)+r), r, slicen) 24 | return get_substs(used=u, arc=arc) 25 | def get_ddr_substs(ddr): 26 | return get_substs(mux="REGDDR:{}".format(ddr)) 27 | def get_clkmux_substs(mux): 28 | if mux == "CLK": 29 | cm = "CLK:::CLK=#SIG" 30 | elif mux == "INV": 31 | cm = "CLK:::CLK=#INV" 32 | elif mux == "1": 33 | cm = "CONST:::CONST=1" 34 | elif mux == "0": 35 | cm = "#OFF" 36 | elif mux == "DDR": 37 | return get_substs(mux="REGDDR:ENABLED") 38 | return get_substs(mux="CLKMUX:{}".format(cm)) 39 | def get_cemux_substs(mux): 40 | if mux == "CE": 41 | cm = "CE:::CE=#SIG" 42 | elif mux == "INV": 43 | cm = "CE:::CE=#INV" 44 | return get_substs(mux="CEMUX:{}".format(cm)) 45 | def get_lsrmux_substs(mux): 46 | if mux == "LSR": 47 | cm = "LSR:::CE=#SIG" 48 | elif mux == "INV": 49 | cm = "LSR:::LSR=#INV" 50 | elif mux == "0": 51 | cm = "CONST:::CONST=0" 52 | return get_substs(mux="LSRMUX:{}".format(cm)) 53 | nonrouting.fuzz_enum_setting(cfg, empty, "SLICE{}.REG{}.USED".format(slicen, r), ["YES", "NO"], 54 | lambda x: get_used_substs(x), False, 55 | desc="`YES` if SLICE {} register {} (Q{}) is used".format(slicen, r, r)) 56 | nonrouting.fuzz_enum_setting(cfg, empty, "SLICE{}.REG{}.REGSET".format(slicen, r), ["RESET", "SET"], 57 | lambda x: get_substs(regset=x), True, 58 | desc="SLICE {} register {} set/reset and init value".format(slicen, r)) 59 | nonrouting.fuzz_enum_setting(cfg, empty, "SLICE{}.REG{}.SEL".format(slicen, r), ["DL", "DF"], 60 | lambda x: get_substs(sel=x), True, 61 | desc="SLICE {} register {} data selection. `DL`=LUT output, `DF`=bypass (M{})".format(slicen, r, r)) 62 | nonrouting.fuzz_enum_setting(cfg, empty, "SLICE{}.REG{}.LSRMODE".format(slicen, r), ["LSR", "PRLD"], 63 | lambda x: get_substs(lsrmode=x), True) 64 | h = "A/B" if slicen in ("A", "B") else "C/D" 65 | nonrouting.fuzz_enum_setting(cfg, empty, "SLICE{}.GSR".format(slicen, r), ["ENABLED", "DISABLED"], 66 | lambda x: get_substs(gsr=x), False, 67 | desc="if `ENABLED`, then FFs in SLICE {} are set/reset by user GSR signal".format(h)) 68 | nonrouting.fuzz_enum_setting(cfg, empty, "SLICE{}.SRMODE".format(slicen, r), ["ASYNC", "LSR_OVER_CE"], 69 | lambda x: get_substs(srmode=x), False, 70 | desc="selects asynchronous set/reset, or sync set/reset which overrides CE for FFs in SLICE {}".format(h)) 71 | nonrouting.fuzz_enum_setting(cfg, empty, "SLICE{}.REGDDR".format(slicen, r), ["ENABLED", "DISABLED"], 72 | lambda x: get_ddr_substs(x), False, 73 | desc="if ENABLED then FFs in SLICE {} are clocked by both edges of the clock".format(h)) 74 | nonrouting.fuzz_enum_setting(cfg, empty, "SLICE{}.CLKMUX".format(slicen, r), ["CLK", "INV", "0", "DDR"], 75 | lambda x: get_clkmux_substs(x), False, 76 | desc="selects clock polarity") 77 | nonrouting.fuzz_enum_setting(cfg, empty, "SLICE{}.CEMUX".format(slicen, r), ["CE", "INV"], 78 | lambda x: get_cemux_substs(x), False, 79 | desc="selects clock enable polarity") 80 | nonrouting.fuzz_enum_setting(cfg, empty, "SLICE{}.LSRMUX".format(slicen, r), ["LSR", "INV", "0"], 81 | lambda x: get_lsrmux_substs(x), False, 82 | desc="selects set/reset gating and inversion") 83 | fuzzloops.parallel_foreach(["A", "B", "C", "D"], per_slice) 84 | 85 | if __name__ == "__main__": 86 | main() 87 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/012-plc-modes/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | import nonrouting 3 | import fuzzloops 4 | import re 5 | 6 | cfg = FuzzConfig(job="SLICEMODE", device="LIFCL-40", sv="../shared/empty_40.v", tiles=["R2C2:PLC"]) 7 | 8 | def main(): 9 | cfg.setup() 10 | empty = cfg.build_design(cfg.sv, {}) 11 | cfg.sv = "slice.v" 12 | 13 | def per_slice(slicen): 14 | def get_substs(mode="LOGIC", kv=None): 15 | if kv is None: 16 | config = "" 17 | else: 18 | config = "{}:::{}={}".format(mode, kv[0], kv[1]) 19 | return dict(z=slicen, mode=mode, config=config) 20 | modes = ["LOGIC", "CCU2"] 21 | if slicen in ("A", "B"): 22 | modes.append("DPRAM") 23 | if slicen == "C": 24 | modes.append("RAMW") 25 | nonrouting.fuzz_enum_setting(cfg, empty, "SLICE{}.MODE".format(slicen), modes, 26 | lambda x: get_substs(x), False) 27 | nonrouting.fuzz_enum_setting(cfg, empty, "SLICE{}.CCU2.INJECT".format(slicen), ["YES", "NO"], 28 | lambda x: get_substs("CCU2", ("INJECT", x)), False) 29 | fuzzloops.parallel_foreach(["A", "B", "C", "D"], per_slice) 30 | 31 | if __name__ == "__main__": 32 | main() 33 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/012-plc-modes/slice.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \dm:cellmodel_primitives ="K0=i48_3_lut", \dm:primitive ="SLICE", \dm:programming ="MODE:${mode} ${config}", \dm:site ="R2C2${z}" *) 7 | SLICE SLICE_I ( ); 8 | endmodule 9 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/020-plc_tap/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import re 4 | 5 | configs = [ 6 | ([(11, 7), (11, 19)], [], FuzzConfig(job="TAPROUTE", device="LIFCL-40", sv="../shared/route_40.v", tiles=["TAP_PLC_R11C14:TAP_PLC"])), 7 | ([(10, 7), (10, 19)], [], FuzzConfig(job="TAPROUTECIB", device="LIFCL-40", sv="../shared/route_40.v", tiles=["TAP_CIB_R10C14:TAP_CIB"])), 8 | ([(1, 7), (1, 19)], [], FuzzConfig(job="TAPROUTECIBT", device="LIFCL-40", sv="../shared/route_40.v", tiles=["TAP_CIBT_R1C14:TAP_CIBT"])), 9 | ([(11, 80)], [], FuzzConfig(job="TAPROUTE_1S", device="LIFCL-40", sv="../shared/route_40.v", tiles=["TAP_PLC_1S_R11C74:TAP_PLC_1S"])), 10 | ([(10, 80)], [], FuzzConfig(job="TAPROUTECIB_1S", device="LIFCL-40", sv="../shared/route_40.v", tiles=["TAP_CIB_1S_R10C74:TAP_CIB_1S"])), 11 | ([(1, 80)], [], FuzzConfig(job="TAPROUTECIBT_1S", device="LIFCL-40", sv="../shared/route_40.v", tiles=["TAP_CIBT_1S_R1C74:TAP_CIBT_1S"])), 12 | 13 | ([(11, 7), ], [(11, 13), ], FuzzConfig(job="TAPROUTE_1SL", device="LIFCL-17", sv="../shared/route_17.v", tiles=["TAP_PLC_1S_L_R11C14:TAP_PLC_1S_L"])), 14 | ([(10, 7), ], [(10, 13), ], FuzzConfig(job="TAPROUTECIB_1SL", device="LIFCL-17", sv="../shared/route_17.v", tiles=["TAP_CIB_1S_L_R10C14:TAP_CIB_1S_L"])), 15 | ([(1, 7), ], [(1, 13), ], FuzzConfig(job="TAPROUTECIBT_1SL", device="LIFCL-17", sv="../shared/route_17.v", tiles=["TAP_CIBT_1S_L_R1C14:TAP_CIBT_1S_L"])), 16 | ] 17 | 18 | def main(): 19 | for locs, rlocs, cfg in configs: 20 | cfg.setup() 21 | nodes = [] 22 | for r, c in locs: 23 | nodes += ["R{}C{}_HPBX{:02}00".format(r, c, i) for i in range(8)] 24 | for r, c in rlocs: 25 | nodes += ["R{}C{}_RHPBX{:02}00".format(r, c, i) for i in range(8)] 26 | fuzz_interconnect(config=cfg, nodenames=nodes, regex=False, bidir=False, full_mux_style=True) 27 | 28 | if __name__ == "__main__": 29 | main() 30 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/021-cmux/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import re 4 | 5 | cfg = FuzzConfig(job="CMUXROUTE", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R29C49:CMUX_0", "CIB_R29C50:CMUX_1", "CIB_R38C49:CMUX_2", "CIB_R38C50:CMUX_3"]) 6 | 7 | def main(): 8 | cfg.setup() 9 | nodes = ["R28C49_JHPRX{}_CMUX_CORE_CMUX1".format(i) for i in range(16)] + \ 10 | ["R28C49_JHPRX{}_CMUX_CORE_CMUX0".format(i) for i in range(16)] + \ 11 | ["R28C49_JDCSMUXOUT_DCSMUX_CORE_DCSMUX0", "R28C49_JDCSMUXOUT_DCSMUX_CORE_DCSMUX1"] 12 | fuzz_interconnect(config=cfg, nodenames=nodes, regex=False, bidir=False, full_mux_style=True) 13 | misc_nodes = [] 14 | for i in range(4): 15 | misc_nodes.append("R28C49_JCLKI_DCC_DCC{}".format(i)) 16 | misc_nodes.append("R28C49_JCE_DCC_DCC{}".format(i)) 17 | misc_nodes.append("R28C49_JCLKO_DCC_DCC{}".format(i)) 18 | for q in ("UL", "UR", "LL", "LR"): 19 | misc_nodes.append("R28C49_JJCLK{}_CMUX_CORE_CMUX0".format(q)) 20 | misc_nodes.append("R28C49_JJCLK{}_CMUX_CORE_CMUX1".format(q)) 21 | misc_nodes.append("R28C49_JJCLK{}_DCSMUX_CORE_DCSMUX0".format(q)) 22 | misc_nodes.append("R28C49_JJCLK{}_DCSMUX_CORE_DCSMUX1".format(q)) 23 | misc_nodes.append("R28C49_JCLK0_DCS_DCSIP") 24 | misc_nodes.append("R28C49_JCLK1_DCS_DCSIP") 25 | misc_nodes.append("R28C49_JDCS0_CMUX_CORE_CMUX0") 26 | misc_nodes.append("R28C49_JDCS0_CMUX_CORE_CMUX1") 27 | misc_nodes.append("R28C49_JDCSOUT_DCS_DCSIP") 28 | misc_nodes.append("R28C49_JSEL_DCS_DCSIP") 29 | misc_nodes.append("R28C49_JSELFORCE_DCS_DCSIP") 30 | 31 | misc_nodes.append("R28C49_JCLKOUT_PCLKDIV_PCLKDIV") 32 | misc_nodes.append("R28C49_JLSRPDIV_PCLKDIV_PCLKDIV") 33 | for i in range(3): 34 | misc_nodes.append("R28C49_JPCLKDIVTESTINP{}_PCLKDIV_PCLKDIV".format(i)) 35 | misc_nodes.append("R28C49_JCLKIN_PCLKDIV_PCLKDIV") 36 | 37 | for i in range(2): 38 | for j in range(7): 39 | misc_nodes.append("R28C49_JTESTINP{}_DCSMUX_CORE_DCSMUX{}".format(j, i)) 40 | for j in range(5): 41 | misc_nodes.append("R28C49_JTESTINP{}_CMUX_CORE_CMUX{}".format(j, i)) 42 | misc_nodes.append("R28C49_JGSR_N_GSR_CORE_GSR_CENTER") 43 | misc_nodes.append("R28C49_JCLK_GSR_CORE_GSR_CENTER") 44 | fuzz_interconnect(config=cfg, nodenames=misc_nodes, regex=False, bidir=False, full_mux_style=False) 45 | if __name__ == "__main__": 46 | main() 47 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/022-midmux/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | 4 | configs = [ 5 | ("HPFE", (28, 0), 12, "L", 6 | FuzzConfig(job="LMIDROUTE", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R28C0:LMID"])), 7 | ("HPFW", (28, 86), 12, "R", 8 | FuzzConfig(job="RMIDROUTE", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R28C87:RMID_DLY20"])), 9 | ("VPFN", (56, 49), 18, "B", 10 | FuzzConfig(job="BMIDROUTE", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R56C49:BMID_0_ECLK_1", "CIB_R56C50:BMID_1_ECLK_2"])), 11 | ("VPFS", (0, 49), 16, "T", 12 | FuzzConfig(job="TMIDROUTE", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R0C49:TMID_0", "CIB_R0C50:TMID_1"])), 13 | 14 | ("HPFE", (10, 0), 12, "L", 15 | FuzzConfig(job="LMIDROUTE", device="LIFCL-17", sv="../shared/route_17.v", tiles=["CIB_R10C0:LMID_RBB_5_15K"])), 16 | ("HPFW", (10, 74), 12, "R", 17 | FuzzConfig(job="RMIDROUTE", device="LIFCL-17", sv="../shared/route_17.v", tiles=["CIB_R10C75:RMID_PICB_DLY10"])), 18 | ("VPFS", (0, 37), 16, "T", 19 | FuzzConfig(job="TMIDROUTE", device="LIFCL-17", sv="../shared/route_17.v", tiles=["CIB_R0C37:TMID_0", "CIB_R0C38:TMID_1_15K", "CIB_R0C39:CLKBUF_T_15K"])), 20 | ] 21 | 22 | def main(): 23 | for feed, rc, ndcc, side, cfg in configs: 24 | cfg.setup() 25 | if cfg.device == "LIFCL-40": 26 | cr, cc = (28, 49) 27 | else: 28 | cr, cc = (10, 37) 29 | r, c = rc 30 | nodes = [] 31 | mux_nodes = [] 32 | for i in range(ndcc): 33 | for j in range(2): 34 | nodes.append("R{}C{}_J{}{}_CMUX_CORE_CMUX{}".format(cr, cc, feed, i, j)) 35 | nodes.append("R{}C{}_J{}{}_CMUX_CORE_CMUX{}".format(cr, cc, feed, i, j)) 36 | nodes.append("R{}C{}_J{}{}_DCSMUX_CORE_DCSMUX{}".format(cr, cc, feed, i, j)) 37 | nodes.append("R{}C{}_J{}{}_DCSMUX_CORE_DCSMUX{}".format(cr, cc, feed, i, j)) 38 | nodes.append("R{}C{}_JCLKO_DCC_DCC{}".format(r, c, i)) 39 | nodes.append("R{}C{}_JCE_DCC_DCC{}".format(r, c, i)) 40 | nodes.append("R{}C{}_JCLKI_DCC_DCC{}".format(r, c, i)) 41 | mux_nodes.append("R{}C{}_J{}{}_{}MID_CORE_{}MIDMUX".format(r, c, feed, i, side, side)) 42 | for i in range(4): 43 | nodes.append("R{}C{}_JTESTINP{}_{}MID_CORE_{}MIDMUX".format(r, c, i, side, side)) 44 | fuzz_interconnect(config=cfg, nodenames=nodes, regex=False, bidir=False, full_mux_style=False) 45 | fuzz_interconnect(config=cfg, nodenames=mux_nodes, regex=False, bidir=False, full_mux_style=True) 46 | def pip_filter(pip, nodes): 47 | from_wire, to_wire = pip 48 | return "PCLKT" in to_wire or "PCLKCIB" in to_wire 49 | fuzz_interconnect(config=cfg, nodenames=["R{}C{}_J*".format(r, c)], regex=True, bidir=False, full_mux_style=False, 50 | pip_predicate=pip_filter) 51 | 52 | if __name__ == "__main__": 53 | main() 54 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/023-trunk-spine/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import re 4 | 5 | spine_cfgs = { 6 | ("CIB_R29C13:SPINE_L1", "R28C13"), 7 | ("CIB_R29C37:SPINE_L0", "R28C37"), 8 | ("CIB_R29C62:SPINE_R0", "R28C61"), 9 | ("CIB_R29C74:SPINE_R1", "R28C73"), 10 | } 11 | 12 | hrow_cfgs = { 13 | ("CIB_R29C37:SPINE_L0", "R28C31"), 14 | ("CIB_R29C62:SPINE_R0", "R28C61"), 15 | } 16 | 17 | trunk_cfgs = { 18 | ("CIB_R29C48:TRUNK_L_EBR_10", "R28C49_L"), 19 | ("CIB_R29C51:TRUNK_R", "R28C49_R"), 20 | } 21 | 22 | def main(): 23 | for tile, rc in spine_cfgs: 24 | cfg = FuzzConfig(job="TAPROUTE", device="LIFCL-40", sv="../shared/route_40.v", tiles=[tile]) 25 | cfg.setup() 26 | nodes = ["{}_VPSX{:02}00".format(rc, i) for i in range(16)] 27 | fuzz_interconnect(config=cfg, nodenames=nodes, regex=False, bidir=False, full_mux_style=False) 28 | for tile, rc in hrow_cfgs: 29 | cfg = FuzzConfig(job="ROWROUTE", device="LIFCL-40", sv="../shared/route_40.v", tiles=[tile]) 30 | cfg.setup() 31 | nodes = ["{}_HPRX{:02}00".format(rc, i) for i in range(16)] 32 | fuzz_interconnect(config=cfg, nodenames=nodes, regex=False, bidir=False, full_mux_style=False) 33 | for tile, rcs in trunk_cfgs: 34 | cfg = FuzzConfig(job="TRUNKROUTE", device="LIFCL-40", sv="../shared/route_40.v", tiles=[tile]) 35 | cfg.setup() 36 | nodes = ["{}HPRX{}".format(rcs, i) for i in range(16)] 37 | fuzz_interconnect(config=cfg, nodenames=nodes, regex=False, bidir=False, full_mux_style=False) 38 | 39 | 40 | 41 | 42 | if __name__ == "__main__": 43 | main() 44 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/024-dcc-dcs/dcc.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="${dev}", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \dm:primitive ="DCC", \dm:programming ="DCC:::DCCEN=${dccen}", \dm:site ="${site}" *) 7 | DCC DCC_I ( ); 8 | 9 | // A primitive is needed, but VHI should be harmless 10 | (* \xref:LOG ="q_c@0@9" *) 11 | VHI vhi_i(); 12 | endmodule 13 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/024-dcc-dcs/dcs.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="${dev}", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \dm:primitive ="DCS", \dm:programming ="DCS:::DCSMODE=${dcsmode}", \dm:site ="${site}" *) 7 | DCS DCS_I ( ); 8 | 9 | // A primitive is needed, but VHI should be harmless 10 | (* \xref:LOG ="q_c@0@9" *) 11 | VHI vhi_i(); 12 | endmodule 13 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/024-dcc-dcs/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | import nonrouting 3 | import fuzzloops 4 | import re 5 | 6 | def main(): 7 | # 40k 8 | dev = "LIFCL-40" 9 | sv = "../shared/empty_40.v" 10 | dcc_tiles = ["CIB_R28C0:LMID", "CIB_R28C87:RMID_DLY20", "CIB_R56C49:BMID_0_ECLK_1", "CIB_R56C50:BMID_1_ECLK_2", 11 | "CIB_R0C49:TMID_0", "CIB_R0C50:TMID_1", "CIB_R29C49:CMUX_0", "CIB_R29C50:CMUX_1", "CIB_R38C49:CMUX_2", "CIB_R38C50:CMUX_3"] 12 | dcs_tiles = ["CIB_R29C49:CMUX_0", "CIB_R29C50:CMUX_1", "CIB_R38C49:CMUX_2", "CIB_R38C50:CMUX_3"] 13 | dcc_prims = ["DCC_L{}".format(i) for i in range(12)] + \ 14 | ["DCC_R{}".format(i) for i in range(12)] + \ 15 | ["DCC_T{}".format(i) for i in range(16)] + \ 16 | ["DCC_B{}".format(i) for i in range(18)] + \ 17 | ["DCC_C{}".format(i) for i in range(4)] 18 | dcs_prims = ["DCS0", ] 19 | 20 | def per_site(site): 21 | if site.startswith("DCC"): 22 | cfg = FuzzConfig(job=site, device=dev, sv=sv, tiles=dcc_tiles) 23 | cfg.setup() 24 | empty = cfg.build_design(cfg.sv, {}) 25 | cfg.sv = "dcc.v" 26 | def get_substs(dccen): 27 | return dict(dev=dev, site=site, dccen=dccen) 28 | nonrouting.fuzz_enum_setting(cfg, empty, "{}.DCCEN".format(site), ["0", "1"], 29 | lambda x: get_substs(x), False, 30 | desc="DCC bypassed (0) or used as gate (1)") 31 | else: 32 | assert site.startswith("DCS") 33 | cfg = FuzzConfig(job=site, device=dev, sv=sv, tiles=dcs_tiles) 34 | cfg.setup() 35 | empty = cfg.build_design(cfg.sv, {}) 36 | cfg.sv = "dcs.v" 37 | def get_substs(dcsmode): 38 | return dict(dev=dev, site=site, dcsmode=dcsmode) 39 | nonrouting.fuzz_enum_setting(cfg, empty, "{}.DCSMODE".format(site), 40 | ["GND", "DCS", "DCS_1", "BUFGCECLK0", "BUFGCECLK0_1", "BUFGCECLK1", "BUFGCECLK1_1", "BUF0", "BUF1", "VCC"], 41 | lambda x: get_substs(x), False, 42 | desc="clock selector mode") 43 | fuzzloops.parallel_foreach(dcc_prims + dcs_prims, per_site) 44 | 45 | #17k 46 | dev = "LIFCL-17" 47 | sv = "../shared/empty_17.v" 48 | dcc_prims = ["DCC_L{}".format(i) for i in range(12)] + \ 49 | ["DCC_R{}".format(i) for i in range(12)] + \ 50 | ["DCC_T{}".format(i) for i in range(16)] 51 | dcc_tiles = ["CIB_R10C0:LMID_RBB_5_15K", "CIB_R10C75:RMID_PICB_DLY10", "CIB_R0C37:TMID_0", "CIB_R0C38:TMID_1_15K", "CIB_R0C39:CLKBUF_T_15K"] 52 | fuzzloops.parallel_foreach(dcc_prims, per_site) 53 | 54 | if __name__ == '__main__': 55 | main() 56 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/031-io_mode/iob_17.v: -------------------------------------------------------------------------------- 1 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-17", \db:package ="CABGA256", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 2 | module top ( 3 | ${cmt} ${pintype} q 4 | ); 5 | 6 | // A primitive is needed, but VHI should be harmless 7 | (* \xref:LOG ="q_c@0@9" *) 8 | VHI vhi_i(); 9 | 10 | (* \xref:LOG ="q_c@0@9" *) 11 | wire q_c; 12 | 13 | ${cmt}(* \xref:LOG ="${primtype}=q_pad.bb_inst@0@8", \dm:cellmodel_primitives ="${primtype}=q_pad.bb_inst", \dm:primitive ="${primtype}", \dm:programming ="MODE:${primtype} ${primtype}:::IO_TYPE=${iotype},BANK_VCCIO=${vcc}${extra_config}:T=${t}", \dm:site ="${site}" *) 14 | ${cmt}${primtype} \q_pad.bb_inst (.PADDO(q_c)); 15 | 16 | endmodule 17 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/031-io_mode/iob_40.v: -------------------------------------------------------------------------------- 1 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="CABGA400", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 2 | module top ( 3 | ${cmt} ${pintype} q 4 | ); 5 | 6 | // A primitive is needed, but VHI should be harmless 7 | (* \xref:LOG ="q_c@0@9" *) 8 | VHI vhi_i(); 9 | 10 | (* \xref:LOG ="q_c@0@9" *) 11 | wire q_c; 12 | 13 | ${cmt}(* \xref:LOG ="${primtype}=q_pad.bb_inst@0@8", \dm:cellmodel_primitives ="${primtype}=q_pad.bb_inst", \dm:primitive ="${primtype}", \dm:programming ="MODE:${primtype} ${primtype}:::IO_TYPE=${iotype},BANK_VCCIO=${vcc}${extra_config}:T=${t}", \dm:site ="${site}" *) 14 | ${cmt}${primtype} \q_pad.bb_inst (.PADDO(q_c)); 15 | 16 | endmodule -------------------------------------------------------------------------------- /fuzzers/LIFCL/032-hsio_mode/iob_40.v: -------------------------------------------------------------------------------- 1 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="CABGA400", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 2 | module top ( 3 | ${cmt} ${pintype} q 4 | ); 5 | 6 | // A primitive is needed, but VHI should be harmless 7 | (* \xref:LOG ="q_c@0@9" *) 8 | VHI vhi_i(); 9 | 10 | (* \xref:LOG ="q_c@0@9" *) 11 | wire q_c; 12 | 13 | ${cmt}(* \xref:LOG ="${primtype}=q_pad.bb_inst@0@8", \dm:cellmodel_primitives ="${primtype}=q_pad.bb_inst", \dm:primitive ="${primtype}", \dm:programming ="MODE:${primtype} ${primtype}:::IO_TYPE=${iotype},BANK_VCCIO=${vcc}${extra_config}:T=${t}", \dm:site ="${site}" *) 14 | ${cmt}${primtype} \q_pad.bb_inst (.PADDO(q_c)); 15 | 16 | endmodule -------------------------------------------------------------------------------- /fuzzers/LIFCL/039-copy-io/fuzzer.py: -------------------------------------------------------------------------------- 1 | import database 2 | import libpyprjoxide 3 | 4 | def main(): 5 | db = libpyprjoxide.Database(database.get_db_root()) 6 | libpyprjoxide.copy_db(db, "LIFCL", "SYSIO_B5_1", ["SYSIO_B5_1_V18", "SYSIO_B5_1_15K_DQS51", "SYSIO_B5_1_15K_DQS50", "SYSIO_B5_1_15K_ECLK_L_V52"], "PEWC", "") 7 | libpyprjoxide.copy_db(db, "LIFCL", "SYSIO_B5_0", ["SYSIO_B5_0_15K_DQS52"], "PEWC", "") 8 | libpyprjoxide.copy_db(db, "LIFCL", "SYSIO_B4_0", ["SYSIO_B4_0_DQS1", "SYSIO_B4_0_DQS3", "SYSIO_B4_0_DLY50", "SYSIO_B4_0_DLY42", "SYSIO_B4_0_15K_DQS42", "SYSIO_B4_0_15K_BK4_V42", "SYSIO_B4_0_15K_V31"], "PEWC", "") 9 | libpyprjoxide.copy_db(db, "LIFCL", "SYSIO_B4_1", ["SYSIO_B4_1_DQS0", "SYSIO_B4_1_DQS2", "SYSIO_B4_1_DQS4", "SYSIO_B4_1_DLY52", "SYSIO_B4_1_15K_DQS41"], "PEWC", "") 10 | libpyprjoxide.copy_db(db, "LIFCL", "SYSIO_B3_0", ["SYSIO_B3_0_DLY30_V18", "SYSIO_B3_0_DQS1", "SYSIO_B3_0_DQS3", "SYSIO_B3_0_15K_DQS32"], "PEWC", "") 11 | libpyprjoxide.copy_db(db, "LIFCL", "SYSIO_B3_1", ["SYSIO_B3_1_DLY32", "SYSIO_B3_1_DQS0", "SYSIO_B3_1_DQS2", "SYSIO_B3_1_DQS4", "SYSIO_B3_1_ECLK_R", "SYSIO_B3_1_V18", "SYSIO_B3_1_15K_DQS30", "SYSIO_B3_1_15K_ECLK_R_DQS31"], "PEWC", "") 12 | 13 | libpyprjoxide.copy_db(db, "LIFCL", "SYSIO_B1_0_ODD", ["SYSIO_B1_0_C"], "C", "") 14 | libpyprjoxide.copy_db(db, "LIFCL", "SYSIO_B2_0_ODD", ["SYSIO_B2_0_C"], "C", "") 15 | libpyprjoxide.copy_db(db, "LIFCL", "SYSIO_B6_0_ODD", ["SYSIO_B6_0_C"], "C", "") 16 | libpyprjoxide.copy_db(db, "LIFCL", "SYSIO_B7_0_ODD", ["SYSIO_B7_0_C"], "C", "") 17 | 18 | if __name__ == '__main__': 19 | main() 20 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/040-speed/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | import nonrouting 3 | import fuzzloops 4 | import re 5 | import database 6 | 7 | speed_map = { 8 | "FAST_1V0": "7_High-Performance_1.0V", 9 | "SLOW_1V0": "7_Low-Power_1.0V", 10 | } 11 | 12 | all_tiles_40 = set(database.get_tilegrid("LIFCL", "LIFCL-40")["tiles"].keys()) 13 | 14 | cfg = FuzzConfig(job="SPEED", device="LIFCL-40", sv="../shared/empty_40.v", tiles=all_tiles_40) 15 | #cfg = FuzzConfig(job="SPEED", device="LIFCL-40", sv="../shared/empty_40.v", tiles=set(["CIB_R43C0:RBB_12"])) 16 | 17 | 18 | def main(): 19 | cfg.setup() 20 | empty = cfg.build_design(cfg.sv, {}) 21 | cfg.sv = "speed_40.v" 22 | nonrouting.fuzz_enum_setting(cfg, empty, "CHIP.SPEED", ["SLOW_1V0", "FAST_1V0"], 23 | lambda x: {"speed": speed_map[x]}, True, 24 | desc="Adjust back bias for high speed or low power") 25 | if __name__ == "__main__": 26 | main() 27 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/040-speed/speed_40.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="${speed}", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | // A primitive is needed, but VHI should be harmless 7 | (* \xref:LOG ="q_c@0@9" *) 8 | VHI vhi_i(); 9 | endmodule 10 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/050-cib-special/cib_iomux_40.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \xref:LOG ="q_c@0@9"${arcs_attr} *) 7 | wire q; 8 | 9 | (* \xref:LOG ="q_c@0@10", \dm:arcs ="${extra_arc}" *) 10 | wire q2; 11 | 12 | (* \dm:cellmodel_primitives ="REG0=reg", \dm:primitive ="SLICE", \dm:programming ="MODE:LOGIC Q0:Q0 ", \dm:site ="R2C2A" *) 13 | SLICE SLICE_I ( .A0(q), .Q0(q), .A1(q2), .Q1(q2) ); 14 | endmodule 15 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/050-cib-special/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | import nonrouting 3 | from interconnect import fuzz_interconnect 4 | import lapie 5 | import re 6 | import fuzzloops 7 | 8 | configs = [ 9 | ((46, 6), FuzzConfig(job="CIBENABLE", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R46C6:CIB"])), 10 | ((1, 18), FuzzConfig(job="CIBTENABLE", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R1C18:CIB_T"])), 11 | ((23, 86), FuzzConfig(job="CIBLRENABLE", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R23C86:CIB_LR"])), 12 | ((37, 86), FuzzConfig(job="CIBLRAENABLE", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R37C86:CIB_LR_A", "CIB_R38C86:CIB_LR_B"])), 13 | ] 14 | 15 | def main(): 16 | def per_cib(cib): 17 | rc, cfg = cib 18 | cfg.setup() 19 | empty = cfg.build_design(cfg.sv, {}) 20 | r, c = rc 21 | # CIB F/Q "used" bits 22 | nodes = ["R{}C{}_JF{}".format(r, c, i) for i in range(8)] 23 | nodes += ["R{}C{}_JQ{}".format(r, c, i) for i in range(8)] 24 | 25 | node_data = lapie.get_node_data(cfg.udb, nodes) 26 | for n in node_data: 27 | to_wire = n.name 28 | setting_name = to_wire.split("_")[1] + "_USED" 29 | from_wire = None 30 | for p in n.uphill_pips: 31 | if "CIBTEST" not in p.from_wire: 32 | from_wire = p.from_wire 33 | break 34 | assert from_wire is not None 35 | arcs_attr = r', \dm:arcs ="{}.{}"'.format(to_wire, from_wire) 36 | nonrouting.fuzz_enum_setting(cfg, empty, "CIB." + setting_name, ["NO", "YES"], 37 | lambda x: dict(arcs_attr=arcs_attr) if x == "YES" else {}, False) 38 | 39 | # CIBMUXIN -> CIBMUXOUT 40 | cfg.sv = "cib_iomux_40.v" 41 | for x in ("A", "B", "C", "D"): 42 | # Stop Radiant trying to tie unused outputs; as this causes weird bit patterns 43 | extra_arcs = [] 44 | for i in range(8): 45 | for x2 in ("A", "B", "C", "D"): 46 | if x2 == x: 47 | continue 48 | extra_arcs.append("R{r}C{c}_JCIBMUXOUT{x}{i}.R{r}C{c}_JCIBMUXINA{i}".format(r=r, c=c, x=x2, i=i)) 49 | cibmuxout = ["R{}C{}_JCIBMUXOUT{}{}".format(r, c, x, i) for i in range(8)] 50 | fuzz_interconnect(config=cfg, nodenames=cibmuxout, regex=False, bidir=False, full_mux_style=True, 51 | extra_substs=dict(extra_arc=" ".join(extra_arcs))) 52 | fuzzloops.parallel_foreach(configs, per_cib) 53 | if __name__ == "__main__": 54 | main() 55 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/060-ebr-config/ebr.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | ${cmt} (* \dm:primitive ="EBR_CORE", \dm:programming ="MODE:${mode} ${config}", \dm:site ="${site}" *) 7 | ${cmt} EBR_CORE EBR_I ( ); 8 | 9 | // A primitive is needed, but VHI should be harmless 10 | (* \xref:LOG ="q_c@0@9" *) 11 | VHI vhi_i(); 12 | endmodule 13 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/061-ebr-routing/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import re 4 | 5 | configs = [ 6 | { 7 | "cfg": FuzzConfig(job="EBRROUTE0", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R29C15:EBR_1", "CIB_R29C16:EBR_2", "CIB_R29C14:MIB_EBR"]), 8 | "rc": (28, 14), 9 | }, 10 | { 11 | "cfg": FuzzConfig(job="EBRROUTE1", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R29C18:EBR_4", "CIB_R29C19:EBR_5", "CIB_R29C17:MIB_EBR"]), 12 | "rc": (28, 17), 13 | }, 14 | { 15 | "cfg": FuzzConfig(job="EBRROUTE2", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R29C21:EBR_7", "CIB_R29C22:EBR_8", "CIB_R29C23:EBR_9", "CIB_R29C24:EBR_10", "CIB_R29C20:MIB_EBR"]), 16 | "rc": (28, 20), 17 | }, 18 | { 19 | "cfg": FuzzConfig(job="EBRROUTE3", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R29C23:EBR_9", "CIB_R29C21:EBR_7", "CIB_R29C22:EBR_8", "CIB_R29C24:EBR_10", "CIB_R29C20:MIB_EBR"]), 20 | "rc": (28, 22), 21 | }, 22 | ] 23 | 24 | ignore_tiles = set([ 25 | "CIB_R28C{}:CIB".format(c) for c in range(14, 27) 26 | ]) 27 | 28 | def main(): 29 | for config in configs: 30 | cfg = config["cfg"] 31 | cfg.setup() 32 | r, c = config["rc"] 33 | nodes = ["R{}C{}_*".format(r, c)] 34 | def nodename_filter(x, nodes): 35 | return ("R{}C{}_".format(r, c) in x) and ("EBR_CORE" in x) 36 | fuzz_interconnect(config=cfg, nodenames=nodes, nodename_predicate=nodename_filter, regex=True, bidir=True, ignore_tiles=ignore_tiles) 37 | 38 | if __name__ == "__main__": 39 | main() 40 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/062-lram-config/lram.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="${device}", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | ${cmt} (* \dm:primitive ="LRAM_CORE", \dm:programming ="MODE:LRAM_CORE ${config}", \dm:site ="${site}" *) 7 | ${cmt} LRAM_CORE LRAM_I ( ); 8 | 9 | // A primitive is needed, but VHI should be harmless 10 | (* \xref:LOG ="q_c@0@9" *) 11 | VHI vhi_i(); 12 | endmodule 13 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/063-lram-routing/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import re 4 | 5 | configs = [ 6 | { 7 | "cfg": FuzzConfig(job="LRAMROUTE0", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R23C87:LRAM_0"]), 8 | "rc": (18, 86), 9 | }, 10 | { 11 | "cfg": FuzzConfig(job="LRAMROUTE1", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R41C87:LRAM_1"]), 12 | "rc": (40, 86), 13 | }, 14 | 15 | { 16 | "cfg": FuzzConfig(job="LRAMROUTE17_0", device="LIFCL-17", sv="../shared/route_17.v", tiles=["CIB_R15C75:LRAM_0_15K"]), 17 | "rc": (15, 74), 18 | }, 19 | { 20 | "cfg": FuzzConfig(job="LRAMROUTE17_1", device="LIFCL-17", sv="../shared/route_17.v", tiles=["CIB_R16C75:LRAM_1_15K"]), 21 | "rc": (16, 74), 22 | }, 23 | { 24 | "cfg": FuzzConfig(job="LRAMROUTE17_2", device="LIFCL-17", sv="../shared/route_17.v", tiles=["CIB_R3C0:LRAM_2_15K"]), 25 | "rc": (2, 0), 26 | }, 27 | { 28 | "cfg": FuzzConfig(job="LRAMROUTE17_3", device="LIFCL-17", sv="../shared/route_17.v", tiles=["CIB_R12C0:LRAM_3_15K"]), 29 | "rc": (11, 0), 30 | }, 31 | { 32 | "cfg": FuzzConfig(job="LRAMROUTE17_4", device="LIFCL-17", sv="../shared/route_17.v", tiles=["CIB_R21C0:LRAM_4_15K"]), 33 | "rc": (20, 0), 34 | }, 35 | ] 36 | 37 | ignore_tiles = set([ 38 | "CIB_R{}C86:CIB_LR".format(c) for c in range(2, 55) 39 | ] + [ 40 | "CIB_R19C86:CIB_LR_A", 41 | "CIB_R20C86:CIB_LR_B", 42 | "CIB_R28C86:CIB_LR_A", 43 | "CIB_R37C86:CIB_LR_A", 44 | "CIB_R46C86:CIB_LR_A", 45 | ]) 46 | 47 | ignore_tiles_17 = set([ 48 | "CIB_R{}C74:CIB_LR".format(c) for c in range(2, 29) 49 | ] + [ 50 | "CIB_R{}C1:CIB_LR".format(c) for c in range(2, 29) 51 | ] + [ 52 | "CIB_R1C1:CIB_T", 53 | "CIB_R10C1:CIB_LR_A", 54 | "CIB_R19C1:CIB_LR_A", 55 | "CIB_R19C74:CIB_LR_A", 56 | "CIB_R10C74:CIB_LR_A" 57 | ]) 58 | 59 | def main(): 60 | for config in configs: 61 | cfg = config["cfg"] 62 | cfg.setup() 63 | r, c = config["rc"] 64 | nodes = ["R{}C{}_*".format(r, c)] 65 | def nodename_filter(x, nodes): 66 | return ("R{}C{}_".format(r, c) in x) and ("LRAM_CORE" in x) 67 | fuzz_interconnect(config=cfg, nodenames=nodes, nodename_predicate=nodename_filter, regex=True, bidir=True, ignore_tiles=ignore_tiles_17 if cfg.device == "LIFCL-17" else ignore_tiles) 68 | 69 | if __name__ == "__main__": 70 | main() 71 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/067-copy-ebr/fuzzer.py: -------------------------------------------------------------------------------- 1 | import database 2 | import libpyprjoxide 3 | 4 | def main(): 5 | db = libpyprjoxide.Database(database.get_db_root()) 6 | libpyprjoxide.copy_db(db, "LIFCL", "EBR_10", ["TRUNK_L_EBR_10", ], "PEWC", "") 7 | 8 | if __name__ == '__main__': 9 | main() 10 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/070-iologic_mode/iologic_17.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-17", \db:package ="CABGA256", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | ${cmt} (* \dm:primitive ="${s}IOLOGIC_CORE", \dm:programming ="MODE:${mode} ${config}", \dm:site ="${site}" *) 7 | ${cmt} ${s}IOLOGIC_CORE EBR_I (${pinconn} ); 8 | ${sig} 9 | // A primitive is needed, but VHI should be harmless 10 | (* \xref:LOG ="q_c@0@9" *) 11 | VHI vhi_i(); 12 | endmodule 13 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/070-iologic_mode/iologic_40.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | ${cmt} (* \dm:primitive ="${s}IOLOGIC_CORE", \dm:programming ="MODE:${mode} ${config}", \dm:site ="${site}" *) 7 | ${cmt} ${s}IOLOGIC_CORE EBR_I (${pinconn} ); 8 | ${sig} 9 | // A primitive is needed, but VHI should be harmless 10 | (* \xref:LOG ="q_c@0@9" *) 11 | VHI vhi_i(); 12 | endmodule 13 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/071-iodelay/iodelay.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \dm:primitive ="${s}IOLOGIC_CORE", \dm:programming ="MODE:${mode} ${config}", \dm:site ="${site}" *) 7 | ${s}IOLOGIC_CORE EBR_I (${pinconn} ); 8 | ${sig} 9 | // A primitive is needed, but VHI should be harmless 10 | (* \xref:LOG ="q_c@0@9" *) 11 | VHI vhi_i(); 12 | endmodule 13 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/080-dsp-config/dsp.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | ${cmt} (* \dm:primitive ="${prim}", \dm:programming ="MODE:${mode} ${config}", \dm:site ="${site}" *) 7 | ${cmt} ${prim} EBR_I ( ); 8 | 9 | // A primitive is needed, but VHI should be harmless 10 | (* \xref:LOG ="q_c@0@9" *) 11 | VHI vhi_i(); 12 | endmodule 13 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/081-dsp-routing/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import re 4 | 5 | configs = [ 6 | { 7 | "cfg": FuzzConfig(job="DSPROUTE0", device="LIFCL-40", sv="../shared/route_40.v", tiles=[ 8 | "CIB_R38C63:DSP_R_1", "CIB_R38C62:MIB_EBR", "CIB_R38C64:DSP_R_2", 9 | "CIB_R38C65:DSP_R_3", "CIB_R38C66:DSP_R_4", "CIB_R38C67:DSP_R_5", 10 | "CIB_R38C68:DSP_R_6", "CIB_R38C69:DSP_R_7", "CIB_R38C70:DSP_R_8", 11 | "CIB_R38C71:DSP_R_9", "CIB_R38C72:DSP_R_10", "CIB_R38C73:DSP_R_11", 12 | ]), 13 | "rc": (37, 63), 14 | }, 15 | { 16 | "cfg": FuzzConfig(job="DSPROUTE1", device="LIFCL-40", sv="../shared/route_40.v", tiles=[ 17 | "CIB_R38C14:DSP_L_0", "CIB_R38C13:MIB_EBR", "CIB_R38C15:DSP_L_1", 18 | "CIB_R38C16:DSP_L_2", "CIB_R38C17:DSP_L_3", "CIB_R38C18:DSP_L_4", 19 | "CIB_R38C19:DSP_L_5", "CIB_R38C20:DSP_L_6", "CIB_R38C21:DSP_L_7", 20 | "CIB_R38C22:DSP_L_8", "CIB_R38C23:DSP_L_9", "CIB_R38C24:DSP_L_10", 21 | ]), 22 | "rc": (37, 14), 23 | }, 24 | ] 25 | 26 | ignore_tiles = set( 27 | ["CIB_R37C{}:CIB".format(c) for c in range(61, 75)] + 28 | ["CIB_R37C{}:CIB".format(c) for c in range(10, 29)] 29 | ) 30 | 31 | def main(): 32 | for config in configs: 33 | cfg = config["cfg"] 34 | cfg.setup() 35 | r, c = config["rc"] 36 | for c2 in range(c, c + 11): 37 | 38 | # Put fixed connections in the most suitable tile 39 | permuted_tiles = [] 40 | for tile in cfg.tiles: 41 | if "C{}:".format(c2) in tile: 42 | permuted_tiles.append(tile) 43 | for tile in cfg.tiles: 44 | if tile not in permuted_tiles: 45 | permuted_tiles.append(tile) 46 | cfg.tiles = permuted_tiles 47 | 48 | nodes = ["R{}C{}_*".format(r, c2)] 49 | def nodename_filter(x, nodes): 50 | return ("R{}C{}_".format(r, c2) in x) and ("MULT9_CORE" in x or "PREADD9_CORE" in x or "MULT18_CORE" in x or "MULT18X36_CORE" in x or "REG18_CORE" in x or "MULT36_CORE" in x or "ACC54_CORE" in x) 51 | fuzz_interconnect(config=cfg, nodenames=nodes, nodename_predicate=nodename_filter, regex=True, bidir=True, ignore_tiles=ignore_tiles) 52 | 53 | if __name__ == "__main__": 54 | main() 55 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/090-sysconfig/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | import nonrouting 3 | import fuzzloops 4 | import re 5 | 6 | cfgs = [ 7 | FuzzConfig(job="SYSCONFIG40", device="LIFCL-40", sv="../shared/empty_40.v", 8 | tiles=["CIB_R0C75:EFB_0", "CIB_R0C72:BANKREF0", "CIB_R0C77:EFB_1_OSC", "CIB_R0C79:EFB_2", 9 | "CIB_R0C81:I2C_EFB_3", "CIB_R0C85:PMU", "CIB_R0C87:MIB_CNR_32_FAFD", "CIB_R1C87:IREF_P33", "CIB_R2C87:POR"]), 10 | FuzzConfig(job="SYSCONFIG17", device="LIFCL-17", sv="../shared/empty_17.v", 11 | tiles=["CIB_R1C75:IREF_15K", "CIB_R0C75:PPT_QOUT_15K", "CIB_R0C74:PVTCAL33_15K", "CIB_R0C73:POR_15K", 12 | "CIB_R0C72:I2C_15K", "CIB_R0C71:OSC_15K", "CIB_R0C70:PMU_15K", "CIB_R0C66:EFB_15K"]) 13 | ] 14 | 15 | def main(): 16 | for cfg in cfgs: 17 | cfg.setup() 18 | empty = cfg.build_design(cfg.sv, {}) 19 | cfg.sv = "../shared/empty_presyn_40.v" 20 | cfg.struct_mode = False 21 | def get_substs(k, v): 22 | return dict(sysconfig="{}={}".format(k, v)) 23 | nonrouting.fuzz_enum_setting(cfg, empty, "SYSCONFIG.MASTER_SPI_PORT", ["DISABLE", "SERIAL", "DUAL", "QUAD"], 24 | lambda x: get_substs("MASTER_SPI_PORT", x), False, 25 | assume_zero_base=True, 26 | desc="status of master SPI port after configuration") 27 | nonrouting.fuzz_enum_setting(cfg, empty, "SYSCONFIG.SLAVE_SPI_PORT", ["DISABLE", "SERIAL", "DUAL", "QUAD"], 28 | lambda x: get_substs("SLAVE_SPI_PORT", x), False, 29 | assume_zero_base=True, 30 | desc="status of slave SPI port after configuration") 31 | nonrouting.fuzz_enum_setting(cfg, empty, "SYSCONFIG.SLAVE_I2C_PORT", ["DISABLE", "ENABLE"], 32 | lambda x: get_substs("SLAVE_I2C_PORT", x), False, 33 | assume_zero_base=True, 34 | desc="status of slave I2C port after configuration") 35 | nonrouting.fuzz_enum_setting(cfg, empty, "SYSCONFIG.SLAVE_I3C_PORT", ["DISABLE", "ENABLE"], 36 | lambda x: get_substs("SLAVE_I3C_PORT", x), False, 37 | assume_zero_base=True, 38 | desc="status of slave I3C port after configuration") 39 | nonrouting.fuzz_enum_setting(cfg, empty, "SYSCONFIG.JTAG_PORT", ["DISABLE", "ENABLE"], 40 | lambda x: get_substs("JTAG_PORT", x), False, 41 | assume_zero_base=True, 42 | desc="status of JTAG port after configuration") 43 | nonrouting.fuzz_enum_setting(cfg, empty, "SYSCONFIG.DONE_PORT", ["DISABLE", "ENABLE"], 44 | lambda x: get_substs("DONE_PORT", x), False, 45 | assume_zero_base=True, 46 | desc="use DONE output after configuration") 47 | nonrouting.fuzz_enum_setting(cfg, empty, "SYSCONFIG.INITN_PORT", ["DISABLE", "ENABLE"], 48 | lambda x: get_substs("INITN_PORT", x), False, 49 | assume_zero_base=True, 50 | desc="use INITN input after configuration") 51 | nonrouting.fuzz_enum_setting(cfg, empty, "SYSCONFIG.PROGRAMN_PORT", ["DISABLE", "ENABLE"], 52 | lambda x: get_substs("PROGRAMN_PORT", x), False, 53 | assume_zero_base=True, 54 | desc="use PROGRAMN input after configuration") 55 | if __name__ == "__main__": 56 | main() 57 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/091-osc/osc.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | ${cmt} (* \dm:primitive ="OSC_CORE", \dm:programming ="MODE:OSC_CORE ${config}", \dm:site ="OSC_CORE_R1C77" *) 7 | ${cmt} OSC_CORE OSC_I ( ); 8 | 9 | // A primitive is needed, but VHI should be harmless 10 | (* \xref:LOG ="q_c@0@9" *) 11 | VHI vhi_i(); 12 | endmodule 13 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/091-osc/osc_17.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-17", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | ${cmt} (* \dm:primitive ="OSC_CORE", \dm:programming ="MODE:OSC_CORE ${config}", \dm:site ="OSC_CORE_R1C71" *) 7 | ${cmt} OSC_CORE OSC_I ( ); 8 | 9 | // A primitive is needed, but VHI should be harmless 10 | (* \xref:LOG ="q_c@0@9" *) 11 | VHI vhi_i(); 12 | endmodule 13 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/092-gsr/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | import nonrouting 3 | import fuzzloops 4 | import re 5 | from interconnect import fuzz_interconnect 6 | 7 | cfg = FuzzConfig(job="GSR", device="LIFCL-40", sv="../shared/empty_40.v", tiles=["CIB_R29C49:CMUX_0", "CIB_R29C50:CMUX_1"]) 8 | 9 | def main(): 10 | cfg.setup() 11 | empty = cfg.build_design(cfg.sv, {}) 12 | cfg.sv = "gsr.v" 13 | 14 | def bin_to_int(x): 15 | val = 0 16 | mul = 1 17 | for bit in x: 18 | if bit: 19 | val |= mul 20 | mul *= 2 21 | return val 22 | 23 | def get_substs(mode="NONE", default_cfg=False, kv=None, mux=False): 24 | if kv is None: 25 | config = "" 26 | elif mux: 27 | val = "#SIG" 28 | if kv[1] in ("0", "1"): 29 | val = kv[1] 30 | if kv[1] == "INV": 31 | val = "#INV" 32 | config = "{}::::{}={}".format(mode, kv[0], val) 33 | else: 34 | config = "{}:::{}={}".format(mode, kv[0], kv[1]) 35 | return dict(mode=mode, cmt="//" if mode == "NONE" else "", config=config) 36 | nonrouting.fuzz_enum_setting(cfg, empty, "GSR_CORE.MODE", ["NONE", "GSR_CORE"], 37 | lambda x: get_substs(mode=x), False, 38 | desc="GSR_CORE primitive mode") 39 | 40 | nonrouting.fuzz_enum_setting(cfg, empty, "GSR_CORE.GSR", ["ENABLED", "DISABLED"], 41 | lambda x: get_substs(mode="GSR_CORE", kv=("GSR", x)), False, 42 | desc="enable global set/reset") 43 | nonrouting.fuzz_enum_setting(cfg, empty, "GSR_CORE.GSR_SYNC", ["ASYNC", "SYNC"], 44 | lambda x: get_substs(mode="GSR_CORE", kv=("GSR_SYNC", x)), False, 45 | desc="synchronise global set/reset") 46 | 47 | nonrouting.fuzz_enum_setting(cfg, empty, "GSR_CORE.CLKMUX", ["CLK", "INV"], 48 | lambda x: get_substs(mode="GSR_CORE", kv=("CLK", x), mux=True), False, 49 | desc="") 50 | nonrouting.fuzz_enum_setting(cfg, empty, "GSR_CORE.GSR_NMUX", ["GSR_N", "INV"], 51 | lambda x: get_substs(mode="GSR_CORE", kv=("GSR_N", x), mux=True), False, 52 | desc="") 53 | # Fuzz GSR routing 54 | cfg.sv = "../shared/route_40.v" 55 | nodes = ["R28C49_JGSR_N_GSR_CORE_GSR_CENTER", "R28C49_JCLK_GSR_CORE_GSR_CENTER", "R28C49_JGSROUT_GSR_CORE_GSR_CENTER"] 56 | fuzz_interconnect(config=cfg, nodenames=nodes, regex=False, bidir=True, full_mux_style=False) 57 | 58 | if __name__ == '__main__': 59 | main() 60 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/092-gsr/gsr.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | ${cmt} (* \dm:primitive ="GSR_CORE", \dm:programming ="MODE:GSR_CORE ${config}", \dm:site ="GSR_CORE_R28C49" *) 7 | ${cmt} GSR_CORE GSR_I ( ); 8 | 9 | // A primitive is needed, but VHI should be harmless 10 | (* \xref:LOG ="q_c@0@9" *) 11 | VHI vhi_i(); 12 | endmodule 13 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/100-ip-base/fuzzer.py: -------------------------------------------------------------------------------- 1 | import fuzzconfig 2 | import nonrouting 3 | import fuzzloops 4 | import database 5 | from os import path 6 | import libpyprjoxide 7 | import json 8 | 9 | cfgs = [ 10 | # (fuzzconfig.FuzzConfig(job="IPADDR", device="LIFCL-40", sv="ip.v", tiles=[]), 11 | # [ 12 | # ("TDPHY_CORE2", "DPHY_CORE"), 13 | # ("TDPHY_CORE26", "DPHY_CORE"), 14 | # ("PLL_LLC", "PLL_CORE"), 15 | # ("PLL_LRC", "PLL_CORE"), 16 | # ("PLL_ULC", "PLL_CORE"), 17 | # ("PMU_CORE_R1C85", "PMU_CORE"), 18 | # ("LSGMIICDR_CORE51", "SGMIICDR_CORE"), 19 | # ("LSGMIICDR_CORE52", "SGMIICDR_CORE"), 20 | # ("I2CFIFO_CORE_R1C81", "I2CFIFO_CORE"), 21 | # ("TPCIE_CORE57", "PCIE_CORE"), 22 | # ("EBR_CORE_R28C26", "EBR_CORE_WID0"), 23 | # ("EBR_CORE_R28C26", "EBR_CORE_WID1"), 24 | # ("EBR_CORE_R28C26", "EBR_CORE_WID2047"), 25 | # ("LRAM_CORE_R18C86", "LRAM_CORE"), 26 | # ("LRAM_CORE_R40C86", "LRAM_CORE"), 27 | # ] 28 | # ), 29 | (fuzzconfig.FuzzConfig(job="IPADDR17", device="LIFCL-17", sv="ip.v", tiles=[]), 30 | [ 31 | ("DPHY0", "DPHY_CORE"), 32 | ("DPHY1", "DPHY_CORE"), 33 | ("PLL_LLC", "PLL_CORE"), 34 | ("PLL_LRC", "PLL_CORE"), 35 | ("PMU_CORE_R1C70", "PMU_CORE"), 36 | ("SGMIICDR_CORE_R28C5", "SGMIICDR_CORE"), 37 | ("SGMIICDR_CORE_R28C4", "SGMIICDR_CORE"), 38 | ("I2CFIFO_CORE_R1C72", "I2CFIFO_CORE"), 39 | ("EBR_CORE_R10C5", "EBR_CORE_WID0"), 40 | ("EBR_CORE_R10C5", "EBR_CORE_WID1"), 41 | ("EBR_CORE_R10C5", "EBR_CORE_WID2047"), 42 | ("LRAM_CORE_R2C1", "LRAM_CORE"), 43 | ("LRAM_CORE_R11C1", "LRAM_CORE"), 44 | ("LRAM_CORE_R20C1", "LRAM_CORE"), 45 | ("LRAM_CORE_R15C74", "LRAM_CORE"), 46 | ("LRAM_CORE_R16C74", "LRAM_CORE"), 47 | ] 48 | ) 49 | ] 50 | 51 | # Config to make sure we get at least one IP bit set 52 | ip_settings = { 53 | "EBR_CORE_WID0": "EBR_CORE:::WID=0b00000000000", 54 | "EBR_CORE_WID1": "EBR_CORE:::WID=0b00000000001", 55 | "EBR_CORE_WID2047": "EBR_CORE:::WID=0b11111111111", 56 | "DPHY_CORE": "DPHY_CORE:::U_PRG_HS_TRAIL=0b000001", 57 | "PLL_CORE": "PLL_CORE:::DIVA=1", 58 | "PMU_CORE": "PMU_CORE:::WKCOUNT0=0b00000001", 59 | "SGMIICDR_CORE": "SGMIICDR_CORE:::DCOITUNE4LSB=15_PERCENT", 60 | "I2CFIFO_CORE": "I2CFIFO_CORE:::I2CSLVADDRA=0b0000000001", 61 | "PCIE_CORE": "PCIE_CORE:::PHY_MODE=0b0001", 62 | "LRAM_CORE": "LRAM_CORE:::CFG_INIT_ID=0b00000000000", 63 | } 64 | 65 | ip_abits = { 66 | "DPHY_CORE": 5, 67 | "PLL_CORE": 7, 68 | "PMU_CORE": 4, 69 | "SGMIICDR_CORE": 4, 70 | "I2CFIFO_CORE": 6, 71 | "PCIE_CORE": 17, 72 | "EBR_CORE": 17, 73 | "LRAM_CORE": 17, 74 | } 75 | 76 | def main(): 77 | for cfg, ip_sites in cfgs: 78 | cfg.setup(skip_specimen=True) 79 | ip_base = {} 80 | for site, prim in ip_sites: 81 | prim_type = prim 82 | wid_idx = prim_type.find("_WID") 83 | if wid_idx != -1: 84 | prim_type = prim_type[0:wid_idx] 85 | bit = cfg.build_design(cfg.sv, dict(cmt="", prim=prim_type, site=site, config=ip_settings[prim])) 86 | chip = libpyprjoxide.Chip.from_bitstream(fuzzconfig.db, bit) 87 | ipv = chip.get_ip_values() 88 | assert len(ipv) > 0 89 | addr = ipv[0][0] 90 | ip_name = site 91 | if "EBR_CORE" in ip_name: 92 | ip_name = prim.replace("_CORE", "") 93 | #if "LRAM_CORE" in ip_name: 94 | # ip_name = "LRAM" 95 | ip_base[ip_name] = { 96 | "addr": addr & ~((1 << ip_abits[prim_type]) - 1), 97 | "abits": ip_abits[prim_type] 98 | } 99 | with open(path.join(database.get_db_root(), "LIFCL", cfg.device, "baseaddr.json"), "w") as jf: 100 | print(json.dumps(dict(regions=ip_base), sort_keys=True, indent=4), file=jf) 101 | 102 | if __name__ == "__main__": 103 | main() 104 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/100-ip-base/ip.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="${device}", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | ${cmt} (* \dm:primitive ="${prim}", \dm:programming ="MODE:${prim} ${config}", \dm:site ="${site}" *) 7 | ${cmt} ${prim} IP_I ( ); 8 | 9 | // A primitive is needed, but VHI should be harmless 10 | (* \xref:LOG ="q_c@0@9" *) 11 | VHI vhi_i(); 12 | endmodule 13 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/120-pll-routing/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import re 4 | 5 | configs = [ 6 | { 7 | "cfg": FuzzConfig(job="PLLULC", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R0C1:GPLL_ULC"]), 8 | "rc": (1, 1), 9 | }, 10 | { 11 | "cfg": FuzzConfig(job="PLLLLC", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R55C0:GPLL_LLC"]), 12 | "rc": (55, 1), 13 | }, 14 | { 15 | "cfg": FuzzConfig(job="PLLLRC", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R53C87:GPLL_LRC"]), 16 | "rc": (53, 86), 17 | }, 18 | { 19 | "cfg": FuzzConfig(job="PLLLLC_15K", device="LIFCL-17", sv="../shared/route_17.v", tiles=["CIB_R29C1:GPLL_LLC_15K"]), 20 | "rc": (28, 1), 21 | }, 22 | { 23 | "cfg": FuzzConfig(job="PLLLRC_15K", device="LIFCL-17", sv="../shared/route_17.v", tiles=["CIB_R29C74:GPLL_LRC_15K"]), 24 | "rc": (28, 74), 25 | }, 26 | ] 27 | 28 | ignore_tiles = set([ 29 | "CIB_R50C86:CIB_LR" 30 | "CIB_R51C86:CIB_LR", 31 | "CIB_R52C86:CIB_LR", 32 | "CIB_R53C86:CIB_LR", 33 | "CIB_R54C86:CIB_LR", 34 | "CIB_R55C86:CIB", 35 | 36 | "CIB_R55C3:CIB", 37 | "CIB_R55C2:CIB", 38 | "CIB_R55C1:CIB", 39 | "CIB_R54C1:CIB_LR", 40 | "CIB_R53C1:CIB_LR", 41 | "CIB_R52C1:CIB_LR", 42 | 43 | "CIB_R1C3:CIB_T" 44 | "CIB_R1C2:CIB_T", 45 | "CIB_R1C1:CIB_T", 46 | "CIB_R2C1:CIB_LR", 47 | "CIB_R3C1:CIB_LR", 48 | ]) 49 | 50 | ignore_tiles_17 = set([ 51 | "CIB_R26C74:CIB_LR", 52 | "CIB_R27C74:CIB_LR", 53 | "CIB_R28C74:CIB", 54 | "CIB_R28C73:CIB", 55 | "CIB_R28C72:CIB", 56 | "CIB_R26C1:CIB_LR", 57 | "CIB_R27C1:CIB_LR", 58 | "CIB_R28C1:CIB", 59 | "CIB_R28C2:CIB", 60 | "CIB_R28C3:CIB", 61 | ]) 62 | 63 | def main(): 64 | for config in configs: 65 | cfg = config["cfg"] 66 | cfg.setup() 67 | r, c = config["rc"] 68 | nodes = ["R{}C{}_*".format(r, c)] 69 | ignore = ignore_tiles 70 | if cfg.device == "LIFCL-17": 71 | ignore = ignore_tiles_17 72 | def nodename_filter(x, nodes): 73 | return ("R{}C{}_".format(r, c) in x) and ("PLL_CORE" in x or "REFMUX_CORE" in x or "FBMUX_CORE" in x) 74 | fuzz_interconnect(config=cfg, nodenames=nodes, nodename_predicate=nodename_filter, regex=True, bidir=True, 75 | ignore_tiles=ignore) 76 | 77 | if __name__ == "__main__": 78 | main() 79 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/121-pll-ipconfig/pll.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \dm:primitive ="PLL_CORE", \dm:programming ="MODE:PLL_CORE PLL_CORE:::${k}=${v}", \dm:site ="PLL_LLC" *) 7 | PLL_CORE IP_I ( ); 8 | 9 | // A primitive is needed, but VHI should be harmless 10 | (* \xref:LOG ="q_c@0@9" *) 11 | VHI vhi_i(); 12 | endmodule 13 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/121-pll-ipconfig/pll_2.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \dm:primitive ="PLL_CORE", \dm:programming ="MODE:PLL_CORE PLL_CORE:::${k}=${v} PLL_CORE:::${ldt}=${ldt_val}", \dm:site ="PLL_LLC" *) 7 | PLL_CORE IP_I ( ); 8 | 9 | // A primitive is needed, but VHI should be harmless 10 | (* \xref:LOG ="q_c@0@9" *) 11 | VHI vhi_i(); 12 | endmodule 13 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/122-pll-config/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | import nonrouting 3 | import fuzzloops 4 | import re 5 | from interconnect import fuzz_interconnect 6 | 7 | cfgs = [ 8 | ("PLL_LLC", 9 | FuzzConfig(job="PLL_LL", device="LIFCL-40", sv="../shared/empty_40.v", tiles=["CIB_R55C0:GPLL_LLC"]), 10 | ), 11 | ("PLL_ULC", 12 | FuzzConfig(job="PLL_LL", device="LIFCL-40", sv="../shared/empty_40.v", tiles=["CIB_R0C1:GPLL_ULC"]), 13 | ), 14 | ("PLL_LRC", 15 | FuzzConfig(job="PLL_LL", device="LIFCL-40", sv="../shared/empty_40.v", tiles=["CIB_R53C87:GPLL_LRC"]), 16 | ), 17 | ("PLL_LLC", 18 | FuzzConfig(job="PLL_LL", device="LIFCL-17", sv="../shared/empty_17.v", tiles=["CIB_R29C1:GPLL_LLC_15K"]), 19 | ), 20 | ("PLL_LRC", 21 | FuzzConfig(job="PLL_LL", device="LIFCL-17", sv="../shared/empty_17.v", tiles=["CIB_R29C74:GPLL_LRC_15K"]), 22 | ), 23 | ] 24 | 25 | def main(): 26 | for prim, cfg in cfgs: 27 | cfg.setup() 28 | empty = cfg.build_design(cfg.sv, {}) 29 | if cfg.device == "LIFCL-40": 30 | cfg.sv = "pll.v" 31 | else: 32 | cfg.sv = "pll_17.v" 33 | 34 | def bin_to_int(x): 35 | val = 0 36 | mul = 1 37 | for bit in x: 38 | if bit: 39 | val |= mul 40 | mul *= 2 41 | return val 42 | 43 | def get_substs(mode="NONE", default_cfg=False, kv=None, mux=False): 44 | if kv is None: 45 | config = "" 46 | elif mux: 47 | val = "#SIG" 48 | if kv[1] in ("0", "1"): 49 | val = kv[1] 50 | if kv[1] == "INV": 51 | val = "#INV" 52 | config = "{}::::{}={}".format(mode, kv[0], val) 53 | else: 54 | config = "{}:::{}={}".format(mode, kv[0], kv[1]) 55 | return dict(mode=mode, cmt="//" if mode == "NONE" else "", config=config, site=prim) 56 | nonrouting.fuzz_enum_setting(cfg, empty, "{}.MODE".format(prim), ["NONE", "PLL_CORE"], 57 | lambda x: get_substs(mode=x), False, 58 | desc="PLL_CORE primitive mode") 59 | nonrouting.fuzz_enum_setting(cfg, empty, "{}.CLKMUX_FB".format(prim), ["CMUX_CLKOP", "CMUX_CLKOS", "CMUX_CLKOS2", "CMUX_CLKOS3", "CMUX_CLKOS4", "CMUX_CLKOS5"], 60 | lambda x: get_substs(mode="PLL_CORE", kv=("CLKMUX_FB", x)), False, 61 | desc="internal feedback selection") 62 | nonrouting.fuzz_enum_setting(cfg, empty, "{}.LMMICLKMUX".format(prim), ["LMMICLK", "INV"], 63 | lambda x: get_substs(mode="PLL_CORE", kv=("LMMICLK", x), mux=True), False, 64 | desc="") 65 | nonrouting.fuzz_enum_setting(cfg, empty, "{}.LMMIRESETNMUX".format(prim), ["LMMIRESETN", "INV"], 66 | lambda x: get_substs(mode="PLL_CORE", kv=("LMMIRESETN", x), mux=True), False, 67 | desc="") 68 | if __name__ == '__main__': 69 | main() 70 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/122-pll-config/pll.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \xref:LOG ="q_c@0@9" *) 7 | wire foo; 8 | 9 | ${cmt} (* \dm:primitive ="PLL_CORE", \dm:programming ="MODE:PLL_CORE ${config}", \dm:site ="${site}" *) 10 | ${cmt} PLL_CORE IP_I (.STDBY(foo), .PLLRESET(foo), .LEGACY(foo), .LOCK(foo) ); 11 | 12 | // A primitive is needed, but VHI should be harmless 13 | (* \xref:LOG ="q_c@0@9" *) 14 | VHI vhi_i(); 15 | endmodule 16 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/122-pll-config/pll_17.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-17", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \xref:LOG ="q_c@0@9" *) 7 | wire foo; 8 | 9 | ${cmt} (* \dm:primitive ="PLL_CORE", \dm:programming ="MODE:PLL_CORE ${config}", \dm:site ="${site}" *) 10 | ${cmt} PLL_CORE IP_I (.STDBY(foo), .PLLRESET(foo), .LEGACY(foo), .LOCK(foo) ); 11 | 12 | // A primitive is needed, but VHI should be harmless 13 | (* \xref:LOG ="q_c@0@9" *) 14 | VHI vhi_i(); 15 | endmodule 16 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/130-config-ip-routing/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import re 4 | 5 | configs = [ 6 | { 7 | "cfg": FuzzConfig(job="CLKRST", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R0C75:EFB_0", "CIB_R0C77:EFB_1_OSC", "CIB_R0C79:EFB_2", "CIB_R0C81:I2C_EFB_3"]), 8 | "rc": (0, 73), 9 | "keywords": ["CLKRST_CORE", "HSE_CORE", "MULTIBOOT_CORE", "LMMI_CORE", "CONFIG_IP_CORE"] 10 | }, 11 | { 12 | "cfg": FuzzConfig(job="CLKRST", device="LIFCL-17", sv="../shared/route_17.v", tiles=["CIB_R0C66:EFB_15K", "CIB_R0C72:I2C_15K", "CIB_R0C71:OSC_15K", "CIB_R0C70:PMU_15K"]), 13 | "rc": (0, 52), 14 | "keywords": ["CLKRST_CORE", "CRE_CORE", "MULTIBOOT_CORE", "LMMI_CORE", "CONFIG_IP_CORE"] 15 | }, 16 | ] 17 | 18 | ignore_tiles = set([ 19 | "CIB_R1C{}:CIB_T".format(c) for c in range(40, 87) 20 | ]) 21 | 22 | def main(): 23 | for config in configs: 24 | cfg = config["cfg"] 25 | cfg.setup() 26 | r, c = config["rc"] 27 | kws = config["keywords"] 28 | nodes = ["R{}C{}_*".format(r, c)] 29 | def nodename_filter(x, nodes): 30 | return ("R{}C{}_".format(r, c) in x) and any(kw in x for kw in kws) 31 | fuzz_interconnect(config=cfg, nodenames=nodes, nodename_predicate=nodename_filter, regex=True, bidir=True, ignore_tiles=ignore_tiles) 32 | 33 | if __name__ == "__main__": 34 | main() 35 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/131-config-ip/ip.v: -------------------------------------------------------------------------------- 1 | (* \db:architecture ="LIFCL", \db:device ="${device}", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 2 | module top ( 3 | 4 | ); 5 | ${cmt} (* \dm:primitive ="${prim}", \dm:programming ="MODE:${mode} ${config}", \dm:site ="${site}" *) 6 | ${cmt} ${prim} IP_I ( ); 7 | 8 | // A primitive is needed, but VHI should be harmless 9 | (* \xref:LOG ="q_c@0@9" *) 10 | VHI vhi_i(); 11 | endmodule 12 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/140-bram-init/ebr.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \dm:primitive ="EBR_CORE", \dm:programming ="MODE:EBR_CORE EBR_CORE:::WID=0b00000000000,INITVAL_${a}=${v}", \dm:site ="EBR_CORE_R28C26" *) 7 | EBR_CORE EBR_I ( ); 8 | 9 | // A primitive is needed, but VHI should be harmless 10 | (* \xref:LOG ="q_c@0@9" *) 11 | VHI vhi_i(); 12 | endmodule 13 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/140-bram-init/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | import nonrouting 3 | import fuzzloops 4 | import re 5 | 6 | cfg = FuzzConfig(job="EBRINIT", device="LIFCL-40", sv="../shared/empty_40.v", tiles=["EBR_WID0:EBR_INIT"]) 7 | 8 | def bin2dec(bits): 9 | x = 0 10 | for i, b in enumerate(bits): 11 | if b: 12 | x |= (1 << i) 13 | return x 14 | 15 | def main(): 16 | cfg.setup() 17 | cfg.sv = "ebr.v" 18 | def per_word(w): 19 | nonrouting.fuzz_ip_word_setting(cfg, "INITVAL_{:02X}".format(w), 320, lambda b: dict(a="{:02X}".format(w), v="0x{:080x}".format(bin2dec(b)))) 20 | fuzzloops.parallel_foreach(range(0x40), per_word) 21 | if __name__ == "__main__": 22 | main() 23 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/141-lram-init/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | import nonrouting 3 | import fuzzloops 4 | import re 5 | 6 | cfg = FuzzConfig(job="LRAMINIT", device="LIFCL-40", sv="../shared/empty_40.v", tiles=["LRAM_CORE_R18C86:LRAM_INIT"]) 7 | 8 | def bin2dec(bits): 9 | x = 0 10 | for i, b in enumerate(bits): 11 | if b: 12 | x |= (1 << i) 13 | return x 14 | 15 | def main(): 16 | cfg.setup() 17 | cfg.sv = "lram.v" 18 | def per_word(w): 19 | nonrouting.fuzz_ip_word_setting(cfg, "INITVAL_{:02X}".format(w), 5120, lambda b: dict(a="{:02X}".format(w), v="0x{:01280x}".format(bin2dec(b)))) 20 | # Only fuzz a couple of init values to stop the database getting massive - we can derive the rest 21 | fuzzloops.parallel_foreach(range(0x2), per_word) 22 | if __name__ == "__main__": 23 | main() 24 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/141-lram-init/lram.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \dm:primitive ="LRAM_CORE", \dm:programming ="MODE:LRAM_CORE LRAM_CORE:::ECC_BYTE_SEL=BYTE_EN,INITVAL_${a}=${v}", \dm:site ="LRAM_CORE_R18C86" *) 7 | LRAM_CORE LRAM_I ( ); 8 | 9 | // A primitive is needed, but VHI should be harmless 10 | (* \xref:LOG ="q_c@0@9" *) 11 | VHI vhi_i(); 12 | endmodule 13 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/150-eclkroute/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import re 4 | 5 | configs = [ 6 | { 7 | "cfg": FuzzConfig(job="ECLK0", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R56C48:ECLK_0", "CIB_R56C49:BMID_0_ECLK_1", "CIB_R56C50:BMID_1_ECLK_2", "CIB_R56C51:ECLK_3"]), 8 | "rc": (55, 48), 9 | }, 10 | { 11 | "cfg": FuzzConfig(job="ECLK1", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R56C49:BMID_0_ECLK_1", "CIB_R56C48:ECLK_0", "CIB_R56C50:BMID_1_ECLK_2", "CIB_R56C51:ECLK_3"]), 12 | "rc": (55, 49), 13 | }, 14 | { 15 | "cfg": FuzzConfig(job="ECLK2", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R56C50:BMID_1_ECLK_2", "CIB_R56C49:BMID_0_ECLK_1", "CIB_R56C48:ECLK_0", "CIB_R56C51:ECLK_3"]), 16 | "rc": (55, 50), 17 | }, 18 | { 19 | "cfg": FuzzConfig(job="ECLK3", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R56C51:ECLK_3", "CIB_R56C50:BMID_1_ECLK_2", "CIB_R56C49:BMID_0_ECLK_1", "CIB_R56C48:ECLK_0"]), 20 | "rc": (55, 51), 21 | }, 22 | ] 23 | 24 | ignore_tiles = set([ 25 | "CIB_R55C46:CIB" 26 | "CIB_R55C47:CIB", 27 | "CIB_R55C48:CIB", 28 | "CIB_R55C49:CIB", 29 | "CIB_R55C50:CIB", 30 | "CIB_R55C50:CIB", 31 | "CIB_R55C51:CIB", 32 | "CIB_R55C52:CIB", 33 | ]) 34 | 35 | def main(): 36 | for config in configs: 37 | cfg = config["cfg"] 38 | cfg.setup() 39 | r, c = config["rc"] 40 | nodes = ["R{}C{}_*".format(r, c)] 41 | def nodename_filter(x, nodes): 42 | return ("R{}C{}_".format(r, c) in x) and ("ECLK" in x) 43 | def pip_filter(x, nodes): 44 | src, snk = x 45 | return "PLL_CORE" not in src and "FBMUX_CORE" not in src and "FBMUX_CORE" not in snk \ 46 | and "I217" not in snk and "I218" not in snk and "ECLKDDR" not in src \ 47 | and "DQS_TOP" not in snk and "PADDI" not in src and "INCK_IOLOGIC" not in src 48 | fuzz_interconnect(config=cfg, nodenames=nodes, nodename_predicate=nodename_filter, pip_predicate=pip_filter, regex=True, bidir=True, ignore_tiles=ignore_tiles) 49 | 50 | if __name__ == "__main__": 51 | main() 52 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/151-eclkprim/eclkprim.v: -------------------------------------------------------------------------------- 1 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 2 | module top ( 3 | 4 | ); 5 | ${cmt} (* \dm:primitive ="${prim}", \dm:programming ="MODE:${mode} ${config}", \dm:site ="${site}" *) 6 | ${cmt} ${prim} ECLK_I ( ); 7 | 8 | // A primitive is needed, but VHI should be harmless 9 | (* \xref:LOG ="q_c@0@9" *) 10 | VHI vhi_i(); 11 | endmodule 12 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/151-eclkprim/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | import nonrouting 3 | import fuzzloops 4 | import re 5 | 6 | configs = [ 7 | { 8 | "cfg": FuzzConfig(job="ECLK0", device="LIFCL-40", sv="../shared/empty_40.v", tiles=["CIB_R56C48:ECLK_0", "CIB_R56C49:BMID_0_ECLK_1", "CIB_R56C50:BMID_1_ECLK_2", "CIB_R56C51:ECLK_3"]), 9 | "rc": (55, 48), 10 | "bank": 5, 11 | }, 12 | { 13 | "cfg": FuzzConfig(job="ECLK1", device="LIFCL-40", sv="../shared/empty_40.v", tiles=["CIB_R56C49:BMID_0_ECLK_1", "CIB_R56C48:ECLK_0", "CIB_R56C50:BMID_1_ECLK_2", "CIB_R56C51:ECLK_3"]), 14 | "rc": (55, 49), 15 | "bank": 4, 16 | }, 17 | { 18 | "cfg": FuzzConfig(job="ECLK2", device="LIFCL-40", sv="../shared/empty_40.v", tiles=["CIB_R56C50:BMID_1_ECLK_2", "CIB_R56C49:BMID_0_ECLK_1", "CIB_R56C48:ECLK_0", "CIB_R56C51:ECLK_3"]), 19 | "rc": (55, 50), 20 | "bank": 3, 21 | }, 22 | ] 23 | 24 | def per_loc(x): 25 | cfg = x["cfg"] 26 | 27 | cfg.setup() 28 | empty = cfg.build_design(cfg.sv, {}) 29 | cfg.sv = "eclkprim.v" 30 | 31 | r, c = x["rc"] 32 | bank = x["bank"] 33 | def get_substs(mode="NONE", default_cfg=False, kv=None, mux=False): 34 | if kv is None: 35 | config = "" 36 | elif mux: 37 | val = "#SIG" 38 | if kv[1] in ("0", "1"): 39 | val = kv[1] 40 | if kv[1] == "INV": 41 | val = "#INV" 42 | config = "{}::::{}={}{}".format(mode, kv[0], val) 43 | else: 44 | config = "{}:::{}={}".format(mode, kv[0], kv[1]) 45 | return dict(mode=mode, cmt="//" if mode == "NONE" else "", config=config, prim=prim, site=site) 46 | prim = "ECLKSYNC_CORE" 47 | for z in ['A', 'B', 'C', 'D']: 48 | site = "ECLKSYNC_CORE_R{}C{}{}".format(r, c, z) 49 | nonrouting.fuzz_enum_setting(cfg, empty, "ECLKSYNC{}{}.MODE".format(bank, z), ["NONE", "ECLKSYNC"], 50 | lambda x: get_substs(mode=x), False, 51 | desc="ECLKSYNC primitive mode") 52 | nonrouting.fuzz_enum_setting(cfg, empty, "ECLKSYNC{}{}.STOP_EN".format(bank, z), ["DISABLE", "ENABLE"], 53 | lambda x: get_substs(mode=prim, kv=("STOP_EN", x)), False, 54 | desc="ECLKSYNC stop control enable") 55 | prim = "ECLKDIV_CORE" 56 | for z in ['A', 'B', 'C', 'D']: 57 | site = "ECLKDIV_CORE_R{}C{}{}".format(r, c, z) 58 | nonrouting.fuzz_enum_setting(cfg, empty, "ECLKDIV{}{}.GSR".format(bank, z), ["DISABLED", "ENABLED"], 59 | lambda x: get_substs(mode=prim, kv=("GSR", x)), False, 60 | desc="ECLKDIV GSR mask") 61 | nonrouting.fuzz_enum_setting(cfg, empty, "ECLKDIV{}{}.ECLK_DIV".format(bank, z), ["DISABLE", "2", "3P5", "4", "5"], 62 | lambda x: get_substs(mode=prim, kv=("ECLK_DIV", x)), False, 63 | desc="ECLKDIV divide value") 64 | def main(): 65 | fuzzloops.parallel_foreach(configs, per_loc) 66 | if __name__ == "__main__": 67 | main() 68 | 69 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/152-dqsroute/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import re 4 | 5 | configs = [ 6 | { 7 | "cfg": FuzzConfig(job="DQS3", device="LIFCL-40", sv="../shared/route_40.v", 8 | tiles=["CIB_R56C75:SYSIO_B3_1_DQS0", "CIB_R56C76:SYSIO_B3_0_DQS1", "CIB_R56C77:SYSIO_B3_1_DQS2", "CIB_R56C78:SYSIO_B3_0_DQS3", "CIB_R56C79:SYSIO_B3_1_DQS4"]), 9 | "rc": (55, 70), 10 | }, 11 | { 12 | "cfg": FuzzConfig(job="DQS4", device="LIFCL-40", sv="../shared/route_40.v", 13 | tiles=["CIB_R56C21:SYSIO_B4_1_DQS0", "CIB_R56C22:SYSIO_B4_0_DQS1", "CIB_R56C23:SYSIO_B4_1_DQS2", "CIB_R56C24:SYSIO_B4_0_DQS3", "CIB_R56C25:SYSIO_B4_1_DQS4"]), 14 | "rc": (55, 16), 15 | }, 16 | ] 17 | 18 | ignore_tiles = set([ 19 | "CIB_R55C{}:CIB".format(i) for i in range(1, 87) 20 | ]) 21 | 22 | def main(): 23 | for config in configs: 24 | cfg = config["cfg"] 25 | cfg.setup() 26 | r, c = config["rc"] 27 | nodes = ["R{}C{}_*".format(r, c)] 28 | def nodename_filter(x, nodes): 29 | return ("R{}C{}_".format(r, c) in x) and ("DQSBUF_CORE" in x or "DQS_TOP" in x) 30 | def pip_filter(x, nodes): 31 | src, snk = x 32 | return "IOLOGIC_CORE" not in snk and "DDRDLL_CORE" not in src 33 | fuzz_interconnect(config=cfg, nodenames=nodes, nodename_predicate=nodename_filter, pip_predicate=pip_filter, regex=True, bidir=True, ignore_tiles=ignore_tiles) 34 | 35 | if __name__ == "__main__": 36 | main() 37 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/153-dqsbuf/dqsbuf.v: -------------------------------------------------------------------------------- 1 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 2 | module top ( 3 | 4 | ); 5 | ${cmt} (* \dm:primitive ="DQSBUF_CORE", \dm:programming ="MODE:${mode} ${config}", \dm:site ="${site}" *) 6 | ${cmt} DQSBUF_CORE DQSBUF_CORE_I ( ); 7 | 8 | // A primitive is needed, but VHI should be harmless 9 | (* \xref:LOG ="q_c@0@9" *) 10 | VHI vhi_i(); 11 | endmodule 12 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/154-ddrll/ddrdll.v: -------------------------------------------------------------------------------- 1 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 2 | module top ( 3 | 4 | ); 5 | ${cmt} (* \dm:primitive ="DDRDLL_CORE", \dm:programming ="MODE:${mode} ${config}", \dm:site ="${site}" *) 6 | ${cmt} DDRDLL_CORE DDRDLL_CORE_I ( ); 7 | 8 | // A primitive is needed, but VHI should be harmless 9 | (* \xref:LOG ="q_c@0@9" *) 10 | VHI vhi_i(); 11 | endmodule 12 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/154-ddrll/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import nonrouting 4 | import re 5 | 6 | configs = [ 7 | { 8 | "cfg": FuzzConfig(job="DDRDLLL", device="LIFCL-40", sv="../shared/route_40.v", 9 | tiles=["CIB_R56C2:DOSCL_P18_V18"]), 10 | "rc": (55, 2), 11 | }, 12 | { 13 | "cfg": FuzzConfig(job="DDRDLLR", device="LIFCL-40", sv="../shared/route_40.v", 14 | tiles=["CIB_R54C87:DDR_OSC_R"]), 15 | "rc": (54, 86), 16 | }, 17 | ] 18 | 19 | ignore_tiles = set([ 20 | "CIB_R55C{}:CIB".format(i) for i in range(1, 87) 21 | ] + [ 22 | "CIB_R54C86:CIB_LR", 23 | "CIB_R53C86:CIB_LR", 24 | "CIB_R52C86:CIB_LR", 25 | "CIB_R54C1:CIB_LR", 26 | ]) 27 | 28 | def main(): 29 | for config in configs: 30 | cfg = config["cfg"] 31 | cfg.setup() 32 | r, c = config["rc"] 33 | nodes = ["R{}C{}_*".format(r, c)] 34 | def nodename_filter(x, nodes): 35 | return ("R{}C{}_".format(r, c) in x) and ("ECLKDDR" in x or "DDRDLL_CORE" in x or "JCLKOUT_I" in x or "JPCLK_I" in x or "JECLK" in x) 36 | def pip_filter(x, nodes): 37 | src, snk = x 38 | return True 39 | fuzz_interconnect(config=cfg, nodenames=nodes, nodename_predicate=nodename_filter, pip_predicate=pip_filter, regex=True, bidir=True, ignore_tiles=ignore_tiles) 40 | 41 | cfg.sv = "../shared/empty_40.v" 42 | empty = cfg.build_design(cfg.sv, {}) 43 | cfg.sv = "ddrdll.v" 44 | 45 | site = "DDRDLL_CORE_R{}C{}".format(r, c) 46 | 47 | def get_substs(mode="DDRDLL_CORE", kv=None, mux=False): 48 | if kv is None: 49 | config = "" 50 | elif mux: 51 | val = "#SIG" 52 | if kv[1] in ("0", "1"): 53 | val = kv[1] 54 | if kv[1] == "INV": 55 | val = "#INV" 56 | config = "{}::::{}={}".format(mode, kv[0], val) 57 | else: 58 | config = "{}:::{}={}".format(mode, kv[0], kv[1]) 59 | return dict(mode=mode, cmt="//" if mode == "NONE" else "", config=config, site=site) 60 | nonrouting.fuzz_enum_setting(cfg, empty, "DDRDLL.MODE", ["NONE", "DDRDLL_CORE"], 61 | lambda x: get_substs(mode=x), False, 62 | desc="DDRDLL primitive mode") 63 | nonrouting.fuzz_enum_setting(cfg, empty, "DDRDLL.GSR", ["ENABLED", "DISABLED"], 64 | lambda x: get_substs(kv=("GSR", x)), False, 65 | desc="DDRDLL GSR mask") 66 | nonrouting.fuzz_enum_setting(cfg, empty, "DDRDLL.ENA_ROUNDOFF", ["ENABLED", "DISABLED"], 67 | lambda x: get_substs(kv=("ENA_ROUNDOFF", x)), False) 68 | nonrouting.fuzz_enum_setting(cfg, empty, "DDRDLL.FORCE_MAX_DELAY", ["CODE_OR_LOCK_FROM_DLL_LOOP", "FORCE_LOCK_AND_CODE"], 69 | lambda x: get_substs(kv=("FORCE_MAX_DELAY", x)), False) 70 | nonrouting.fuzz_enum_setting(cfg, empty, "DDRDLL.RSTMUX", ["RST", "INV"], 71 | lambda x: get_substs(kv=("RST", x), mux=True), False) 72 | if __name__ == "__main__": 73 | main() 74 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/155-dlldel/dlldel.v: -------------------------------------------------------------------------------- 1 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 2 | module top ( 3 | 4 | ); 5 | ${cmt} (* \dm:primitive ="DLLDEL_CORE", \dm:programming ="MODE:${mode} ${config}", \dm:site ="${site}" *) 6 | ${cmt} DLLDEL_CORE DLLDEL_CORE_I ( ); 7 | 8 | // A primitive is needed, but VHI should be harmless 9 | (* \xref:LOG ="q_c@0@9" *) 10 | VHI vhi_i(); 11 | endmodule 12 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/160-hard-ip-routing/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | from interconnect import fuzz_interconnect 3 | import re 4 | 5 | configs = [ 6 | { 7 | "cfg": FuzzConfig(job="DPHYROUTE0", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R0C4:MIPI_DPHY_0", "CIB_R0C2:DPHY_CLKMUX0"]), 8 | "rc": (0, 2), 9 | }, 10 | { 11 | "cfg": FuzzConfig(job="DPHYROUTE1", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R0C28:MIPI_DPHY_1", "CIB_R0C26:DPHY_CLKMUX1"]), 12 | "rc": (0, 26), 13 | }, 14 | { 15 | "cfg": FuzzConfig(job="PCIEROUTE", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R0C57:PCIE_X1"]), 16 | "rc": (0, 57), 17 | }, 18 | { 19 | "cfg": FuzzConfig(job="ADCROUTE", device="LIFCL-40", sv="../shared/route_40.v", tiles=["CIB_R50C87:ADC"]), 20 | "rc": (50, 86), 21 | }, 22 | ] 23 | 24 | ignore_tiles = set( 25 | ["CIB_R1C{}:CIB_T".format(c) for c in range(1, 86)] + 26 | ["CIB_R{}C1:CIB_LR".format(r) for r in range(2, 54)] + 27 | ["CIB_R{}C86:CIB_LR".format(r) for r in range(2, 54)] + 28 | ["CIB_R46C86:CIB_LR_A", "CIB_R46C1:CIB_LR_A"] 29 | ) 30 | 31 | def main(): 32 | for config in configs: 33 | cfg = config["cfg"] 34 | cfg.setup() 35 | r, c = config["rc"] 36 | nodes = ["R{}C{}_*".format(r, c)] 37 | def nodename_filter(x, nodes): 38 | return ("R{}C{}_".format(r, c) in x) and ("DPHY_CORE" in x or "DPHY_REFCLOCK_MUX_CORE" in x or "PCIE_CORE" in x or "ADC_CORE" in x) 39 | fuzz_interconnect(config=cfg, nodenames=nodes, nodename_predicate=nodename_filter, regex=True, bidir=True, ignore_tiles=ignore_tiles) 40 | 41 | if __name__ == "__main__": 42 | main() 43 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/161-dphy-ipconfig/dphy.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \dm:primitive ="DPHY_CORE", \dm:programming ="MODE:DPHY_CORE DPHY_CORE:::${k}=${v}", \dm:site ="DPHY0" *) 7 | DPHY_CORE IP_I ( ); 8 | 9 | // A primitive is needed, but VHI should be harmless 10 | (* \xref:LOG ="q_c@0@9" *) 11 | VHI vhi_i(); 12 | endmodule 13 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/161-dphy-ipconfig/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | import nonrouting 3 | import fuzzloops 4 | import re 5 | 6 | import os 7 | import get_params 8 | 9 | 10 | cfg = FuzzConfig(job="DPHYIP", device="LIFCL-40", sv="../shared/empty_40.v", tiles=["TDPHY_CORE2:DPHY_CORE"]) 11 | 12 | def bin2bin(bits): 13 | return "0b{}".format("".join(["1" if b else "0" for b in reversed(bits)])) 14 | 15 | 16 | def main(): 17 | cfg.setup() 18 | cfg.sv = "dphy.v" 19 | empty = cfg.build_design(cfg.sv, dict(k="GSR", v="ENABLED")) 20 | words, enums = get_params.get_params(os.path.join(os.environ['RADIANTDIR'], "cae_library", "simulation", "verilog", "lifcl", "DPHY.v")) 21 | def per_word(w): 22 | name, width, default = w 23 | nonrouting.fuzz_ip_word_setting(cfg, name, width, lambda b: dict(k=name, v=str(bin2bin(b))), "") 24 | fuzzloops.parallel_foreach(words, per_word) 25 | def per_enum(e): 26 | name, options = e 27 | nonrouting.fuzz_ip_enum_setting(cfg, empty, name, options, lambda x: dict(k=name, v=x), "") 28 | fuzzloops.parallel_foreach(enums, per_enum) 29 | 30 | if __name__ == "__main__": 31 | main() 32 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/162-pcie-ipconfig/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | import nonrouting 3 | import fuzzloops 4 | import re 5 | 6 | import os 7 | import get_params 8 | 9 | 10 | cfg = FuzzConfig(job="PCIEIP", device="LIFCL-40", sv="../shared/empty_40.v", tiles=["TPCIE_CORE57:PCIE_CORE"]) 11 | 12 | def bin2bin(bits): 13 | return "0b{}".format("".join(["1" if b else "0" for b in reversed(bits)])) 14 | 15 | defaults = [] 16 | 17 | def get_substs(k, v): 18 | p = "{}={}".format(k, v) 19 | for dk, dv in defaults: 20 | if dk != k: 21 | p += ",{}={}".format(dk, dv) 22 | return dict(p=p) 23 | 24 | def main(): 25 | cfg.setup() 26 | cfg.sv = "pcie.v" 27 | empty = cfg.build_design(cfg.sv, get_substs("GSR", "ENABLED")) 28 | words, enums = get_params.get_params(os.path.join(os.environ['RADIANTDIR'], "cae_library", "simulation", "verilog", "lifcl", "PCIE.v")) 29 | # force words with non-zero default to zero... 30 | for n, w, d in words: 31 | if int(d, 2) != 0: 32 | defaults.append((n, "0b{}".format("0" * w))) 33 | def per_word(w): 34 | name, width, default = w 35 | nonrouting.fuzz_ip_word_setting(cfg, name, width, lambda b: get_substs(name, str(bin2bin(b))), "", default=[d == "1" for d in reversed(default)]) 36 | fuzzloops.parallel_foreach(words, per_word) 37 | def per_enum(e): 38 | name, options = e 39 | nonrouting.fuzz_ip_enum_setting(cfg, empty, name, options, lambda x: get_substs(name, x), "") 40 | fuzzloops.parallel_foreach(enums, per_enum) 41 | 42 | if __name__ == "__main__": 43 | main() 44 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/162-pcie-ipconfig/pcie.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \dm:primitive ="PCIE_CORE", \dm:programming ="MODE:PCIE_CORE PCIE_CORE:::${p}", \dm:site ="TPCIE_CORE57" *) 7 | PCIE_CORE IP_I ( ); 8 | 9 | // A primitive is needed, but VHI should be harmless 10 | (* \xref:LOG ="q_c@0@9" *) 11 | VHI vhi_i(); 12 | endmodule 13 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/900-always-on/fuzzer.py: -------------------------------------------------------------------------------- 1 | from fuzzconfig import FuzzConfig 2 | import nonrouting 3 | import fuzzloops 4 | import re 5 | import libpyprjoxide 6 | import fuzzconfig 7 | 8 | cfgs = [ 9 | FuzzConfig(job="EMPTY", device="LIFCL-40", sv="../shared/empty_40.v", tiles=[]), 10 | FuzzConfig(job="EMPTY", device="LIFCL-17", sv="../shared/empty_17.v", tiles=[]), 11 | ] 12 | 13 | def main(): 14 | for cfg in cfgs: 15 | cfg.setup() 16 | empty = cfg.build_design(cfg.sv, {}) 17 | libpyprjoxide.add_always_on_bits(fuzzconfig.db, empty) 18 | 19 | if __name__ == "__main__": 20 | main() 21 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/shared/empty_17.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-17", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | // A primitive is needed, but VHI should be harmless 7 | (* \xref:LOG ="q_c@0@9" *) 8 | VHI vhi_i(); 9 | endmodule 10 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/shared/empty_40.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | // A primitive is needed, but VHI should be harmless 7 | (* \xref:LOG ="q_c@0@9" *) 8 | VHI vhi_i(); 9 | endmodule 10 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/shared/empty_presyn_40.v: -------------------------------------------------------------------------------- 1 | module top(output q); 2 | assign q = 1'b1; 3 | endmodule 4 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/shared/route_17.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-17", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \xref:LOG ="q_c@0@9"${arcs_attr} *) 7 | wire q; 8 | 9 | (* \dm:cellmodel_primitives ="REG0=reg", \dm:primitive ="SLICE", \dm:programming ="MODE:LOGIC Q0:Q0 ", \dm:site ="R2C2A" *) 10 | SLICE SLICE_I ( .A0(q), .Q0(q) ); 11 | endmodule 12 | -------------------------------------------------------------------------------- /fuzzers/LIFCL/shared/route_40.v: -------------------------------------------------------------------------------- 1 | 2 | (* \db:architecture ="LIFCL", \db:device ="LIFCL-40", \db:package ="QFN72", \db:speed ="7_High-Performance_1.0V", \db:timestamp =1576073342, \db:view ="physical" *) 3 | module top ( 4 | 5 | ); 6 | (* \xref:LOG ="q_c@0@9"${arcs_attr} *) 7 | wire q; 8 | 9 | (* \dm:cellmodel_primitives ="REG0=reg", \dm:primitive ="SLICE", \dm:programming ="MODE:LOGIC Q0:Q0 ", \dm:site ="R2C2A" *) 10 | SLICE SLICE_I ( .A0(q), .Q0(q) ); 11 | endmodule 12 | -------------------------------------------------------------------------------- /libprjoxide/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | members = [ 4 | "prjoxide", 5 | "pyprjoxide", 6 | ] 7 | -------------------------------------------------------------------------------- /libprjoxide/prjoxide/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "prjoxide" 3 | version = "0.1.0" 4 | authors = ["gatecat "] 5 | edition = "2018" 6 | build = "build.rs" 7 | 8 | [features] 9 | default = [] 10 | interchange = ["capnp", "flate2", "capnpc"] 11 | 12 | [dependencies] 13 | regex = "1" 14 | serde = { version = "1", features = ["derive"] } 15 | serde_json = "1" 16 | ron = "0.5.1" 17 | multimap = "0.8.0" 18 | lazy_static = "1.4.0" 19 | pulldown-cmark = "0.6.1" 20 | itertools = "0.8.2" 21 | num-bigint = "0.4.0" 22 | log = "0.4.11" 23 | clap = { version = "3.1", features = ["derive"] } 24 | include_dir = "0.6.0" 25 | capnp = {version = "0.14", optional = true } 26 | flate2 = {version = "1.0", optional = true } 27 | 28 | [build-dependencies] 29 | capnpc = {version = "0.14", optional = true } 30 | 31 | [lib] 32 | name = "prjoxide" 33 | crate-type = ["rlib"] 34 | 35 | [[bin]] 36 | name = "prjoxide" 37 | path = "src/bin/prjoxide.rs" 38 | -------------------------------------------------------------------------------- /libprjoxide/prjoxide/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | #[cfg(feature = "interchange")] { 3 | capnpc::CompilerCommand::new() 4 | .default_parent_module(vec!["schema".into()]) 5 | .src_prefix("../../3rdparty/fpga-interchange-schema/interchange/") 6 | .file("../../3rdparty/fpga-interchange-schema/interchange/References.capnp") 7 | .run().expect("schema compiler command"); 8 | capnpc::CompilerCommand::new() 9 | .default_parent_module(vec!["schema".into()]) 10 | .src_prefix("../../3rdparty/fpga-interchange-schema/interchange/") 11 | .file("../../3rdparty/fpga-interchange-schema/interchange/LogicalNetlist.capnp") 12 | .run().expect("schema compiler command"); 13 | capnpc::CompilerCommand::new() 14 | .default_parent_module(vec!["schema".into()]) 15 | .src_prefix("../../3rdparty/fpga-interchange-schema/interchange/") 16 | .file("../../3rdparty/fpga-interchange-schema/interchange/DeviceResources.capnp") 17 | .run().expect("schema compiler command"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /libprjoxide/prjoxide/src/bba/bbafile.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryInto; 2 | use std::io::{Result, Write}; 3 | 4 | pub struct BBAWriter<'a> { 5 | out: &'a mut dyn Write, 6 | } 7 | 8 | impl<'a> BBAWriter<'a> { 9 | pub fn new(out: &mut dyn Write) -> BBAWriter { 10 | BBAWriter { out } 11 | } 12 | pub fn u8_val(&mut self, val: u8) -> Result<()> { 13 | writeln!(&mut self.out, "u8 {}", val)?; 14 | Ok(()) 15 | } 16 | pub fn u16_val(&mut self, val: u16) -> Result<()> { 17 | writeln!(&mut self.out, "u16 {}", val)?; 18 | Ok(()) 19 | } 20 | pub fn u32_val(&mut self, val: u32) -> Result<()> { 21 | writeln!(&mut self.out, "u32 {}", val)?; 22 | Ok(()) 23 | } 24 | pub fn i8_val(&mut self, val: i8) -> Result<()> { 25 | writeln!(&mut self.out, "u8 {}", val)?; 26 | Ok(()) 27 | } 28 | pub fn i16_val(&mut self, val: i16) -> Result<()> { 29 | writeln!(&mut self.out, "u16 {}", val)?; 30 | Ok(()) 31 | } 32 | pub fn i32_val(&mut self, val: i32) -> Result<()> { 33 | writeln!(&mut self.out, "u32 {}", val)?; 34 | Ok(()) 35 | } 36 | pub fn pre(&mut self, s: &str) -> Result<()> { 37 | writeln!(&mut self.out, "pre {}", s)?; 38 | Ok(()) 39 | } 40 | pub fn post(&mut self, s: &str) -> Result<()> { 41 | writeln!(&mut self.out, "post {}", s)?; 42 | Ok(()) 43 | } 44 | pub fn push(&mut self, s: &str) -> Result<()> { 45 | writeln!(&mut self.out, "push {}", s)?; 46 | Ok(()) 47 | } 48 | pub fn pop(&mut self) -> Result<()> { 49 | writeln!(&mut self.out, "pop")?; 50 | Ok(()) 51 | } 52 | pub fn ref_label(&mut self, s: &str) -> Result<()> { 53 | writeln!(&mut self.out, "ref {}", s)?; 54 | Ok(()) 55 | } 56 | pub fn ref_slice(&mut self, s: &str, len: usize) -> Result<()> { 57 | writeln!(&mut self.out, "ref {}", s)?; 58 | self.u32_val(len.try_into().unwrap())?; 59 | Ok(()) 60 | } 61 | pub fn str_val(&mut self, s: &str) -> Result<()> { 62 | writeln!(&mut self.out, "str |{}|", s)?; 63 | Ok(()) 64 | } 65 | pub fn label(&mut self, s: &str) -> Result<()> { 66 | writeln!(&mut self.out, "label {}", s)?; 67 | Ok(()) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /libprjoxide/prjoxide/src/bba/idstring.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use crate::bba::bbastruct::BBAStructs; 4 | use std::fs::File; 5 | use std::io::{prelude::*, BufReader}; 6 | 7 | #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] 8 | pub struct IdString(usize); 9 | 10 | impl IdString { 11 | pub fn val(&self) -> usize { 12 | return self.0; 13 | } 14 | } 15 | 16 | pub struct IdStringDB { 17 | strings: Vec, 18 | string_to_id: HashMap, 19 | const_ids_count: usize, 20 | } 21 | 22 | impl IdStringDB { 23 | pub fn new() -> IdStringDB { 24 | let mut db = IdStringDB { 25 | strings: vec!["".to_string()], 26 | string_to_id: HashMap::new(), 27 | const_ids_count: 1, 28 | }; 29 | db.string_to_id.insert("".to_string(), IdString(0)); 30 | db 31 | } 32 | 33 | // Setup from a nextpnr constids file 34 | pub fn from_constids(filename: &str) -> std::io::Result { 35 | let mut ids = IdStringDB::new(); 36 | let file = File::open(filename)?; 37 | let reader = BufReader::new(file); 38 | for line in reader.lines() { 39 | let l = line?; 40 | if l.len() < 3 || &l[0..2] != "X(" { 41 | continue; 42 | } 43 | let end_pos = l.rfind(')').unwrap(); 44 | let constid = &l[2..end_pos]; 45 | ids.id(constid); 46 | } 47 | ids.const_ids_count = ids.strings.len(); 48 | Ok(ids) 49 | } 50 | 51 | pub fn write_bba(&self, out: &mut BBAStructs) -> std::io::Result<()> { 52 | out.string_list("bba_idstrings", &self.strings[self.const_ids_count..])?; 53 | out.list_begin("id_db")?; 54 | out.id_string_db( 55 | self.const_ids_count, 56 | self.strings.len() - self.const_ids_count, 57 | "bba_idstrings", 58 | )?; 59 | Ok(()) 60 | } 61 | 62 | pub fn id(&mut self, id: &str) -> IdString { 63 | match self.string_to_id.get(id) { 64 | Some(k) => *k, 65 | None => { 66 | let index = self.strings.len(); 67 | self.strings.push(id.to_string()); 68 | self.string_to_id.insert(id.to_string(), IdString(index)); 69 | return IdString(index); 70 | } 71 | } 72 | } 73 | 74 | pub fn get_id(&self, id: &str) -> Option { 75 | self.string_to_id.get(id).cloned() 76 | } 77 | 78 | pub fn str(&self, index: IdString) -> &str { 79 | &self.strings[index.0] 80 | } 81 | 82 | pub fn len(&self) -> usize { 83 | self.strings.len() 84 | } 85 | pub fn idx_str(&self, index: usize) -> &str { 86 | &self.strings[index] 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /libprjoxide/prjoxide/src/bba/idxset.rs: -------------------------------------------------------------------------------- 1 | use std::cmp::Eq; 2 | use std::collections::HashMap; 3 | use std::hash::Hash; 4 | 5 | pub struct IndexedSet { 6 | keys: Vec, 7 | key_to_index: HashMap, 8 | } 9 | 10 | impl IndexedSet { 11 | pub fn new() -> IndexedSet { 12 | IndexedSet:: { 13 | keys: Vec::new(), 14 | key_to_index: HashMap::new(), 15 | } 16 | } 17 | 18 | pub fn add(&mut self, key: &T) -> usize { 19 | match self.key_to_index.get(key) { 20 | Some(k) => *k, 21 | None => { 22 | let index = self.keys.len(); 23 | self.keys.push(key.clone()); 24 | self.key_to_index.insert(key.clone(), index); 25 | return index; 26 | } 27 | } 28 | } 29 | 30 | pub fn get_index(&self, key: &T) -> Option { 31 | self.key_to_index.get(key).cloned() 32 | } 33 | 34 | pub fn key(&self, index: usize) -> &T { 35 | &self.keys[index] 36 | } 37 | pub fn iter(&self) -> std::slice::Iter { 38 | self.keys.iter() 39 | } 40 | pub fn len(&self) -> usize { 41 | self.keys.len() 42 | } 43 | } 44 | 45 | pub struct IndexedMap { 46 | data: Vec<(Key, Value)>, 47 | key_to_index: HashMap, 48 | } 49 | 50 | impl IndexedMap { 51 | pub fn new() -> IndexedMap { 52 | IndexedMap:: { 53 | data: Vec::new(), 54 | key_to_index: HashMap::new(), 55 | } 56 | } 57 | 58 | pub fn add(&mut self, key: &Key, value: Value) -> usize { 59 | match self.key_to_index.get(key) { 60 | Some(k) => *k, 61 | None => { 62 | let index = self.data.len(); 63 | self.data.push((key.clone(), value)); 64 | self.key_to_index.insert(key.clone(), index); 65 | return index; 66 | } 67 | } 68 | } 69 | 70 | pub fn get_index(&self, key: &Key) -> Option { 71 | self.key_to_index.get(key).cloned() 72 | } 73 | 74 | pub fn key(&self, index: usize) -> &Key { 75 | &self.data[index].0 76 | } 77 | 78 | pub fn value(&self, index: usize) -> &Value { 79 | &self.data[index].1 80 | } 81 | pub fn value_by_key(&self, key: &Key) -> &Value { 82 | &self.data[self.get_index(key).unwrap()].1 83 | } 84 | 85 | pub fn value_mut(&mut self, index: usize) -> &mut Value { 86 | &mut self.data[index].1 87 | } 88 | 89 | pub fn iter(&self) -> std::slice::Iter<(Key, Value)> { 90 | self.data.iter() 91 | } 92 | 93 | pub fn iter_mut(&mut self) -> std::slice::IterMut<(Key, Value)> { 94 | self.data.iter_mut() 95 | } 96 | pub fn len(&self) -> usize { 97 | self.data.len() 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /libprjoxide/prjoxide/src/docs.rs: -------------------------------------------------------------------------------- 1 | use pulldown_cmark::{html, Options, Parser}; 2 | use std::fs::File; 3 | use std::io::prelude::*; 4 | use std::io::BufReader; 5 | use std::path::Path; 6 | 7 | fn preprocess(filename: &str, out: &mut String) { 8 | let file = File::open(filename).unwrap(); 9 | let reader = BufReader::new(file); 10 | 11 | for line in reader.lines().map(Result::unwrap) { 12 | if line.starts_with(".include ") { 13 | let relpath = &line[9..]; 14 | let incpath = Path::new(filename).parent().unwrap().join(relpath); 15 | preprocess(incpath.to_str().unwrap(), out); 16 | } else { 17 | out.push_str(&line); 18 | out.push('\n'); 19 | } 20 | } 21 | } 22 | 23 | pub fn md_to_html(md: &str) -> String { 24 | let mut options = Options::empty(); 25 | options.insert(Options::ENABLE_STRIKETHROUGH); 26 | options.insert(Options::ENABLE_TABLES); 27 | let parser = Parser::new_ext(md, options); 28 | 29 | // Write to String buffer. 30 | let mut html_output = String::new(); 31 | html::push_html(&mut html_output, parser); 32 | html_output 33 | } 34 | 35 | pub fn md_file_to_html(filename: &str) -> String { 36 | let mut preproc = String::new(); 37 | preprocess(filename, &mut preproc); 38 | md_to_html(&preproc) 39 | } 40 | -------------------------------------------------------------------------------- /libprjoxide/prjoxide/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate lazy_static; 3 | 4 | extern crate log; 5 | 6 | pub mod bba { 7 | pub mod bbafile; 8 | pub mod bbastruct; 9 | pub mod idstring; 10 | pub mod idxset; 11 | pub mod tileloc; 12 | pub mod tiletype; 13 | pub mod timing; 14 | } 15 | 16 | pub mod bels; 17 | pub mod bitstream; 18 | pub mod chip; 19 | pub mod database; 20 | pub mod database_html; 21 | pub mod docs; 22 | pub mod fasmparse; 23 | pub mod fuzz; 24 | pub mod ipfuzz; 25 | pub mod nodecheck; 26 | pub mod wires; 27 | pub mod pip_classes; 28 | pub mod sites; 29 | pub mod interchange_gen { 30 | pub mod routing_graph; 31 | pub mod writer; 32 | pub mod bel_pin_map; 33 | } 34 | mod schema; 35 | -------------------------------------------------------------------------------- /libprjoxide/prjoxide/src/nodecheck.rs: -------------------------------------------------------------------------------- 1 | use crate::chip::*; 2 | use crate::database::*; 3 | use std::collections::BTreeSet; 4 | use std::fs::File; 5 | use std::io::*; 6 | 7 | pub fn check(db: &mut Database, c: &Chip, nodefile: &str) { 8 | let f = File::open(nodefile).unwrap(); 9 | let reader = BufReader::new(f); 10 | let mut lattice_pips = BTreeSet::<(String, String)>::new(); // (from, to) 11 | let mut oxide_pips = BTreeSet::<(String, String)>::new(); // (from, to) 12 | for line in reader.lines() { 13 | let l = line.unwrap(); 14 | let s = l.split(' ').collect::>(); 15 | if s.len() < 3 { 16 | continue; 17 | } 18 | if s[1] == "-->" { 19 | lattice_pips.insert((s[0].to_string(), s[2].to_string())); 20 | } else if s[1] == "<--" { 21 | lattice_pips.insert((s[2].to_string(), s[0].to_string())); 22 | } 23 | } 24 | 25 | for tile in c.tiles.iter() { 26 | let tdb = db.tile_bitdb(&c.family, &tile.tiletype); 27 | let norm_wire = |w: &str| { 28 | let sep_pos = w.find(':'); 29 | if let Some(sp) = sep_pos { 30 | let prefix = &w[0..sp]; 31 | let mut rel_x = 0; 32 | let mut rel_y = 0; 33 | let mut tokens = Vec::new(); 34 | let mut last = 0; 35 | for (index, _) in 36 | prefix.match_indices(|c| c == 'N' || c == 'E' || c == 'S' || c == 'W') 37 | { 38 | if last != index { 39 | tokens.push(&prefix[last..index]); 40 | } 41 | last = index; 42 | } 43 | tokens.push(&prefix[last..]); 44 | for tok in tokens { 45 | match tok.chars().nth(0).unwrap() { 46 | 'N' => rel_y = -tok[1..].parse::().unwrap(), 47 | 'S' => rel_y = tok[1..].parse::().unwrap(), 48 | 'E' => rel_x = tok[1..].parse::().unwrap(), 49 | 'W' => rel_x = -tok[1..].parse::().unwrap(), 50 | _ => { 51 | return None; // Skip global wires etc 52 | } 53 | } 54 | } 55 | Some(format!( 56 | "R{}C{}_{}", 57 | tile.y as i32 + rel_y, 58 | tile.x as i32 + rel_x, 59 | &w[sp + 1..] 60 | )) 61 | } else { 62 | Some(format!("R{}C{}_{}", tile.y, tile.x, w)) 63 | } 64 | }; 65 | // Currently just checking fixed conns - could check pips too 66 | for (to_wire, conns) in tdb.db.conns.iter() { 67 | let norm_to_wire = norm_wire(to_wire); 68 | if let Some(tw) = norm_to_wire { 69 | for from_wire in conns.iter().filter_map(|c| norm_wire(&c.from_wire)) { 70 | oxide_pips.insert((from_wire, tw.to_string())); 71 | } 72 | } 73 | } 74 | } 75 | for (from, to) in oxide_pips.iter() { 76 | if !lattice_pips.contains(&(from.to_string(), to.to_string())) { 77 | eprintln!("{} --> {}", from, to); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /libprjoxide/prjoxide/src/schema.rs: -------------------------------------------------------------------------------- 1 | #![allow(warnings, unused)] 2 | #![cfg(feature = "interchange")] 3 | 4 | pub mod References_capnp { 5 | include!(concat!(env!("OUT_DIR"), "/References_capnp.rs")); 6 | } 7 | pub mod LogicalNetlist_capnp { 8 | include!(concat!(env!("OUT_DIR"), "/LogicalNetlist_capnp.rs")); 9 | } 10 | pub mod DeviceResources_capnp { 11 | include!(concat!(env!("OUT_DIR"), "/DeviceResources_capnp.rs")); 12 | } 13 | -------------------------------------------------------------------------------- /libprjoxide/pyprjoxide/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pyprjoxide" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | prjoxide = { path = "../prjoxide" } 8 | 9 | [dependencies.pyo3] 10 | version = "0.13.1" 11 | features = ["extension-module"] 12 | 13 | [lib] 14 | name = "pyprjoxide" 15 | crate-type = ["cdylib"] 16 | -------------------------------------------------------------------------------- /minitests/.gitignore: -------------------------------------------------------------------------------- 1 | *.tmp 2 | *.fasm 3 | work/ 4 | -------------------------------------------------------------------------------- /minitests/interchange/archcheck.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -ex 3 | 4 | # TODO: make these configurable 5 | DEVICE=LIFCL-17 6 | NEXTPNR_BUILD=../../../nextpnr/build 7 | 8 | mkdir -p work 9 | prjoxide interchange-export ${DEVICE} work/${DEVICE}.capnp 10 | python3 -m fpga_interchange.nextpnr_emit --schema_dir ../../3rdparty/fpga-interchange-schema/interchange \ 11 | --output_dir work --device work/${DEVICE}.capnp --device_config nexus_device_config.yaml 12 | ${NEXTPNR_BUILD}/bba/bbasm --l work/chipdb.bba work/${DEVICE}.bin 13 | ${NEXTPNR_BUILD}/nextpnr-fpga_interchange --chipdb work/${DEVICE}.bin --test 14 | -------------------------------------------------------------------------------- /minitests/interchange/nexus_device_config.yaml: -------------------------------------------------------------------------------- 1 | # Which BEL names are global buffers for nextpnr? 2 | global_buffers: [] 3 | # How should nextpnr lump BELs during analytic placement? 4 | buckets: 5 | - bucket: LUTS 6 | cells: 7 | - LUT4 8 | -------------------------------------------------------------------------------- /minitests/simple/io.v: -------------------------------------------------------------------------------- 1 | module top( 2 | input a, 3 | output y); 4 | 5 | wire a_buf; 6 | (* LOC="P11", IO_TYPE="LVCMOS10", PULLMODE="UP" *) 7 | IB ib_a(.I(a), .O(a_buf)); 8 | 9 | (* LOC="P10", IO_TYPE="LVCMOS18H" *) 10 | OB ob_y(.I(a_buf), .O(y)); 11 | endmodule 12 | -------------------------------------------------------------------------------- /minitests/simple/wire.v: -------------------------------------------------------------------------------- 1 | module top(input a, output y); 2 | assign y = a; 3 | endmodule 4 | -------------------------------------------------------------------------------- /radiant.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | radiantdir="${RADIANTDIR:-$HOME/lscc/radiant/3.0}" 4 | export FOUNDRY="${radiantdir}/ispfpga" 5 | bindir="${radiantdir}/bin/lin64" 6 | LSC_DIAMOND=true 7 | export LSC_DIAMOND 8 | export NEOCAD_MAXLINEWIDTH=32767 9 | export TCL_LIBRARY="${radiantdir}/tcltk/linux/lib/tcl8.6" 10 | export fpgabindir=${FOUNDRY}/bin/lin64 11 | ld_lib_path_orig=$LD_LIBRARY_PATH 12 | export LD_LIBRARY_PATH="${bindir}:${fpgabindir}" 13 | export LM_LICENSE_FILE="${radiantdir}/license/license.dat" 14 | 15 | set -ex 16 | 17 | V_SUB=${2%.v} 18 | PART=$1 19 | set -- "$1" $V_SUB 20 | 21 | EXTRA_BIT_ARGS= 22 | 23 | case "${PART}" in 24 | LIFCL-17) 25 | PACKAGE="${DEV_PACKAGE:-CABGA256}" 26 | DEVICE="LIFCL-17" 27 | LSE_ARCH="lifcl" 28 | SPEED_GRADE="${SPEED_GRADE:-7_High-Performance_1.0V}" 29 | ;; 30 | LIFCL-40) 31 | PACKAGE="${DEV_PACKAGE:-CABGA400}" 32 | DEVICE="LIFCL-40" 33 | LSE_ARCH="lifcl" 34 | SPEED_GRADE="${SPEED_GRADE:-7_High-Performance_1.0V}" 35 | ;; 36 | LFD2NX-40) 37 | PACKAGE="${DEV_PACKAGE:-CABGA256}" 38 | DEVICE="LFD2NX-40" 39 | LSE_ARCH="lfd2nx" 40 | SPEED_GRADE="${SPEED_GRADE:-7_High-Performance_1.0V}" 41 | ;; 42 | LFCPNX-100) 43 | PACKAGE="${DEV_PACKAGE:-LFG672}" 44 | DEVICE="LFCPNX-100" 45 | LSE_ARCH="lfcpnx" 46 | EXTRA_BIT_ARGS="-ipeval" 47 | SPEED_GRADE="${SPEED_GRADE:-7_High-Performance_1.0V}" 48 | ;; 49 | esac 50 | 51 | SCRIPT_PATH=$(readlink -f "${BASH_SOURCE:-$0}") 52 | SCRIPT_DIR=$(dirname "$SCRIPT_PATH") 53 | bscache=${BITSTREAM_CACHE:-$SCRIPT_DIR/tools/bitstreamcache.py} 54 | 55 | ( 56 | 57 | rm -rf "$2.tmp" 58 | mkdir -p "$2.tmp" 59 | cp "$2.v" "$2.tmp/input.v" 60 | MAYBE_PDC="" 61 | if [ -e "$2.pdc" ]; then cp "$2.pdc" "$2.tmp/input.pdc"; MAYBE_PDC="$2.tmp/input.pdc"; fi 62 | 63 | if ([ -z "$FORCE_REBUILD"] && (LD_LIBRARY_PATH=$ld_lib_path_orig $bscache fetch $PART "$2.tmp" "$2.tmp/input.v" $MAYBE_PDC)); then 64 | # Cache hit 65 | echo "Cache hit, not running Radiant" 66 | else 67 | # Cache miss 68 | cd "$2.tmp" 69 | if [ -n "$STRUCT_VER" ]; then 70 | "$fpgabindir"/sv2udb -o par.udb input.v 71 | else 72 | "$fpgabindir"/synthesis -a "$LSE_ARCH" -p "$DEVICE" -t "$PACKAGE" \ 73 | -use_io_insertion 1 -use_io_reg auto -use_carry_chain 1 \ 74 | -ver input.v \ 75 | -output_hdl synth.vm 76 | 77 | "$fpgabindir"/postsyn -a "$LSE_ARCH" -p "$DEVICE" -t "$PACKAGE" -sp "$SPEED_GRADE" \ 78 | -top -w -o synth.udb synth.vm 79 | if [ -e input.pdc ]; then 80 | MAP_PDC="input.pdc" 81 | else 82 | MAP_PDC="" 83 | fi 84 | "$fpgabindir"/map -o map.udb synth.udb $MAP_PDC 85 | "$fpgabindir"/par map.udb par.udb 86 | fi 87 | 88 | if [ -n "$GEN_RBF" ]; then 89 | "$fpgabindir"/bitgen $EXTRA_BIT_ARGS -b -d -w par.udb 90 | LD_LIBRARY_PATH=$ld_lib_path_orig $bscache commit $PART "input.v" $MAP_PDC output "par.udb" "par.rbt" 91 | else 92 | if [ -n "$RBK_MODE" ]; then 93 | "$fpgabindir"/bitgen $EXTRA_BIT_ARGS -d -w -m 1 par.udb 94 | mv par.rbk par.bit 95 | else 96 | "$fpgabindir"/bitgen $EXTRA_BIT_ARGS -d -w par.udb 97 | fi 98 | LD_LIBRARY_PATH=$ld_lib_path_orig $bscache commit $PART "input.v" $MAP_PDC output "par.udb" "par.bit" 99 | fi 100 | export LD_LIBRARY_PATH="" 101 | fi 102 | ) 103 | 104 | if [ -n "$GEN_RBF" ]; then 105 | cp "$2.tmp"/par.rbt "$2.rbt" 106 | else 107 | cp "$2.tmp"/par.bit "$2.bit" 108 | fi 109 | 110 | if [ -n "$DO_UNPACK" ]; then 111 | prjoxide unpack "$2.bit" "$2.fasm" 112 | fi 113 | -------------------------------------------------------------------------------- /radiant_cmd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script to run a single Radiant command 4 | # You need to set the RADIANTDIR environment variable to the path where you have 5 | # installed Lattice Radiant, unless it matches this default. 6 | 7 | radiantdir="${RADIANTDIR:-$HOME/lscc/radiant/3.0}" 8 | export FOUNDRY="${radiantdir}/ispfpga" 9 | bindir="${radiantdir}/bin/lin64" 10 | LSC_DIAMOND=true 11 | export LSC_DIAMOND 12 | export NEOCAD_MAXLINEWIDTH=32767 13 | export TCL_LIBRARY="${radiantdir}/tcltk/linux/lib/tcl8.6" 14 | export fpgabindir=${FOUNDRY}/bin/lin64 15 | export LD_LIBRARY_PATH="${bindir}:${fpgabindir}" 16 | export LM_LICENSE_FILE="${radiantdir}/license/license.dat" 17 | PATH=$FOUNDRY/bin/lin64:$bindir:$PATH exec $* 18 | -------------------------------------------------------------------------------- /timing/.gitignore: -------------------------------------------------------------------------------- 1 | output/ 2 | work/ 3 | *.tmp/ 4 | -------------------------------------------------------------------------------- /timing/fuzzers/LIFCL/01-dff/Makefile: -------------------------------------------------------------------------------- 1 | NAME=dff 2 | RUNS=1 3 | GENERATOR=gen_dff.py 4 | DEVICE=LIFCL-40 5 | ALLOW_FAIL=false 6 | 7 | include ../../../tools/fuzzer.mk 8 | -------------------------------------------------------------------------------- /timing/fuzzers/LIFCL/01-dff/gen_dff.py: -------------------------------------------------------------------------------- 1 | dffs = [] 2 | 3 | for clk in ("clk", "clkn"): 4 | for lsr in ("lsr", "lsrn", "1'b0"): 5 | for ce in ("ce", "cen", "1'b0"): 6 | for d in ("d", "x ^ d"): 7 | for prim, sr in [("FD1P3BX", "PD"), ("FD1P3DX", "CD"), ("FD1P3IX", "CD"), ("FD1P3JX", "PD")]: 8 | i = len(dffs) 9 | dffs.append("{prim} LOGIC_DFF_{i} (.D({d}[{i}]), .CK({ck}), .SP({ce}), .{sr}({lsr}), .Q(q[{i}]));".format( 10 | prim=prim, i=i, d=d, ck=clk, ce=ce, sr=sr, lsr=lsr, 11 | )) 12 | 13 | print("module top(input clk, lsr, ce, x, input [{0}:0] d, input [8:0] sel, output qq);".format(len(dffs)-1)) 14 | print(" wire clkn, lsrn, cen;") 15 | print(" INV clk_inv (.A(clk), .Z(clkn));") 16 | print(" INV lsr_inv (.A(lsr), .Z(lsrn));") 17 | print(" INV ce_inv (.A(ce), .Z(cen));") 18 | print(" wire [{}:0] q;".format(len(dffs))) 19 | print(" assign qq = q[sel];") 20 | print(" {}".format("\n ".join(dffs))) 21 | print("endmodule") 22 | -------------------------------------------------------------------------------- /timing/fuzzers/LIFCL/02-ram/Makefile: -------------------------------------------------------------------------------- 1 | NAME=ram 2 | RUNS=1 2 3 4 5 6 7 8 3 | GENERATOR=gen_ram.py 4 | DEVICE=LIFCL-40 5 | ALLOW_FAIL=false 6 | 7 | include ../../../tools/fuzzer.mk 8 | -------------------------------------------------------------------------------- /timing/fuzzers/LIFCL/03-picorv32/Makefile: -------------------------------------------------------------------------------- 1 | NAME=picorv32 2 | RUNS=1 2 3 4 3 | GENERATOR=./gen_picorv32.py 4 | DEVICE=LIFCL-40 5 | ALLOW_FAIL=false 6 | 7 | include ../../../tools/fuzzer.mk 8 | -------------------------------------------------------------------------------- /timing/fuzzers/LIFCL/04-dsp/Makefile: -------------------------------------------------------------------------------- 1 | NAME=dsp 2 | RUNS=1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 3 | GENERATOR=gen_dsp.py 4 | DEVICE=LIFCL-40 5 | ALLOW_FAIL=false 6 | 7 | include ../../../tools/fuzzer.mk 8 | -------------------------------------------------------------------------------- /timing/fuzzers/LIFCL/04-dsp/gen_dsp.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | # (name, cost, a_width, b_with, c_width, z_width, extra_registers) 4 | prims = [ 5 | ("MULT18X18", 2, 18, 18, None, 36, ()), 6 | ("MULT18X36", 4, 18, 36, None, 54, ()), 7 | ("MULT36X36", 8, 36, 36, None, 72, ()), 8 | ("MULT9X9", 1, 9, 9, None, 18, ()), 9 | ("MULTADDSUB18X18", 4, 18, 18, 54, 54, ("ADDSUB", "CIN")), 10 | ("MULTADDSUB18X36", 4, 18, 36, 54, 54, ("ADDSUB", "CIN")), 11 | ("MULTADDSUB36X36", 8, 36, 36, 108, 108, ("ADDSUB", "CIN")), 12 | ("MULTPREADD18X18", 2, 18, 18, 18, 36, ()), 13 | ("MULTPREADD9X9", 1, 9, 9, 9, 18, ()), 14 | ] 15 | 16 | max_cost = 56 17 | 18 | print("module top(input clk, input [3:0] ce, input [3:0] rst, input [7:0] d, output [7:0] q);") 19 | data = ["d[{}]".format(i) for i in range(8)] 20 | curr_cost = 0 21 | i = 0 22 | 23 | while True: 24 | prim, cost, A, B, C, Z, regs = prims[np.random.randint(len(prims))] 25 | curr_cost += cost 26 | if curr_cost > max_cost: 27 | break 28 | a = "{{{}}}".format(", ".join(np.random.choice(data) for j in range(A))) 29 | b = "{{{}}}".format(", ".join(np.random.choice(data) for j in range(B))) 30 | if C is not None: 31 | c = "{{{}}}".format(", ".join(np.random.choice(data) for j in range(C))) 32 | print(" wire [{}:0] d_{};".format(Z-1, i)) 33 | print(" {} #(".format(prim)) 34 | print(" .REGINPUTA(\"{}\"),".format(np.random.choice(["REGISTER", "BYPASS"]))) 35 | print(" .REGINPUTB(\"{}\"),".format(np.random.choice(["REGISTER", "BYPASS"]))) 36 | if C is not None: 37 | print(" .REGINPUTC(\"{}\"),".format(np.random.choice(["REGISTER", "BYPASS"]))) 38 | for er in regs: 39 | print(" .REG{}(\"{}\"),".format(er, np.random.choice(["REGISTER", "BYPASS"]))) 40 | print(" .REGOUTPUT(\"{}\"),".format(np.random.choice(["REGISTER", "BYPASS"]))) 41 | print(" .RESETMODE(\"{}\")".format(np.random.choice(["SYNC", "ASYNC"]))) 42 | print(" ) dsp_{} (".format(i)) 43 | print(" .A({}),".format(a)) 44 | print(" .B({}),".format(b)) 45 | if C is not None: 46 | print(" .C({}),".format(c)) 47 | print(" .CLK(clk),") 48 | print(" .CEA(ce[{}]),".format(np.random.randint(4))) 49 | print(" .CEB(ce[{}]),".format(np.random.randint(4))) 50 | print(" .RSTA(rst[{}]),".format(np.random.randint(4))) 51 | print(" .RSTB(rst[{}]),".format(np.random.randint(4))) 52 | print(" .Z(d_{})".format(i)) 53 | print(" );") 54 | data = ["d_{}[{}]".format(i, j) for j in range(Z)] 55 | i += 1 56 | 57 | print(" assign q = {{{}}};".format(", ".join(np.random.choice(data) for j in range(8)))) 58 | print("endmodule") 59 | -------------------------------------------------------------------------------- /timing/fuzzers/LIFCL/05-clock/Makefile: -------------------------------------------------------------------------------- 1 | NAME=clock 2 | RUNS=1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 3 | GENERATOR=gen_clk.py 4 | DEVICE=LIFCL-40 5 | ALLOW_FAIL=true 6 | 7 | include ../../../tools/fuzzer.mk 8 | -------------------------------------------------------------------------------- /timing/fuzzers/LIFCL/06-carry/Makefile: -------------------------------------------------------------------------------- 1 | NAME=carry 2 | RUNS=1 3 | GENERATOR=gen_carry.py 4 | DEVICE=LIFCL-40 5 | ALLOW_FAIL=true 6 | 7 | include ../../../tools/fuzzer.mk 8 | -------------------------------------------------------------------------------- /timing/fuzzers/LIFCL/06-carry/gen_carry.py: -------------------------------------------------------------------------------- 1 | print("module top(input [1:0] A, B, C, D, output [5:0] S);") 2 | print("wire [1:0] cy;") 3 | for i in range(3): 4 | print(" CCU2 #(.INIT0(\"0x1234\"), .INIT1(\"0x5678\")) SLICE_CCU_{} (".format(i)) 5 | if i > 0: 6 | print(" .CIN(cy[{}]),".format(i-1)) 7 | print(" {},".format(", ".join([".{p}0({p}[0])".format(p=p) for p in "ABCD"]))) 8 | print(" {},".format(", ".join([".{p}1({p}[1])".format(p=p) for p in "ABCD"]))) 9 | if i < 2: 10 | print(" .COUT(cy[{}]),".format(i)) 11 | print(" .S0(S[{}]), .S1(S[{}])".format(i*2, i*2+1)) 12 | print(" );") 13 | print("endmodule") 14 | -------------------------------------------------------------------------------- /timing/fuzzers/LIFCL/07-lutram/Makefile: -------------------------------------------------------------------------------- 1 | NAME=lutram 2 | RUNS=1 3 | GENERATOR=gen_lutram.py 4 | DEVICE=LIFCL-40 5 | ALLOW_FAIL=false 6 | 7 | include ../../../tools/fuzzer.mk 8 | -------------------------------------------------------------------------------- /timing/fuzzers/LIFCL/07-lutram/gen_lutram.py: -------------------------------------------------------------------------------- 1 | print(""" 2 | module top(input clk, wre, input [3:0] wad, rad, wd, output [3:0] rd); 3 | 4 | reg [3:0] mem[0:15]; 5 | 6 | always @(posedge clk) if(wre) mem[wad] <= wd; 7 | 8 | assign rd = mem[rad]; 9 | 10 | endmodule 11 | """) 12 | -------------------------------------------------------------------------------- /timing/fuzzers/LIFCL/08-io/Makefile: -------------------------------------------------------------------------------- 1 | NAME=io 2 | RUNS=1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 3 | GENERATOR=gen_io.py 4 | DEVICE=LIFCL-40 5 | ALLOW_FAIL=true 6 | 7 | include ../../../tools/fuzzer.mk 8 | -------------------------------------------------------------------------------- /timing/tools/fuzzer.mk: -------------------------------------------------------------------------------- 1 | all: work/stamp 2 | 3 | work/stamp: $(foreach run,$(RUNS),work/$(run).stamp) 4 | touch $@ 5 | 6 | BASE_DIR=../../../../ 7 | OUT_DIR=../../../output/ 8 | 9 | work/design_%.v: $(GENERATOR) 10 | mkdir -p work/ 11 | python $(GENERATOR) > $@ 12 | 13 | work/design_%.bit: work/design_%.v 14 | $(BASE_DIR)/radiant.sh $(DEVICE) $< || $(ALLOW_FAIL) 15 | 16 | work/%.stamp: work/design_%.bit 17 | mkdir -p $(OUT_DIR) 18 | 19 | python $(BASE_DIR)/timing/util/extract_route.py work/design_$*.tmp/par.udb $(OUT_DIR)/$(NAME)_$*_route.pickle 20 | 21 | # we need the '|| true' because of 22 | # malloc_consolidate(): unaligned fastbin chunk detected 23 | 24 | $(BASE_DIR)/radiant_cmd.sh backanno -sp 4 -w -o $(OUT_DIR)/$(NAME)_$*_4.vo work/design_$*.tmp/par.udb || true 25 | $(BASE_DIR)/radiant_cmd.sh backanno -sp 5 -w -o $(OUT_DIR)/$(NAME)_$*_5.vo work/design_$*.tmp/par.udb || true 26 | $(BASE_DIR)/radiant_cmd.sh backanno -sp 6 -w -o $(OUT_DIR)/$(NAME)_$*_6.vo work/design_$*.tmp/par.udb || true 27 | 28 | $(BASE_DIR)/radiant_cmd.sh backanno -sp 10 -w -o $(OUT_DIR)/$(NAME)_$*_10.vo work/design_$*.tmp/par.udb || true 29 | $(BASE_DIR)/radiant_cmd.sh backanno -sp 11 -w -o $(OUT_DIR)/$(NAME)_$*_11.vo work/design_$*.tmp/par.udb || true 30 | $(BASE_DIR)/radiant_cmd.sh backanno -sp 12 -w -o $(OUT_DIR)/$(NAME)_$*_12.vo work/design_$*.tmp/par.udb || true 31 | 32 | $(BASE_DIR)/radiant_cmd.sh backanno -min -w -o $(OUT_DIR)/$(NAME)_$*_M.vo work/design_$*.tmp/par.udb || true 33 | 34 | touch $@ 35 | 36 | .PRECIOUS: work/design_%.v work/design_%.bit work/%.stamp 37 | -------------------------------------------------------------------------------- /timing/tools/pickle_sdf.py: -------------------------------------------------------------------------------- 1 | import parse_sdf 2 | import sys, pickle 3 | 4 | def main(): 5 | parsed = parse_sdf.parse_sdf_file(sys.argv[1]) 6 | with open(sys.argv[2], "wb") as pickled: 7 | pickle.dump(parsed, pickled) 8 | 9 | if __name__ == '__main__': 10 | main() 11 | -------------------------------------------------------------------------------- /timing/tools/postprocess.mk: -------------------------------------------------------------------------------- 1 | FOLDER?=output 2 | TOOLS?=tools 3 | UTIL?=util 4 | 5 | vo=$(wildcard $(FOLDER)/*.vo) 6 | vo_json=$(patsubst %.vo,%.vo.json,$(vo)) 7 | 8 | sdf=$(wildcard $(FOLDER)/*.sdf) 9 | sdf_pickled=$(patsubst %.sdf,%.sdf.pickle,$(sdf)) 10 | 11 | all: $(vo_json) $(sdf_pickled) 12 | 13 | %.vo.json: %.vo 14 | python $(TOOLS)/yosysify_verilog.py $< $<_yosys.v 15 | yosys -f verilog -p "write_json $@" $<_yosys.v 16 | rm "$<_yosys.v" 17 | 18 | %.sdf.pickle: %.sdf 19 | python $(TOOLS)/pickle_sdf.py $< $@ 20 | -------------------------------------------------------------------------------- /timing/tools/run-fuzzers.mk: -------------------------------------------------------------------------------- 1 | ARCH?=LIFCL 2 | 3 | fuzzers=$(wildcard fuzzers/$(ARCH)/*) 4 | stamps=$(patsubst %,%/work/stamp,$(fuzzers)) 5 | 6 | all: $(stamps) 7 | 8 | %/work/stamp: 9 | cd $* && $(MAKE) 10 | 11 | -------------------------------------------------------------------------------- /timing/tools/verilog_to_json.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -ex 3 | for vo in $*; do 4 | python yosysify_verilog.py $vo ${vo}_yosys.v 5 | yosys -f verilog -p "write_json ${vo}.json" ${vo}_yosys.v 6 | rm ${vo}_yosys.v 7 | done 8 | -------------------------------------------------------------------------------- /timing/tools/yosysify_verilog.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | in_spec = False 4 | 5 | with open(sys.argv[1], "r") as i: 6 | with open(sys.argv[2], "w") as o: 7 | for line in i: 8 | if " specify" in line or in_spec: 9 | if " endspecify" in line: 10 | in_spec = False 11 | else: 12 | in_spec = True 13 | continue # Yosys can't cope with the more complex features used 14 | o.write(line) 15 | -------------------------------------------------------------------------------- /timing/util/extract_route.py: -------------------------------------------------------------------------------- 1 | import lapie 2 | import pickle 3 | import sys 4 | 5 | def main(): 6 | udb = sys.argv[1] 7 | # Get actual routed path using Tcl 8 | nets = lapie.list_nets(udb) 9 | routing = lapie.get_routing(udb, nets) 10 | 11 | # (source, sink) -> pips 12 | arc2pips = {} 13 | 14 | # Keep track of fanout - we'll need this later! 15 | wire_fanout = {} 16 | 17 | for net in sorted(nets): 18 | if net not in routing: 19 | continue 20 | route = routing[net] 21 | tree = {} 22 | # Construct route tree dst->src 23 | for pip in route.pips: 24 | tree[pip.node2] = pip.node1 25 | # Mapping node -> pin 26 | node2pin = {} 27 | for pin in route.pins: 28 | node2pin[pin.node] = (pin.cell, pin.pin) 29 | 30 | for rpin in route.pins: 31 | pin = (rpin.cell, rpin.pin) 32 | cursor = rpin.node 33 | if cursor not in tree: 34 | continue 35 | pin_route = [] 36 | while True: 37 | wire_fanout[cursor] = wire_fanout.get(cursor, 0) + 1 38 | if cursor not in tree: 39 | if cursor in node2pin: 40 | # Found a complete (src, sink) route 41 | pin_route.reverse() 42 | arc2pips[(node2pin[cursor], pin)] = pin_route 43 | break 44 | prev_wire = tree[cursor] 45 | pin_route.append((prev_wire, cursor)) 46 | cursor = prev_wire 47 | with open(sys.argv[2], "wb") as pf: 48 | pickle.dump(dict(arc2pips=arc2pips, wire_fanout=wire_fanout), pf) 49 | 50 | if __name__ == '__main__': 51 | main() 52 | -------------------------------------------------------------------------------- /timing/util/parse_sdf.py: -------------------------------------------------------------------------------- 1 | """ 2 | Utilities for SDF file parsing to determine cell timings 3 | """ 4 | import sys, pickle 5 | 6 | 7 | class SDFData: 8 | def __init__(self): 9 | self.cells = {} 10 | 11 | class Delay: 12 | def __init__(self, minv, typv, maxv): 13 | self.minv = minv 14 | self.typv = typv 15 | self.maxv = maxv 16 | 17 | 18 | class IOPath: 19 | def __init__(self, from_pin, to_pin, rising, falling): 20 | self.from_pin = from_pin 21 | self.to_pin = to_pin 22 | self.rising = rising 23 | self.falling = falling 24 | 25 | 26 | class SetupHoldCheck: 27 | def __init__(self, pin, clock, setup, hold): 28 | self.pin = pin 29 | self.clock = clock 30 | self.setup = setup 31 | self.hold = hold 32 | 33 | 34 | class WidthCheck: 35 | def __init__(self, clock, width): 36 | self.clock = clock 37 | self.width = width 38 | 39 | 40 | class Interconnect: 41 | def __init__(self, from_net, to_net, rising, falling): 42 | self.from_net = from_net 43 | self.to_net = to_net 44 | self.rising = rising 45 | self.falling = falling 46 | 47 | 48 | class CellData: 49 | def __init__(self, celltype, inst): 50 | self.type = celltype 51 | self.inst = inst 52 | self.entries = [] 53 | self.interconnect = {} 54 | 55 | 56 | def parse_sexpr(stream): 57 | content = [] 58 | buffer = "" 59 | instr = False 60 | while True: 61 | c = stream.read(1) 62 | assert c != "", "unexpected end of file" 63 | if instr: 64 | if c == '"': 65 | instr = False 66 | else: 67 | buffer += c 68 | else: 69 | if c == '(': 70 | content.append(parse_sexpr(stream)) 71 | elif c == ')': 72 | if buffer != "": 73 | content.append(buffer) 74 | return content 75 | elif c.isspace(): 76 | if buffer != "": 77 | content.append(buffer) 78 | buffer = "" 79 | elif c == '"': 80 | instr = True 81 | else: 82 | buffer += c 83 | 84 | 85 | def parse_sexpr_file(filename): 86 | with open(filename, 'r') as f: 87 | assert f.read(1) == '(' 88 | return parse_sexpr(f) 89 | 90 | 91 | def parse_delay(delay): 92 | sp = [int(x) for x in delay.split(":")] 93 | assert len(sp) == 3 94 | return Delay(sp[0], sp[1], sp[2]) 95 | 96 | 97 | def parse_sdf_file(filename, route_mode=False): 98 | sdata = parse_sexpr_file(filename) 99 | assert sdata[0] == "DELAYFILE" 100 | sdf = SDFData() 101 | for entry in sdata[1:]: 102 | if entry[0] != "CELL": 103 | continue 104 | assert entry[1][0] == "CELLTYPE" 105 | celltype = entry[1][1] 106 | assert entry[2][0] == "INSTANCE" 107 | if len(entry[2]) > 1: 108 | if route_mode: 109 | continue 110 | inst = entry[2][1] 111 | else: 112 | inst = "top" 113 | cell = CellData(celltype, inst) 114 | for subentry in entry[3:]: 115 | if subentry[0] == "DELAY": 116 | assert subentry[1][0] == "ABSOLUTE" 117 | for delay in subentry[1][1:]: 118 | if delay[0] == "IOPATH": 119 | cell.entries.append( 120 | IOPath(delay[1], delay[2], parse_delay(delay[3][0]), parse_delay(delay[4][0]))) 121 | elif delay[0] == "INTERCONNECT": 122 | cell.interconnect[(delay[1], delay[2])] = Interconnect(delay[1], delay[2], 123 | parse_delay(delay[3][0]), 124 | parse_delay(delay[4][0])) 125 | elif subentry[0] == "TIMINGCHECK": 126 | for check in subentry[1:]: 127 | if check[0] == "SETUPHOLD": 128 | cell.entries.append( 129 | SetupHoldCheck(check[1], check[2], parse_delay(check[3][0]), parse_delay(check[4][0]))) 130 | elif check[0] == "WIDTH": 131 | cell.entries.append(WidthCheck(check[1], parse_delay(check[2][0]))) 132 | sdf.cells[inst] = cell 133 | return sdf 134 | -------------------------------------------------------------------------------- /timing/util/timing_config.py: -------------------------------------------------------------------------------- 1 | # These pip classes always have zero delay 2 | 3 | zero_delay_classes = { 4 | "slice_internal", 5 | "vcc_internal", 6 | "s1:span1s -> a", 7 | "jeclkdiv0_mid_entry", 8 | "jeclkdiv0 -> jvpf_mid", 9 | "f -> a", 10 | "f -> b", 11 | "f -> c", 12 | "f -> d", 13 | "q -> abcd", 14 | "cibmuxo -> io18", 15 | "clk -> clk_dff", 16 | } 17 | -------------------------------------------------------------------------------- /tools/.gitignore: -------------------------------------------------------------------------------- 1 | *.tmp 2 | *.log 3 | -------------------------------------------------------------------------------- /tools/bitstreamcache.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Bitstream cache tool for prjoxide 4 | 5 | This avoids expensive bitstream rebuilds when making small changes to the 6 | fuzzer and the Verilog input is largely unchanged. 7 | 8 | Note that it is disabled by default. Run: 9 | tools/bitstreamcache.py init 10 | to start using it. 11 | 12 | Usage: 13 | tools/bitstreamcache.py fetch ... 14 | if a bitstream with the given configuration and input already exists, 15 | copy the products to and return 0. Otherwise return 1. 16 | 17 | tools/bitstreamcache.py commit output .. 18 | save output files as the products of the input files and configuration 19 | 20 | gzip and gunzip must be on your path for it to work 21 | 22 | """ 23 | 24 | import sys, os, shutil, hashlib, gzip 25 | 26 | root_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..") 27 | cache_dir = os.path.join(root_dir, ".bitstreamcache") 28 | 29 | def get_hash(device, input_files): 30 | hasher = hashlib.sha1() 31 | hasher.update(b"DEVICE") 32 | hasher.update(device.encode('utf-8')) 33 | for envkey in ("GEN_RBF", "DEV_PACKAGE", "SPEED_GRADE", "STRUCT_VER", "RBK_MODE"): 34 | if envkey in os.environ: 35 | hasher.update(envkey.encode('utf-8')) 36 | hasher.update(os.environ[envkey].encode('utf-8')) 37 | for fname in input_files: 38 | ext = os.path.splitext(fname)[1] 39 | hasher.update("input{}".format(ext).encode('utf-8')) 40 | with open(fname, "rb") as f: 41 | hasher.update(f.read()) 42 | return hasher.hexdigest() 43 | 44 | if len(sys.argv) < 2: 45 | print("Expected command (init|fetch|commit)") 46 | sys.exit(1) 47 | cmd = sys.argv[1] 48 | if cmd == "init": 49 | if not os.path.exists(cache_dir): 50 | os.mkdir(cache_dir) 51 | if cmd == "fetch": 52 | if not os.path.exists(cache_dir): 53 | sys.exit(1) 54 | if len(sys.argv) < 5: 55 | print("Usage: tools/bitstreamcache.py fetch ...") 56 | sys.exit(1) 57 | h = get_hash(sys.argv[2], sys.argv[4:]) 58 | print(h) 59 | cache_entry = os.path.join(cache_dir, h) 60 | if not os.path.exists(cache_entry) or len(os.listdir(cache_entry)) == 0: 61 | sys.exit(1) 62 | for outprod in os.listdir(cache_entry): 63 | bn = outprod 64 | assert bn.endswith(".gz") 65 | bn = bn[:-3] 66 | with gzip.open(os.path.join(cache_entry, outprod), 'rb') as gzf: 67 | with open(os.path.join(sys.argv[3], bn), 'wb') as outf: 68 | outf.write(gzf.read()) 69 | sys.exit(0) 70 | if cmd == "commit": 71 | if not os.path.exists(cache_dir): 72 | sys.exit(0) 73 | idx = sys.argv.index("output") 74 | if len(sys.argv) < 6 or idx == -1: 75 | print("Usage: tools/bitstreamcache.py commit output ..") 76 | sys.exit(1) 77 | h = get_hash(sys.argv[2], sys.argv[3:idx]) 78 | cache_entry = os.path.join(cache_dir, h) 79 | if not os.path.exists(cache_entry): 80 | os.mkdir(cache_entry) 81 | for outprod in sys.argv[idx+1:]: 82 | bn = os.path.basename(outprod) 83 | cn = os.path.join(cache_entry, bn + ".gz") 84 | with gzip.open(cn, 'wb') as gzf: 85 | with open(outprod, 'rb') as inf: 86 | gzf.write(inf.read()) 87 | sys.exit(0) 88 | -------------------------------------------------------------------------------- /tools/extract_tilegrid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | This script reads the output from Lattice's bstool in "test" mode, which should be invoked thus: 4 | 5 | ``` 6 | bstool -t bitstream.bit > bitstream.test 7 | ``` 8 | 9 | and from it obtains a list of tiles with the following information: 10 | - Tile name (with position encoded in the name) 11 | - Tile type 12 | - Frame and bit offset 13 | - Bitstream size in bits ("rows") and frames ("cols") 14 | and creates a JSON file as output 15 | """ 16 | 17 | import sys, re 18 | import json, argparse 19 | 20 | tile_re = re.compile( 21 | r'^Tile\s+([A-Z0-9a-z_/]+)\s+\((\d+), (\d+)\)\s+bitmap offset\s+\((\d+), (\d+)\)\s+\<([A-Z0-9a-z_/]+)>\s*$') 22 | end_digit_re = re.compile( 23 | r'(\d+)$') 24 | 25 | parser = argparse.ArgumentParser(description=__doc__) 26 | parser.add_argument('device', type=str, 27 | help="device name") 28 | parser.add_argument('infile', type=argparse.FileType('r'), 29 | help="input file from bstool") 30 | parser.add_argument('outfile', type=argparse.FileType('w'), 31 | help="output JSON file") 32 | rc_re = re.compile(r'R(\d+)C(\d+)') 33 | 34 | # For some reason TAP tiles don't have a column in their name. Restore them, 35 | # using locations determined from Radiant physical view (for now) 36 | tap_frame_to_col_100 = { 37 | 16: 14, 38 | # mid: 26 39 | 22: 38, 40 | # mid: 50 41 | 28: 62, 42 | # mid: 74 43 | 34: 86, 44 | # mid: 98 45 | 40: 110, 46 | # mid: 122 47 | 46: 134, 48 | 52: 146, 49 | } 50 | tap_frame_to_col_40 = { 51 | 16: 14, 52 | 22: 38, 53 | 28: 62, 54 | 34: 74 55 | } 56 | tap_frame_to_col_17 = { 57 | 16: 14, 58 | 22: 26, 59 | 28: 50, 60 | 34: 62 61 | } 62 | 63 | def get_tf2c(dev): 64 | if dev == "LFCPNX-100": 65 | return tap_frame_to_col_100 66 | elif dev == "LIFCL-40" or dev == "LFDN2X-40": 67 | return tap_frame_to_col_40 68 | elif dev == "LIFCL-17": 69 | return tap_frame_to_col_17 70 | else: 71 | assert False 72 | 73 | def main(argv): 74 | args = parser.parse_args(argv[1:]) 75 | tiles = {} 76 | current_tile = None 77 | tap_frame_to_col = get_tf2c(args.device) 78 | for line in args.infile: 79 | tile_m = tile_re.match(line) 80 | if tile_m: 81 | name = tile_m.group(6) 82 | current_tile = { 83 | "tiletype": tile_m.group(1), 84 | "start_bit": int(tile_m.group(4)), 85 | "start_frame": int(tile_m.group(5)), 86 | "bits": int(tile_m.group(2)), 87 | "frames": int(tile_m.group(3)), 88 | } 89 | s = rc_re.search(name) 90 | if not s: 91 | assert current_tile["start_frame"] in tap_frame_to_col 92 | # Regularise tile name for TAP tiles 93 | col = tap_frame_to_col[current_tile["start_frame"]] 94 | em = end_digit_re.search(name) 95 | row = int(em.group(1)) 96 | name = "{}_R{}C{}".format(name[0:-len(em.group(1))], row, col) 97 | current_tile["y"] = row 98 | current_tile["x"] = col 99 | else: 100 | current_tile["y"] = int(s.group(1)) 101 | current_tile["x"] = int(s.group(2)) 102 | identifier = name + ":" + tile_m.group(1) 103 | assert identifier not in tiles 104 | tiles[identifier] = current_tile 105 | json.dump({"tiles": tiles}, args.outfile, sort_keys=True, indent=4) 106 | args.outfile.write("\n") 107 | if __name__ == "__main__": 108 | main(sys.argv) 109 | -------------------------------------------------------------------------------- /tools/fixup_io_tilegrid.py: -------------------------------------------------------------------------------- 1 | import database 2 | import tiles 3 | import json 4 | from os import path 5 | 6 | """ 7 | Despite Lattice assigning them the same tile type; "odd" and "even" top/left/right IO 8 | locations have slightly different routing - swapped output tristate and data 9 | 10 | This script fixes this by patching tile names 11 | """ 12 | 13 | for f, d in [("LIFCL", "LIFCL-40"), ("LIFCL", "LFD2NX-40"), ("LFCPNX", "LFCPNX-100")]: 14 | tgp = path.join(database.get_db_root(), f, d, "tilegrid.json") 15 | with open(tgp, "r") as infile: 16 | tg = json.load(infile)["tiles"] 17 | 18 | tiles_by_xy = [[]] 19 | max_row = 0 20 | max_col = 0 21 | for tile in sorted(tg.keys()): 22 | r, c = tiles.pos_from_name(tile) 23 | max_row = max(r, max_row) 24 | max_col = max(c, max_col) 25 | while r >= len(tiles_by_xy): 26 | tiles_by_xy.append([]) 27 | while c >= len(tiles_by_xy[r]): 28 | tiles_by_xy[r].append([]) 29 | tiles_by_xy[r][c].append(tile) 30 | 31 | # Top tiles 32 | is_odd = False 33 | for col in tiles_by_xy[0]: 34 | for tile in col: 35 | tt = tiles.type_from_fullname(tile) 36 | if not tt.startswith("SYSIO"): 37 | continue 38 | # Don't rename special or already-renamed tiles 39 | if tt[-1].isdigit(): 40 | new_name = tile + ("_ODD" if is_odd else "_EVEN") 41 | assert new_name not in tg 42 | tg[new_name] = dict(tg[tile]) 43 | tg[new_name]["tiletype"] = tg[new_name]["tiletype"] + ("_ODD" if is_odd else "_EVEN") 44 | del tg[tile] 45 | is_odd = not is_odd 46 | 47 | 48 | # Left/right tiles 49 | for tc in (0, max_col): 50 | is_odd = False 51 | bank = "" 52 | for row in tiles_by_xy: 53 | for tile in row[tc]: 54 | tt = tiles.type_from_fullname(tile) 55 | if not tt.startswith("SYSIO"): 56 | continue 57 | if tt.endswith("REM"): 58 | continue 59 | tile_bank = tt[tt.find("B")+1] 60 | if tile_bank != bank: 61 | is_odd = False 62 | bank = tile_bank 63 | if tt[-1].isdigit(): 64 | new_name = tile + ("_ODD" if is_odd else "_EVEN") 65 | assert new_name not in tg 66 | tg[new_name] = dict(tg[tile]) 67 | tg[new_name]["tiletype"] = tg[new_name]["tiletype"] + ("_ODD" if is_odd else "_EVEN") 68 | del tg[tile] 69 | is_odd = not is_odd 70 | with open(tgp, "w") as outfile: 71 | json.dump({"tiles": tg}, outfile, sort_keys=True, indent=4) 72 | -------------------------------------------------------------------------------- /tools/get_device_tilegrid.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | set -ex 4 | 5 | GEN_RBF=1 ../radiant.sh $1 ../minitests/simple/wire.v 6 | 7 | # Strip out bitstream data to prevent bstool crashing 8 | # we only want tile offsets anyway 9 | sed -i 's/^[01]\+$//g' ../minitests/simple/wire.rbt 10 | ../radiant_cmd.sh bstool -t ../minitests/simple/wire.rbt > ../minitests/simple/wire.dump 2>/dev/null 11 | -------------------------------------------------------------------------------- /tools/html_tilebits.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Convert the tile grid for a given family and device to HTML format 4 | """ 5 | import sys, re 6 | import argparse 7 | import database 8 | import libpyprjoxide 9 | from os import path 10 | 11 | parser = argparse.ArgumentParser(description=__doc__) 12 | parser.add_argument('family', type=str, 13 | help="FPGA family (e.g. LIFCL)") 14 | parser.add_argument('device', type=str, 15 | help="FPGA device (e.g. LIFCL-40)") 16 | parser.add_argument('tiletype', type=str, 17 | help="tile type (e.g. PLC)") 18 | parser.add_argument('outdir', type=str, 19 | help="output HTML directory") 20 | 21 | def main(argv): 22 | args = parser.parse_args(argv[1:]) 23 | db = libpyprjoxide.Database(database.get_db_root()) 24 | docs_root = path.join(database.get_oxide_root(), "docs") 25 | libpyprjoxide.write_tilebits_html(db, docs_root, args.family, args.device, args.tiletype, args.outdir) 26 | 27 | if __name__ == "__main__": 28 | main(sys.argv) 29 | -------------------------------------------------------------------------------- /tools/html_tilegrid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Convert the tile grid for a given family and device to HTML format 4 | """ 5 | import sys, re 6 | import argparse 7 | import database 8 | import libpyprjoxide 9 | 10 | parser = argparse.ArgumentParser(description=__doc__) 11 | parser.add_argument('family', type=str, 12 | help="FPGA family (e.g. LIFCL)") 13 | parser.add_argument('device', type=str, 14 | help="FPGA device (e.g. LIFCL-40)") 15 | parser.add_argument('outfile', type=str, 16 | help="output HTML file") 17 | parser.add_argument('routfile', type=str, 18 | help="regions output HTML file") 19 | 20 | def main(argv): 21 | args = parser.parse_args(argv[1:]) 22 | db = libpyprjoxide.Database(database.get_db_root()) 23 | libpyprjoxide.write_tilegrid_html(db, args.family, args.device, args.outfile) 24 | libpyprjoxide.write_region_html(db, args.family, args.device, args.routfile) 25 | 26 | if __name__ == "__main__": 27 | main(sys.argv) 28 | -------------------------------------------------------------------------------- /tools/parse_pins.py: -------------------------------------------------------------------------------- 1 | import json, sys 2 | 3 | # Parse a Lattice pinout CSV file to a JSON file for the database 4 | # Usage: parse_pins.py pinout.csv iodb.json 5 | 6 | def main(): 7 | packages = [] 8 | pads = [] 9 | with open(sys.argv[1], "r") as csvf: 10 | for line in csvf: 11 | sl = line.replace('"', '') 12 | sl = sl.strip() 13 | if len(sl) == 0 or sl.startswith('#'): 14 | continue 15 | splitl = sl.split(',') 16 | if len(splitl) == 0 or splitl[0] == '': 17 | continue 18 | if len(packages) == 0: 19 | # Header line 20 | COL_PADN = 0 21 | COL_FUNC = 1 22 | COL_CUST_NAME = 2 23 | COL_BANK = 3 24 | COL_DF = 4 25 | COL_LVDS = 5 26 | COL_HIGHSPEED = 6 27 | COL_DQS = 7 28 | COL_PKG_START = 8 29 | 30 | if splitl[0] == "index": 31 | # new style pinout 32 | COL_PADN = 1 33 | COL_FUNC = 2 34 | COL_CUST_NAME = None 35 | COL_BANK = 3 36 | COL_DF = 5 37 | COL_LVDS = 6 38 | COL_HIGHSPEED = 7 39 | COL_DQS = 4 40 | COL_PKG_START = 8 41 | elif splitl[2] == "BANK": 42 | # LIFCL-17 style pinout 43 | COL_PADN = 0 44 | COL_FUNC = 1 45 | COL_CUST_NAME = None 46 | COL_BANK = 2 47 | COL_DF = 4 48 | COL_LVDS = 5 49 | COL_HIGHSPEED = 6 50 | COL_DQS = 3 51 | COL_PKG_START = 7 52 | assert splitl[COL_PADN] == "PADN" 53 | packages = splitl[COL_PKG_START:] 54 | continue 55 | func = splitl[COL_FUNC] 56 | io_offset = -1 57 | io_side = '' 58 | io_spfunc = [] 59 | io_pio = -1 60 | io_dqs = [] 61 | io_vref = -1 62 | if len(func) >= 4 and func[0] == 'P' and func[1] in ('T', 'L', 'R', 'B') and func[-1] in ('A', 'B', 'C', 'D'): 63 | # Regular PIO 64 | io_offset = int(func[2:-1]) 65 | io_side = func[1] 66 | io_spfunc = splitl[COL_DF].split('/') 67 | io_pio = "ABCD".index(func[-1]) 68 | if io_spfunc == ['-']: 69 | io_spfunc = [] 70 | io_dqs = splitl[COL_DQS] 71 | if io_dqs == "" or io_dqs == "-": 72 | io_dqs = [] 73 | elif io_dqs.find("DQSN") == 1: 74 | io_dqs = [2, int(io_dqs[5:])] 75 | elif io_dqs.find("DQS") == 1: 76 | io_dqs = [1, int(io_dqs[4:])] 77 | elif io_dqs.find("DQ") == 1: 78 | io_dqs = [0, int(io_dqs[3:])] 79 | else: 80 | assert False, "bad DQS type" 81 | 82 | for spf in io_spfunc: 83 | if spf.startswith('VREF'): 84 | bank, _, ref = spf[4:].partition('_') 85 | assert int(bank) == int(splitl[COL_BANK]) 86 | io_vref = int(ref) 87 | 88 | elif func.startswith('ADC_') or func.startswith('DPHY') or func.startswith('SD0') or func.startswith('JTAG_'): 89 | # Special IO, that we still want in the db 90 | io_spfunc = [func, ] 91 | else: 92 | continue 93 | io_bank = int(splitl[COL_BANK]) if splitl[COL_BANK].isdigit() else -1 94 | io_pins = splitl[COL_PKG_START:] 95 | pads.append(dict(side=io_side, offset=io_offset, pio=io_pio, func=io_spfunc, bank=io_bank, dqs=io_dqs, vref=io_vref, pins=io_pins)) 96 | with open(sys.argv[2], "w") as jsf: 97 | jsf.write(json.dumps(dict(packages=packages, pads=pads), sort_keys=True, indent=4)) 98 | jsf.write('\n') 99 | if __name__ == '__main__': 100 | main() 101 | -------------------------------------------------------------------------------- /tools/test_sites.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Convert the tile grid for a given family and device to HTML format 4 | """ 5 | import sys, re 6 | import argparse 7 | import database 8 | import libpyprjoxide 9 | 10 | 11 | def main(argv): 12 | db = libpyprjoxide.Database(database.get_db_root()) 13 | libpyprjoxide.build_sites(db, "LIFCL-40", "PLC") 14 | 15 | if __name__ == "__main__": 16 | main(sys.argv) 17 | -------------------------------------------------------------------------------- /tools/tilegrid_all.py: -------------------------------------------------------------------------------- 1 | 2 | #!/usr/bin/env python3 3 | """ 4 | For each family and device, obtain a tilegrid and save it in the database 5 | """ 6 | 7 | import os 8 | from os import path 9 | import subprocess 10 | import extract_tilegrid 11 | 12 | import database 13 | 14 | def main(): 15 | devices = database.get_devices() 16 | for family in sorted(devices["families"].keys()): 17 | for device in sorted(devices["families"][family]["devices"].keys()): 18 | output_file = path.join(database.get_db_subdir(family, device), "tilegrid.json") 19 | subprocess.check_call(["./get_device_tilegrid.sh", device]) 20 | extract_tilegrid.main(["extract_tilegrid", device, "../minitests/simple/wire.dump", output_file]) 21 | 22 | 23 | if __name__ == "__main__": 24 | main() 25 | -------------------------------------------------------------------------------- /util/common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gatecat/prjoxide/30712ff988a3ea7700fa11b87ae2d77e55c7c468/util/common/__init__.py -------------------------------------------------------------------------------- /util/common/database.py: -------------------------------------------------------------------------------- 1 | """ 2 | Database and Database Path Management 3 | """ 4 | import os 5 | from os import path 6 | import json 7 | import subprocess 8 | 9 | 10 | def get_oxide_root(): 11 | """Return the absolute path to the Project Oxide repo root""" 12 | return path.abspath(path.join(__file__, "../../../")) 13 | 14 | 15 | def get_db_root(): 16 | """ 17 | Return the path containing the Project Oxide database 18 | This is database/ in the repo, unless the `PRJOXIDE_DB` environment 19 | variable is set to another value. 20 | """ 21 | if "PRJOXIDE_DB" in os.environ and os.environ["PRJOXIDE_DB"] != "": 22 | return os.environ["PRJOXIDE_DB"] 23 | else: 24 | return path.join(get_oxide_root(), "database") 25 | 26 | 27 | def get_db_subdir(family = None, device = None, package = None): 28 | """ 29 | Return the DB subdirectory corresponding to a family, device and 30 | package (all if applicable), creating it if it doesn't already 31 | exist. 32 | """ 33 | subdir = get_db_root() 34 | dparts = [family, device, package] 35 | for dpart in dparts: 36 | if dpart is None: 37 | break 38 | subdir = path.join(subdir, dpart) 39 | if not path.exists(subdir): 40 | os.mkdir(subdir) 41 | return subdir 42 | 43 | 44 | def get_tilegrid(family, device): 45 | """ 46 | Return the deserialised tilegrid for a family, device 47 | """ 48 | tgjson = path.join(get_db_subdir(family, device), "tilegrid.json") 49 | with open(tgjson, "r") as f: 50 | return json.load(f) 51 | 52 | 53 | def get_devices(): 54 | """ 55 | Return the deserialised content of devices.json 56 | """ 57 | djson = path.join(get_db_root(), "devices.json") 58 | with open(djson, "r") as f: 59 | return json.load(f) 60 | 61 | 62 | def get_db_commit(): 63 | return subprocess.getoutput('git -C "{}" rev-parse HEAD'.format(get_db_root())) 64 | -------------------------------------------------------------------------------- /util/common/radiant.py: -------------------------------------------------------------------------------- 1 | """ 2 | Python wrapper for `radiant.sh` 3 | """ 4 | from os import path 5 | import os 6 | import subprocess 7 | import database 8 | 9 | 10 | def run(device, source, struct_ver=True, raw_bit=False, pdcfile=None, rbk_mode=False): 11 | """ 12 | Run radiant.sh with a given device name and source Verilog file 13 | """ 14 | env = os.environ.copy() 15 | if struct_ver: 16 | env["STRUCT_VER"] = "1" 17 | if raw_bit: 18 | env["GEN_RBT"] = "1" 19 | if rbk_mode: 20 | env["RBK_MODE"] = "1" 21 | dsh_path = path.join(database.get_oxide_root(), "radiant.sh") 22 | return subprocess.run(["bash",dsh_path,device,source], env=env) 23 | -------------------------------------------------------------------------------- /util/common/tiles.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | pos_re = re.compile(r'R(\d+)C(\d+)') 4 | 5 | 6 | def pos_from_name(tile): 7 | """ 8 | Extract the tile position as a (row, column) tuple from its name 9 | """ 10 | s = pos_re.search(tile) 11 | assert s 12 | return int(s.group(1)), int(s.group(2)) 13 | 14 | 15 | def type_from_fullname(tile): 16 | """ 17 | Extract the type from a full tile name (in name:type) format 18 | """ 19 | return tile.split(":")[1] 20 | -------------------------------------------------------------------------------- /util/fuzz/fuzzconfig.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module provides a structure to define the fuzz environment 3 | """ 4 | import os 5 | from os import path 6 | from string import Template 7 | import radiant 8 | import database 9 | import libpyprjoxide 10 | 11 | db = None 12 | 13 | class FuzzConfig: 14 | def __init__(self, device, job, tiles, sv): 15 | """ 16 | :param job: user-friendly job name, used for folder naming etc 17 | :param device: Target device name 18 | :param tiles: List of tiles to consider during fuzzing 19 | :param sv: Minimal structural Verilog file to use as a base for interconnect fuzzing 20 | """ 21 | self.device = device 22 | self.job = job 23 | self.tiles = tiles 24 | self.sv = sv 25 | self.rbk_mode = True if self.device == "LFCPNX-100" else False 26 | self.struct_mode = True 27 | self.udb_specimen = None 28 | 29 | @property 30 | def workdir(self): 31 | return path.join(".", "work", self.job) 32 | 33 | def make_workdir(self): 34 | """Create the working directory for this job, if it doesn't exist already""" 35 | os.makedirs(self.workdir, exist_ok=True) 36 | 37 | def setup(self, skip_specimen=False): 38 | """ 39 | Create a working directory, and run Radiant on a minimal Verilog file to create a udb for Tcl usage etc 40 | """ 41 | 42 | # Load the global database if it doesn't exist already 43 | global db 44 | if db is None: 45 | db = libpyprjoxide.Database(database.get_db_root()) 46 | 47 | self.make_workdir() 48 | if not skip_specimen: 49 | self.build_design(self.sv, {}) 50 | 51 | def build_design(self, des_template, substitutions, prefix="", substitute=True): 52 | """ 53 | Run Radiant on a given design template, applying a map of substitutions, plus some standard substitutions 54 | if not overriden. 55 | 56 | :param des_template: path to template (structural) Verilog file 57 | :param substitutions: dictionary containing template subsitutions to apply to Verilog file 58 | :param prefix: prefix to append to filename, for running concurrent jobs without collisions 59 | 60 | Returns the path to the output bitstream 61 | """ 62 | subst = dict(substitutions) 63 | if "arcs_attr" not in subst: 64 | subst["arcs_attr"] = "" 65 | if "device" not in subst: 66 | subst["device"] = self.device 67 | desfile = path.join(self.workdir, prefix + "design.v") 68 | bitfile = path.join(self.workdir, prefix + "design.bit") 69 | 70 | if "sysconfig" in subst: 71 | pdcfile = path.join(self.workdir, prefix + "design.pdc") 72 | with open(pdcfile, "w") as pdcf: 73 | pdcf.write("ldc_set_sysconfig {{{}}}\n".format(subst["sysconfig"])) 74 | 75 | if path.exists(bitfile): 76 | os.remove(bitfile) 77 | with open(des_template, "r") as inf: 78 | with open(desfile, "w") as ouf: 79 | if substitute: 80 | ouf.write(Template(inf.read()).substitute(**subst)) 81 | else: 82 | ouf.write(inf.read()) 83 | radiant.run(self.device, desfile, struct_ver=self.struct_mode, raw_bit=False, rbk_mode=self.rbk_mode) 84 | if self.struct_mode and self.udb_specimen is None: 85 | self.udb_specimen = path.join(self.workdir, prefix + "design.tmp", "par.udb") 86 | return bitfile 87 | 88 | 89 | @property 90 | def udb(self): 91 | """ 92 | A udb file specimen for Tcl 93 | """ 94 | assert self.udb_specimen is not None 95 | return self.udb_specimen 96 | -------------------------------------------------------------------------------- /util/fuzz/fuzzloops.py: -------------------------------------------------------------------------------- 1 | """ 2 | General Utilities for Fuzzing 3 | """ 4 | 5 | import os 6 | from threading import Thread, RLock 7 | 8 | def parallel_foreach(items, func): 9 | """ 10 | Run a function over a list of values, running a number of jobs 11 | in parallel. OXIDE_JOBS should be set to the number of jobs to run, 12 | defaulting to 4. 13 | """ 14 | if "OXIDE_JOBS" in os.environ: 15 | jobs = int(os.environ["OXIDE_JOBS"]) 16 | else: 17 | jobs = 4 18 | items_queue = list(items) 19 | items_lock = RLock() 20 | 21 | def runner(): 22 | while True: 23 | with items_lock: 24 | if len(items_queue) == 0: 25 | return 26 | item = items_queue[0] 27 | items_queue.pop(0) 28 | func(item) 29 | 30 | threads = [Thread(target=runner) for i in range(jobs)] 31 | for t in threads: 32 | t.start() 33 | for t in threads: 34 | t.join() 35 | -------------------------------------------------------------------------------- /util/fuzz/get_params.py: -------------------------------------------------------------------------------- 1 | import re, sys 2 | 3 | # Read a Lattice Verilog file and extract the parameters and their widths/set of values 4 | 5 | ov_re = re.compile(r'\\otherValues = "{([^}]*)}"') 6 | p_re = re.compile(r'parameter ([A-Z0-9a-z_]*) = "([^"]*)"') 7 | # returns [(word_name, word_length)], [(enum_name, [enum_values])] 8 | def get_params(f): 9 | words = [] 10 | enums = [] 11 | with open(f, "r") as pf: 12 | other_vals = None 13 | for line in pf: 14 | ov_m = ov_re.search(line) 15 | if ov_m: 16 | other_vals = ov_m.group(1).split(",") 17 | if other_vals == [""]: 18 | other_vals = [] 19 | continue 20 | p_m = p_re.search(line) 21 | if p_m: 22 | name = p_m.group(1) 23 | val = p_m.group(2) 24 | if val.startswith("0b"): 25 | words.append((name, len(val) - 2, val[2:])) 26 | else: 27 | assert len(other_vals) > 0 28 | enums.append((name, [val] + other_vals)) 29 | return (words, enums) 30 | 31 | def main(): 32 | words, enums = get_params(sys.argv[1]) 33 | for n, l, d in words: 34 | print("{}[{}] {}".format(n, l, d)) 35 | for n, v in enums: 36 | print("{} {{{}}}".format(n, ", ".join(v))) 37 | 38 | if __name__ == '__main__': 39 | main() 40 | -------------------------------------------------------------------------------- /util/fuzz/interconnect.py: -------------------------------------------------------------------------------- 1 | """ 2 | Utilities for fuzzing interconect 3 | """ 4 | 5 | import threading 6 | import tiles 7 | import libpyprjoxide 8 | import fuzzconfig 9 | import fuzzloops 10 | import lapie 11 | 12 | def fuzz_interconnect( 13 | config, 14 | nodenames, 15 | regex=False, 16 | nodename_predicate=lambda x, nets: True, 17 | pip_predicate=lambda x, nets: True, 18 | bidir=False, 19 | nodename_filter_union=False, 20 | full_mux_style=False, 21 | ignore_tiles=set(), 22 | extra_substs={}, 23 | fc_filter=lambda x: True 24 | ): 25 | """ 26 | Fuzz interconnect given a list of nodenames to analyse. Pips associated these nodenames will be found using the Tcl 27 | API and bits identified as described above. 28 | 29 | :param config: FuzzConfig instance containing target device and tile(s) of interest 30 | :param nodenames: A list of nodes or node regexes in Lattice (un-normalised) format to analyse 31 | :param regex: enable regex names 32 | :param nodename_predicate: a predicate function which should return True if a netname is of interest, given 33 | the netname and the set of all nets 34 | :param pip_predicate: a predicate function which should return True if an arc, given the arc as a (source, sink) 35 | tuple and the set of all nodenames, is of interest 36 | :param bidir: if True, pips driven by as well as driving the given nodenames will be considered during analysis 37 | :param nodename_filter_union: if True, pips will be included if either net passes nodename_predicate, if False both 38 | nets much pass the predicate. 39 | :param full_mux_style: if True, is a full mux, and all 0s is considered a valid config bit possibility 40 | on certain families. 41 | :param ignore_tiles: don't reject pips that touch these tils 42 | :param extra_substs: extra SV substitutions 43 | :param fc_filter: skip fixed connections if this returns false for a sink wire name 44 | """ 45 | nodes = lapie.get_node_data(config.udb, nodenames, regex) 46 | base_bitf = config.build_design(config.sv, extra_substs, "base_") 47 | 48 | all_wirenames = set([n.name for n in nodes]) 49 | all_pips = set() 50 | for node in nodes: 51 | for p in node.uphill_pips: 52 | all_pips.add((p.from_wire, p.to_wire)) 53 | if bidir: 54 | for p in node.downhill_pips: 55 | all_pips.add((p.from_wire, p.to_wire)) 56 | per_sink = list(sorted(all_pips)) 57 | # First filter using netname predicate 58 | if nodename_filter_union: 59 | all_pips = filter(lambda x: nodename_predicate(x[0], all_wirenames) and nodename_predicate(x[1], all_wirenames), 60 | all_pips) 61 | else: 62 | all_pips = filter(lambda x: nodename_predicate(x[0], all_wirenames) or nodename_predicate(x[1], all_wirenames), 63 | all_pips) 64 | # Then filter using the pip predicate 65 | fuzz_pips = list(filter(lambda x: pip_predicate(x, all_wirenames), all_pips)) 66 | if len(fuzz_pips) == 0: 67 | return 68 | sinks = {} 69 | for from_wire, to_wire in fuzz_pips: 70 | if to_wire not in sinks: 71 | sinks[to_wire] = [] 72 | sinks[to_wire].append(from_wire) 73 | def per_sink(to_wire): 74 | # Get a unique prefix from the thread ID 75 | prefix = "thread{}_".format(threading.get_ident()) 76 | fz = libpyprjoxide.Fuzzer.pip_fuzzer(fuzzconfig.db, base_bitf, set(config.tiles), to_wire, config.tiles[0], ignore_tiles, full_mux_style, not (fc_filter(to_wire))) 77 | for from_wire in sinks[to_wire]: 78 | arcs_attr = r', \dm:arcs ="{}.{}"'.format(to_wire, from_wire) 79 | substs = extra_substs.copy() 80 | substs["arcs_attr"] = arcs_attr 81 | arc_bit = config.build_design(config.sv, substs, prefix) 82 | fz.add_pip_sample(fuzzconfig.db, from_wire, arc_bit) 83 | fz.solve(fuzzconfig.db) 84 | fuzzloops.parallel_foreach(list(sorted(sinks.keys())), per_sink) 85 | --------------------------------------------------------------------------------