├── .gitignore ├── LICENSE ├── README.md └── hardware ├── README.md ├── bbq ├── README.md ├── generator │ ├── bbq.py │ ├── bbq_level.py │ ├── bbq_level_ingress.py │ ├── bbq_level_lx.py │ ├── bbq_level_pb.py │ ├── bbq_level_steering.py │ └── codegen.py ├── ip │ ├── .gitignore │ └── my_pll.tcl.template ├── quartus │ ├── .gitignore │ ├── bbq.qpf │ ├── bbq.qsf │ └── bbq.sdc ├── scripts │ ├── bisect_fmax.sh │ ├── sweep_bisect_fmax.sh │ ├── sweep_params.sh │ ├── sweep_seeds.sh │ └── synthesize.sh ├── setup.sh ├── src │ ├── common │ │ ├── bram_simple2port.v │ │ └── sc_fifo.v │ ├── ffs.sv │ ├── heap_ops.sv │ └── top.sv └── tb │ ├── .gitignore │ ├── README.md │ ├── bbq │ ├── run_test.sh │ └── tb_bbq.sv │ ├── ffs │ ├── run_test.sh │ └── tb_ffs.sv │ └── run_common.sh ├── bmw ├── ip │ ├── .gitignore │ └── my_pll.tcl.template ├── quartus │ ├── .gitignore │ ├── bmw.qpf │ ├── bmw.qsf │ └── bmw.sdc ├── scripts │ ├── bisect_fmax.sh │ ├── sweep_bisect_fmax.sh │ └── synthesize.sh ├── setup.sh └── src │ ├── bmw_sram.sv │ ├── bmw_sram_top.sv │ ├── common │ ├── bram_simple2port.v │ └── dual_port_bram.v │ ├── infer_sdram.sv │ └── top.sv ├── pieo ├── ip │ ├── .gitignore │ └── my_pll.tcl.template ├── quartus │ ├── .gitignore │ ├── pieo.qpf │ ├── pieo.qsf │ └── pieo.sdc ├── scripts │ ├── bisect_fmax.sh │ ├── sweep_bisect_fmax.sh │ └── synthesize.sh ├── setup.sh └── src │ ├── common │ └── dual_port_bram.v │ ├── pieo.sv │ ├── pieo_datatypes.sv │ └── top.sv └── pifo ├── ip ├── .gitignore └── my_pll.tcl.template ├── quartus ├── .gitignore ├── pifo.qpf ├── pifo.qsf └── pifo.sdc ├── scripts ├── bisect_fmax.sh ├── sweep_bisect_fmax.sh └── synthesize.sh ├── setup.sh └── src ├── panic_pifo.sv ├── pifo.sv └── top.sv /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .dvt 3 | dvt_build.log 4 | __pycache__/ 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The Clear BSD License 2 | 3 | Copyright (c) 2024 Carnegie Mellon University 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted (subject to the limitations in the disclaimer 8 | below) provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, 11 | this list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from this 19 | software without specific prior written permission. 20 | 21 | NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY 22 | THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 23 | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 25 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 26 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 29 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 30 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | POSSIBILITY OF SUCH DAMAGE. 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # BBQ 4 | 5 | The Bitmapped Bucket Queue (or BBQ for short) is a **highly scalable and performant priority queue architecture** for hardware packet scheduling. Underlying BBQ is an Integer Priority Queueing (IPQ) scheme that circumvents the complexity barrier imposed by comparison-based sorting, allowing it to scale to a large number of queue elements without increasing the runtime complexity of operations. Refer to the [NSDI '24 paper](https://www.usenix.org/conference/nsdi24/presentation/atre) for details about BBQ's design and how it makes it feasible, for the first time, to implement programmable packet scheduling on modern line-rate switches and SmartNICs. 6 | 7 | ## Contents 8 | 9 | This repository contains synthesizable SystemVerilog code for BBQ, as well as a number of existing hardware priority queue designs we compare against: [PIFO](https://web.mit.edu/pifo/pifo-sigcomm.pdf) (SIGCOMM '16), [PIEO](https://web.ics.purdue.edu/~vshriva/papers/pieo_2019.pdf) (SIGCOMM '19), and [BMW-Tree](https://dl.acm.org/doi/pdf/10.1145/3603269.3604862) (SIGCOMM '23). In addition, we provide scripts to synthesize these designs to hardware (targeting FPGAs and ASICs), and a simulation testbench for BBQ (consisting of a number of unit- and regression-tests). 10 | 11 | ## Getting Started 12 | 13 | This code was tested on Ubuntu 22.04 LTS. The workflow and minimum system requirements depend on how you intend to use this research artifact. 14 | 15 | 0. **Browsing Code**: You can find the source code for BBQ as well as the baseline designs in the `hardware` subdirectory. For instance, PIFO's priority queue implementation can be found in `hardware/pifo/src/pifo.sv`. In the case of BBQ, the source code is auto-generated by a Python wrapper that stitches together modular blocks of hand-written SystemVerilog code; to run this script, you will need **Python 3.10** or newer. The instructions for this can be found in the `hardware/bbq` subdirectory. 16 | 17 | 1. **FPGA Simulation**: If you simply want to run and test these designs in simulation, you will need **Modelsim (for Intel FPGAs)**. The BBQ source code is known to work with [Modelsim Standard Edition v20.1.1](https://www.intel.com/content/www/us/en/software-kit/750666/modelsim-intel-fpgas-standard-edition-software-version-20-1-1.html). We recommend using the *Starter Edition* (included with all of Intel's Modelsim distributions), which is free to use and works seamlessly for designs with fewer than 10K LoC. As a starting point for simulation, we provide a testbench for bbq in the `hardware/bbq/tb` subdirectory. 18 | 19 | 2. **FPGA Synthesis**: If you want to synthesize these designs to an FPGA target, you will need **Intel Quartus Prime**. All designs contained herein are known to work with [Quartus Prime Pro Edition v19.3](https://www.intel.com/content/www/us/en/software-kit/750666/modelsim-intel-fpgas-standard-edition-software-version-20-1-1.html). **Note**: Most of the included designs use a small set of Intel IPs (BRAM and SCFIFO); if you intend to use a different synthesis toolchain (e.g., Xilinx Vivado), you will need to modify the designs to use the equivalent IPs from the corresponding vendor. To get started with FPGA synthesis, refer to the README in the `hardware` subdirectory. 20 | 21 | 3. **ASIC Synthesis**: The PIFO and BBQ designs can also be synthesized to ASIC targets using the **Synopsys Design Compiler**. The ASIC synthesis flow is known to work with [Synopsys S-2021.06 (Version 5.3)](https://solvnet.synopsys.com/Install/installation_guide.jsp?id=206&releasedate=2021-06-07) using a 7 nm Standard Cell Library based on the [ASAP7 PDK](https://github.com/The-OpenROAD-Project/asap7_pdk_r1p7/tree/main). To get started with ASIC synthesis, refer to the README in the `evaluation` subdirectory (in progress, please check back shortly). 22 | 23 |
24 | -------------------------------------------------------------------------------- /hardware/README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ## FPGA Synthesis 4 | 5 | This directory contains the required SystemVerilog code, Quartus project files, and bash scripts required to synthesize the encompassed designs (`bbq`, `bmw`, `pieo`, and `pifo`) to an Intel Stratix 10MX FPGA. If you wish to target a different FPGA device or family, you will need to modify the ".qsf" file and IP-generation tcl script in each of the subdirectories (to find all offending files, run `grep -Rn "DEVICE" --include=*.{qsf,template}` in this directory). We provide scripts for three different FPGA synthesis flows. 6 | 7 | ### (A) Single-configuration synthesis with a predefined target frequency 8 | 9 | Each design has a set of parameters that are configurable at compile-time: for instance, we can synthesize PIFO with a specific number of queue elements (e.g., 1024) and priority bits (e.g., 9). This flow allows us to synthesize _one_ such configuration with a _predefined_ target frequency (or "fmax"). To use this flow, do the following steps: 10 | 11 | 1. First, we need to instantiate a PLL (clock circuit) IP operating at a fixed frequency to drive the design. For the design you want to synthesize (say, `DESIGN`, which can be either `bbq`, `bmw`, `pieo`, or `pifo`), choose the clock frequency in MHz you wish to target (say, `TARGET_FMAX_MHz`), then run the following command from this directory: ```${DESIGN}/setup.sh ${TARGET_FMAX_MHz}```. For instance, to setup PIFO to operate with a 200 MHz clock, run: ```pifo/setup.sh 200``` 12 | 13 | 2. Finally, run the synthesis script as follows: ```${CONFIG_OPTION_1}=${CONFIG_VALUE_1} ... ${DESIGN}/scripts/synthesize.sh [SEED]```. You will need to set all the required configuration options in order to perform synthesis. The (optional) SEED value is used to seed the synthesis tool's random-number generator. To find the relevant options for a given design, refer to the docstring of the corresponding synthesis script. For instance, to synthesize PIFO with 2^10 elements and 9-bit priorities, run: ```ELEMENT_BITS=10 PRIORITY_BITS=9 pifo/scripts/synthesize.sh```. 14 | 15 | Once synthesis completes, you can find the corresponding compiler reports (placement, timing, etc.) and bitstream (if successfully generated) in the ```${DESIGN}/quartus/output_files``` subdirectory. 16 | 17 | ### (B) Single-configuration synthesis with fmax bisection search 18 | 19 | Often, the maximum achievable clock frequency (fmax) is not known ahead of time. This flow allows us to automatically find the close-to-best possible fmax (and the corresponding seed value) for a single design configuration using a bisection search over a range of clock frequencies. To use this flow for a given design (say, `DESIGN`), run the following command from this directory: ```${CONFIG_OPTION_1}=${CONFIG_VALUE_1} ... [MIN_FREQ=AAA] [MAX_FREQ=BBB] [PRECISION=CCC] ${DESIGN}/scripts/bisect_fmax.sh ${SEED_1} ${SEED_2} ...```. The configuration options have the same semantics as described in Step 2 of [(A)](#a-single-configuration-synthesis-with-a-predefined-target-frequency). Optionally, you can set the limits (in MHz) of the frequency range (`MIN_FREQ`, `MAX_FREQ`), and the precision (also in MHz) of the bisection search (`PRECISION`). You must also specify (an arbitrary number of) SEEDs to use. For instance, to find the best fmax for a PIFO with 2^10 elements and 9-bit priorities using 5 seeds, run: ```ELEMENT_BITS=10 PRIORITY_BITS=9 MIN_FREQ=50 MAX_FREQ=250 pifo/scripts/bisect_fmax.sh 1 2 3 4 5``` 20 | 21 | The script iteratively synthesizes the design (using the specified set of seeds) at various fmax targets informed by bisection search. The process completes once either: (a) the lower- and upper-bounds of the search are within `PRECISION` MHz of each other, or (b) the script fails to synthesize a design that meets the timing requirements corresponding to `MIN_FREQ`. A summary of the results (best fmax, and the corresponding seed) are written to `${DESIGN}/quartus/bisect_fmax/fmax.txt`. 22 | 23 | ### (C) Multi-configuration sweep with fmax bisection search 24 | 25 | This flow extends [(B)](#b-single-configuration-synthesis-with-fmax-bisection-search) to automatically find the best fmax for _multiple_ design configurations (queue size, number of priority bits, and so on). To use this flow for a given design (say, `DESIGN`), first modify the `for` loops in `${DESIGN}/scripts/sweep_bisect_fmax.sh` to correspond to the design configurations you would like to sweep. Finally, run the following command from this directory: ```[MIN_FREQ=AAA] [MAX_FREQ=BBB] [PRECISION=CCC] [NUM_PROCS=DDD] ./sweep_bisect_fmax.sh ${SEED_1} ${SEED_2} ...```. `MIN_FREQ`, `MAX_FREQ`, and `PRECISION` have the same semantics as described earlier. `NUM_PROCS` is an optional parameter that parallelizes the design-space exploration using the specified number of cores. 26 | 27 | The results for each configuration are written to the newly-created `${DESIGN}/quartus/sweep_bisect_fmax` directory. Note that you will need [GNU parallel](https://www.gnu.org/software/parallel/) to use this flow. 28 | 29 |
30 | -------------------------------------------------------------------------------- /hardware/bbq/README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ## FPGA Simulation 4 | 5 | ### Generating BBQ's Source Code 6 | 7 | Unlike the other designs, BBQ's implementation file (`bbq.sv`) is not checked in to its `src` directory. Instead, we use a Python wrapper to generate BBQ's source code by stitching together modular blocks of hand-written SystemVerilog code. The reason is that the semantics of BBQ's pipeline depend heavily on the _number of levels_ in its bitmap tree, and encoding this configurability directly in SystemVerilog would yield highly complex and unwieldy source code. Instead, we choose to offload the complexity of handling this parameter to Python, resulting in simpler, cleaner, and more manageable SystemVerilog code. 8 | 9 | Thus, as a first step in the simulation flow, we need to generate BBQ's source code for a chosen number of bitmap levels (say, `NUM_BITMAP_LEVELS`). To do this, run the following snippet from this directory: 10 | ``` 11 | python3 generator/bbq.py ${NUM_BITMAP_LEVELS} > src/bbq.sv 12 | ``` 13 | 14 | This generates source code for a `bbq` SystemVerilog module with the specified bitmap tree depth. At this point, the tree depth is fixed, and should not be changed! However, you may still tune the _width_ of each bitmap, the queue size, and the width of each queue entry by initializing the appropriate parameters while instantiating the module (`HEAP_BITMAP_WIDTH`, `HEAP_MAX_NUM_ENTRIES`, and `HEAP_ENTRY_DWIDTH`, respectively). For example usage, please refer to `src/top.sv`. 15 | 16 | ### Simulating BBQ 17 | 18 | As a starting point for simulation, this repository contains a testbench with a regression test suite for BBQ and the Find-First Set (FFS) module underlying BBQ. Once you have generated the BBQ source code (as described above), you can exercise the simulation testbench by following the README in the [tb](tb) subdirectory. 19 | 20 |
21 | -------------------------------------------------------------------------------- /hardware/bbq/generator/bbq_level.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | from __future__ import annotations 3 | 4 | import typing 5 | from abc import ABC, abstractmethod 6 | 7 | from codegen import CodeGen 8 | 9 | # Hack for type hinting with circular imports 10 | if typing.TYPE_CHECKING: from bbq import BBQ 11 | 12 | 13 | class BBQLevel(ABC): 14 | """Represents a generic BBQ level.""" 15 | def __init__(self, bbq: BBQ, start_cycle: int) -> None: 16 | self.bbq = bbq # Pointer to BBQ instance 17 | self.start_cycle = start_cycle # Starting pipeline cycle 18 | 19 | # Housekeeping 20 | self.prev_level: BBQLevel = None # Pointer to the prev level 21 | self.next_level: BBQLevel = None # Pointer to the next level 22 | 23 | 24 | @property 25 | def num_bitmap_levels(self) -> int: 26 | """Returns the bitmap level count.""" 27 | return self.bbq.num_bitmap_levels 28 | 29 | 30 | @property 31 | def end_cycle(self) -> int: 32 | """Ending pipeline cycle.""" 33 | return self.start_cycle + self.latency() 34 | 35 | 36 | @abstractmethod 37 | def name(self) -> str: 38 | """Canonical level name.""" 39 | raise NotImplementedError() 40 | 41 | 42 | @abstractmethod 43 | def latency(self) -> int: 44 | """Latency in cycles.""" 45 | raise NotImplementedError() 46 | 47 | 48 | @abstractmethod 49 | def emit_stage_defs(self, cg: CodeGen) -> None: 50 | """Emit per-stage definitions.""" 51 | raise NotImplementedError() 52 | 53 | 54 | @abstractmethod 55 | def emit_state_dependent_combinational_logic(self, cg: CodeGen) -> None: 56 | """Emit state-dependent combinational logic.""" 57 | raise NotImplementedError() 58 | 59 | 60 | @abstractmethod 61 | def emit_combinational_default_assigns(self, cg: CodeGen) -> None: 62 | """Emit state-agnostic default assigns.""" 63 | raise NotImplementedError() 64 | 65 | 66 | @abstractmethod 67 | def emit_state_agnostic_combinational_logic(self, cg: CodeGen) -> None: 68 | """Emit state-agnostic combinational logic.""" 69 | raise NotImplementedError() 70 | 71 | 72 | @abstractmethod 73 | def emit_sequential_pipeline_logic(self, cg: CodeGen) -> None: 74 | """Emit sequential logic for this level.""" 75 | raise NotImplementedError() 76 | -------------------------------------------------------------------------------- /hardware/bbq/generator/bbq_level_ingress.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | from __future__ import annotations 3 | 4 | import typing 5 | 6 | from bbq_level import BBQLevel 7 | from codegen import CodeGen 8 | 9 | # Hack for type hinting with circular imports 10 | if typing.TYPE_CHECKING: from bbq import BBQ 11 | 12 | 13 | class BBQLevelIngress(BBQLevel): 14 | """Represents the ingress level in BBQ.""" 15 | def __init__(self, bbq: BBQ, start_cycle: int) -> None: 16 | super().__init__(bbq, start_cycle) 17 | 18 | 19 | def name(self) -> str: 20 | """Canonical level name.""" 21 | return "ingress" 22 | 23 | 24 | def latency(self) -> int: 25 | """Latency in cycles.""" 26 | return 0 27 | 28 | 29 | def emit_stage_defs(self, cg: CodeGen) -> None: 30 | """Emit per-stage definitions.""" 31 | cycle = self.start_cycle 32 | 33 | cg.comment("Stage {} metadata".format(cycle)) 34 | cg.align_defs([ 35 | ("logic", "valid_s{};".format(cycle)), 36 | ("counter_t", "old_occupancy_s{};".format(cycle)), 37 | ("counter_t", "new_occupancy_s{};".format(cycle)), 38 | ("counter_t", "reg_old_occupancy_s{};".format(cycle)), 39 | ("counter_t", "reg_new_occupancy_s{};".format(cycle)), 40 | ]) 41 | cg.emit() 42 | cycle += 1 43 | 44 | 45 | def emit_state_dependent_combinational_logic(self, cg: CodeGen) -> None: 46 | """Emit state-dependent combinational logic.""" 47 | pass 48 | 49 | 50 | def emit_combinational_default_assigns(self, cg: CodeGen) -> None: 51 | """Emit default assignments.""" 52 | cycle = self.start_cycle 53 | cg.emit("valid_s{} = 0;".format(cycle)) 54 | 55 | if self.bbq.is_logically_partitioned: 56 | cg.emit("old_occupancy_s{} = occupancy[reg_bbq_id_s[{}]];" 57 | .format(cycle, cycle - 1)) 58 | else: 59 | cg.emit("old_occupancy_s{} = occupancy;".format(cycle)) 60 | 61 | cycle += 1 62 | 63 | 64 | def emit_state_agnostic_combinational_logic(self, cg: CodeGen) -> None: 65 | """Emit state-agnostic combinational logic.""" 66 | seq_cycle = self.start_cycle - 1 67 | 68 | old_occupancy = "old_occupancy_s{}".format(seq_cycle + 1) 69 | cg.comment([ 70 | "Stage {}: Determine operation validity. Disables the pipeline".format(seq_cycle + 1), 71 | "stage if the BBQ is empty (deques), or FL is empty (enques).", 72 | ], True) 73 | cg.start_conditional("if", "reg_valid_s[{}]".format(seq_cycle)) 74 | cg.align_assignment("valid_s{}".format(seq_cycle + 1), [ 75 | "(", 76 | "(reg_is_enque_s[{}] && !fl_empty) ||".format(seq_cycle), 77 | ("(!reg_is_enque_s[{}] && ({}[0] |" 78 | .format(seq_cycle, old_occupancy)), 79 | 80 | (" {}[WATERLEVEL_IDX])));" 81 | .format(old_occupancy)) 82 | ], "=", True) 83 | cg.end_conditional("if") 84 | 85 | cg.comment("Update the occupancy counter") 86 | cg.align_ternary( 87 | "new_occupancy_s{}[WATERLEVEL_IDX-1:0]".format(seq_cycle + 1), 88 | ["reg_is_enque_s[{}]".format(seq_cycle)], 89 | ["({}[WATERLEVEL_IDX-1:0] + 1)".format(old_occupancy), 90 | "({}[WATERLEVEL_IDX-1:0] - 1)".format(old_occupancy)], 91 | "=", True, False) 92 | 93 | cg.emit() 94 | cg.align_assignment( 95 | "new_occupancy_s{}[WATERLEVEL_IDX]".format(seq_cycle + 1), 96 | ["(reg_is_enque_s[{}] ?".format(seq_cycle), 97 | "({0}[WATERLEVEL_IDX] | {0}[0]) :".format(old_occupancy), 98 | "((|{0}[WATERLEVEL_IDX-1:2]) | (&{0}[1:0])));".format(old_occupancy), 99 | ], 100 | "=", True) 101 | 102 | cg.emit() 103 | cg.comment("If enqueing, also deque the free list") 104 | cg.start_conditional("if", ("valid_s{} && reg_is_enque_s[{}]" 105 | .format(seq_cycle + 1, seq_cycle))) 106 | 107 | cg.emit("fl_rdreq = 1;") 108 | cg.end_conditional("if") 109 | cg.emit() 110 | 111 | 112 | def emit_sequential_pipeline_logic(self, cg: CodeGen) -> None: 113 | """Emit sequential logic for this level.""" 114 | cycle = self.end_cycle 115 | cg.comment([ 116 | "Stage {}: Determine operation validity. Disables the pipeline".format(cycle), 117 | "stage if the BBQ is empty (deques) or FL is empty (enqueues).", 118 | ], True) 119 | 120 | value_override = {"reg_valid_s": "valid_s{}".format(cycle)} 121 | self.bbq.emit_sequential_primary_signals(cycle, value_override) 122 | 123 | cg.emit([ 124 | "reg_old_occupancy_s{0} <= old_occupancy_s{0};".format(cycle), 125 | "reg_new_occupancy_s{0} <= new_occupancy_s{0};".format(cycle), 126 | ]) 127 | cg.emit() 128 | 129 | cg.start_conditional("if", "valid_s{}".format(cycle)) 130 | cg.emit("occupancy{} <= new_occupancy_s{};" 131 | .format("[reg_bbq_id_s[{}]]".format(cycle - 1) if 132 | self.bbq.is_logically_partitioned else "", cycle)) 133 | 134 | cg.end_conditional("if") 135 | cg.emit() 136 | 137 | cg.start_ifdef("DEBUG") 138 | id_str_prefix = ("logical ID: %0d, " 139 | if self.bbq.is_logically_partitioned else "") 140 | 141 | id_val_prefix = ("reg_bbq_id_s[{}], ".format(cycle - 1) 142 | if self.bbq.is_logically_partitioned else "") 143 | 144 | cg.start_conditional("if", ("reg_valid_s[{}] && !valid_s{}" 145 | .format(cycle - 1, cycle))) 146 | cg.emit("$display(") 147 | cg.emit([ 148 | ("\"[BBQ] At S{0} ({1}op: %s), rejected at Stage {2}->{0}\"," 149 | .format(cycle, id_str_prefix, cycle - 1)), 150 | 151 | "{}reg_op_type_s[{}].name);".format(id_val_prefix, cycle - 1), 152 | ], True, 4) 153 | cg.end_conditional("if") 154 | 155 | cg.start_conditional("if", "valid_s{}".format(cycle)) 156 | cg.emit("$display(") 157 | cg.emit([ 158 | "\"[BBQ] At S{} ({}op: %s), updating occupancy\",".format(cycle, id_str_prefix), 159 | "{}reg_op_type_s[{}].name, \" from %0d to %0d\",".format(id_val_prefix, cycle - 1), 160 | "old_occupancy_s{}[WATERLEVEL_IDX-1:0],".format(cycle), 161 | "new_occupancy_s{}[WATERLEVEL_IDX-1:0]);".format(cycle), 162 | ], True, 4) 163 | cg.end_conditional("if") 164 | cg.end_ifdef() 165 | cg.emit() 166 | -------------------------------------------------------------------------------- /hardware/bbq/generator/bbq_level_steering.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | from __future__ import annotations 3 | 4 | import typing 5 | 6 | from bbq_level import BBQLevel 7 | from bbq_level_pb import BBQLevelPB 8 | from codegen import CodeGen 9 | 10 | # Hack for type hinting with circular imports 11 | if typing.TYPE_CHECKING: from bbq import BBQ 12 | 13 | 14 | class BBQLevelSteering(BBQLevel): 15 | """Represents the steering level in BBQ.""" 16 | def __init__(self, bbq: BBQ, start_cycle: int, 17 | num_lps: int, level_id: int) -> None: 18 | 19 | super().__init__(bbq, start_cycle) 20 | 21 | self.num_lps = num_lps # Number of logical partitions 22 | self.level_id = level_id # ID of the maximum level replaced 23 | 24 | 25 | @property 26 | def is_leaf(self) -> bool: 27 | """Returns whether this is a leaf level.""" 28 | return isinstance(self.next_level, BBQLevelPB) 29 | 30 | 31 | def name(self) -> str: 32 | """Canonical level name.""" 33 | return "steering" 34 | 35 | 36 | def latency(self) -> int: 37 | """Latency in cycles.""" 38 | return 0 39 | 40 | 41 | def emit_stage_defs(self, cg: CodeGen) -> None: 42 | """Emit per-stage definitions.""" 43 | cycle = self.start_cycle 44 | 45 | cg.comment("Stage {} metadata".format(cycle)) 46 | if self.is_leaf: 47 | cg.align_defs([ 48 | ("heap_priority_t", "priority_s{};".format(cycle)), 49 | ]) 50 | for offset in range(1, 5): 51 | cg.align_defs([ 52 | ("logic", "{}_addr_conflict_s{}_s{};".format( 53 | self.next_level.name(), (cycle + offset), cycle)) 54 | ]) 55 | if self.is_leaf: 56 | cg.align_defs([ 57 | ("counter_t", "reg_{}_counter_s{};".format(self.name(), cycle)), 58 | ]) 59 | for offset in range(1, 5): 60 | cg.align_defs([ 61 | ("logic", "reg_{}_addr_conflict_s{}_s{};".format( 62 | self.next_level.name(), (cycle + offset), cycle)) 63 | ]) 64 | if self.is_leaf: 65 | cg.align_defs([ 66 | ("counter_t", "reg_old_{}_counter_s{};".format(self.name(), cycle)), 67 | ("logic", "reg_{}_counter_non_zero_s{};".format(self.name(), cycle)), 68 | ]) 69 | cg.emit() 70 | cycle += 1 71 | 72 | 73 | def emit_state_dependent_combinational_logic(self, cg: CodeGen) -> None: 74 | """Emit state-dependent combinational logic.""" 75 | pass 76 | 77 | 78 | def emit_combinational_default_assigns(self, cg: CodeGen) -> None: 79 | """Emit state-agnostic default assigns.""" 80 | cycle = self.start_cycle 81 | 82 | # If this (steering) level is also the leaf level, then 83 | # the priority simply corresponds to the logical BBQ ID. 84 | if self.is_leaf: 85 | cg.emit("priority_s{} = reg_priority_s[{}];" 86 | .format(cycle, cycle - 1)) 87 | 88 | cycle += 1 89 | 90 | 91 | def emit_state_agnostic_combinational_logic(self, cg: CodeGen) -> None: 92 | """Emit state-agnostic combinational logic.""" 93 | seq_cycle = self.end_cycle - 1 94 | 95 | cg.comment([ 96 | ("Stage {}: Steer op to the appropriate logical BBQ." 97 | .format(seq_cycle + 1)) 98 | ], True) 99 | 100 | if self.is_leaf: 101 | cg.comment("Read PB contents") 102 | cg.emit("pb_rden = reg_valid_s[{}];".format(seq_cycle)) 103 | cg.emit() 104 | 105 | elif self.next_level.sram_bitmap: 106 | cg.comment("Read L{} bitmap".format(self.level_id + 1)) 107 | cg.emit("bm_{}_rden = reg_valid_s[{}];".format( 108 | self.next_level.name(), seq_cycle)) 109 | 110 | cg.emit("bm_{}_rdaddress = reg_bbq_id_s[{}];".format( 111 | self.next_level.name(), seq_cycle)) 112 | 113 | cg.emit() 114 | 115 | cg.comment("Compute conflicts") 116 | for offset in range(1, 5): 117 | cg.align_assignment( 118 | ("{}_addr_conflict_s{}_s{}" 119 | .format(self.next_level.name(), 120 | seq_cycle + 1 + offset, 121 | seq_cycle + 1)), 122 | ["(", 123 | ("reg_valid_s[{}] && reg_valid_s[{}] &&" 124 | .format(seq_cycle, seq_cycle + offset)), 125 | 126 | ("(reg_bbq_id_s[{}] == reg_bbq_id_s[{}]));" 127 | .format(seq_cycle, seq_cycle + offset)) 128 | ], 129 | "=", True) 130 | cg.emit() 131 | 132 | if self.is_leaf: 133 | cg.comment("Disable conflicting reads during writes") 134 | cg.start_conditional("if", 135 | ("pb_addr_conflict_s{}_s{}".format( 136 | self.next_level.end_cycle, seq_cycle + 1)) 137 | ) 138 | cg.emit([ 139 | "pb_rdwr_conflict = 1;", 140 | "pb_rden = 0;", 141 | ]) 142 | cg.end_conditional("if") 143 | 144 | seq_cycle += 1 145 | 146 | 147 | def emit_sequential_pipeline_logic(self, cg: CodeGen) -> None: 148 | """Emit sequential logic for this level.""" 149 | cycle = self.start_cycle 150 | 151 | cg.comment([ 152 | "Stage {}: Steer op to the appropriate logical BBQ.".format(cycle) 153 | ], True) 154 | 155 | self.bbq.emit_sequential_primary_signals(cycle) 156 | if not self.is_leaf: 157 | cg.emit("reg_{}_addr_s[{}] <= reg_bbq_id_s[{}];" 158 | .format(self.next_level.name(), cycle, cycle - 1)) 159 | 160 | cg.emit() 161 | 162 | for offset in range(1, 5): 163 | cg.emit( 164 | "reg_{0}_addr_conflict_s{1}_s{2} <= " 165 | "{0}_addr_conflict_s{1}_s{2};".format( 166 | self.next_level.name(), cycle + offset, cycle) 167 | ) 168 | cg.emit() 169 | 170 | if self.is_leaf: 171 | cg.comment([ 172 | "With a steering level that replaces the leaf-level", 173 | "bitmaps, we can effectively substitute StOC values", 174 | "(used in Stage {}) with logical occupancy counters.".format(cycle + 1) 175 | ]) 176 | cg.emit([ 177 | ("reg_{}_counter_s{} <= reg_new_occupancy_s{};" 178 | .format(self.name(), cycle, cycle - 1)), 179 | 180 | ("reg_old_{}_counter_s{} <= reg_old_occupancy_s{};" 181 | .format(self.name(), cycle, cycle - 1)), 182 | ]) 183 | cg.align_assignment( 184 | "reg_{}_counter_non_zero_s{}".format(self.name(), cycle), 185 | ["(reg_is_enque_s[{}] |".format(cycle - 1), 186 | "reg_new_occupancy_s{}[WATERLEVEL_IDX]);".format(cycle - 1)], 187 | "<=", False) 188 | cg.emit() 189 | 190 | elif (not self.is_leaf) and (not self.next_level.sram_bitmap): 191 | cg.comment("Forward L{} bitmap updates".format(self.level_id + 1)) 192 | cg.align_ternary( 193 | "reg_{}_bitmap_s[{}]".format( 194 | self.next_level.name(), cycle), 195 | 196 | ["{}_addr_conflict_s{}_s{}" 197 | .format(self.next_level.name(), 198 | self.next_level.end_cycle, cycle)], 199 | 200 | ["{}_bitmap_s{}".format(self.next_level.name(), 201 | self.next_level.end_cycle), 202 | 203 | "{}_bitmaps[reg_bbq_id_s[{}]]".format( 204 | self.next_level.name(), cycle - 1)], 205 | "<=", True, True) 206 | cg.emit() 207 | 208 | cg.start_ifdef("DEBUG") 209 | cg.start_conditional("if", "reg_valid_s[{}]".format(cycle - 1)) 210 | cg.emit("$display(") 211 | cg.emit([ 212 | "\"[BBQ] At S{} (logical ID: %0d, op: %s),\",".format(cycle), 213 | "reg_bbq_id_s[{0}], reg_op_type_s[{0}].name,".format(cycle - 1), 214 | 215 | ("\" steering op to the corresponding {}\");" 216 | .format("PB" if self.is_leaf else 217 | "L{} bitmap".format(self.level_id + 1))), 218 | ], True, 4) 219 | cg.end_conditional("if") 220 | cg.end_ifdef() 221 | 222 | cycle += 1 223 | -------------------------------------------------------------------------------- /hardware/bbq/generator/codegen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import math 3 | from collections import deque 4 | from typing import List, Tuple 5 | 6 | class CodeGen: 7 | """Backend for generating SystemVerilog code.""" 8 | def __init__(self) -> None: 9 | self.out = "" # Emitted code 10 | self.level = 0 # Current indent level 11 | self.spacing = 4 # Spacing per indent level 12 | self.stack = deque() # Stack for tracking blocks 13 | 14 | 15 | @property 16 | def indent(self) -> int: 17 | """Fetch current indent spacing.""" 18 | return self.level * self.spacing 19 | 20 | 21 | def tab(self, num: int=1) -> str: 22 | """Creates multi-tab indents.""" 23 | return " " * self.spacing * num 24 | 25 | def inc_level(self) -> None: 26 | """Add indentation.""" 27 | self.level += 1 28 | 29 | 30 | def dec_level(self) -> None: 31 | """Remove indentation.""" 32 | assert self.level >= 0 33 | self.level -= 1 34 | 35 | 36 | def _format_str(self, x: str, offset: int) -> str: 37 | """Formats a string with the current indent.""" 38 | assert isinstance(x, str) # Sanity check 39 | if not x: return x # Leave empty strings 40 | return (" " * (self.indent + offset)) + x 41 | 42 | 43 | def emit(self, x: str | List[str]="", indent_first: bool=True, 44 | offset: int=0, trailing_newline: bool=True) -> None: 45 | """Emit str (or list thereof) with the current indent.""" 46 | if isinstance(x, str): 47 | if x: # Not an empty string 48 | self.out += (self._format_str(x, offset) 49 | if indent_first else x) 50 | 51 | elif isinstance(x, list): 52 | first = True 53 | for v in x: 54 | if v is None: continue 55 | self.out += ((self._format_str(v, offset) if indent_first else v) 56 | if first else "\n{}".format(self._format_str(v, offset))) 57 | 58 | first = False # First valid value 59 | 60 | # Sanity check 61 | else: assert False 62 | if trailing_newline: self.out += "\n" 63 | 64 | 65 | def comment(self, x: str | List[str], is_block: bool=False) -> None: 66 | """Emits a block or inline comment.""" 67 | if is_block: self.emit("/**") 68 | 69 | prefix = " * " if is_block else "// " 70 | if isinstance(x, str): 71 | self.emit(prefix + x) 72 | else: 73 | assert isinstance(x, list) 74 | for v in x: self.emit(prefix + v) 75 | 76 | if is_block: self.emit(" */") 77 | 78 | 79 | def enum(self, name: str, values: List[str]) -> None: 80 | """Emit enum typedef with appropriate width.""" 81 | 82 | # Sanity checks 83 | assert self.level == 0 84 | assert len(values) >= 2 85 | 86 | # Compute type width 87 | log_num_values = math.ceil(math.log2(len(values))) 88 | logictype = ("logic" if (log_num_values == 1) else 89 | "logic [{}:0]".format(log_num_values - 1)) 90 | 91 | self.emit("typedef enum {} {{".format(logictype)) 92 | self.inc_level() 93 | 94 | for idx in range(len(values)): 95 | self.emit(values[idx], True, 0, False) 96 | if idx != (len(values) - 1): self.out += "," 97 | self.emit() 98 | 99 | self.dec_level() 100 | self.emit("}} {};".format(name)) 101 | 102 | 103 | def align_assignment(self, lhs: str, rhs: str | List[str], 104 | assign: str, tab_indent: bool=False) -> None: 105 | """Emit code of type: lhs = (rhs... (multi-line)).""" 106 | assign_str = "{} {} ".format(lhs, assign) 107 | self.emit(assign_str, True, 0, False) 108 | 109 | # Account for additional brace/bracket 110 | offset = (self.spacing if tab_indent 111 | else (len(assign_str) + 1)) 112 | 113 | self.emit(rhs, False, offset, True) 114 | 115 | 116 | def align_defs(self, defs: List[Tuple], align : int=40) -> None: 117 | """Emit tab-aligned definitions.""" 118 | for (lhs, rhs) in defs: 119 | if rhs is None: continue 120 | padding = align - len(lhs) 121 | assert padding > 0 # Sanity check 122 | self.emit(lhs + (" " * padding) + rhs) 123 | 124 | 125 | def _align_ternary_value(self, value: str | List[str], 126 | value_pad: int) -> List[str]: 127 | """Helper method to format multi-line ternary values.""" 128 | if isinstance(value, str): return [value] 129 | else: 130 | assert isinstance(value, list) 131 | if len(value) == 1: return value 132 | 133 | output_list = [] 134 | for i, v in enumerate(value): 135 | output_list.append("({}".format(v) if (i == 0) else 136 | "{}{}".format(" " * (value_pad + 1), v)) 137 | output_list[-1] += ")" 138 | return output_list 139 | 140 | 141 | def align_ternary( 142 | self, lhs: str, conditionals: List[str], 143 | values: List[str | List[str]], assign: str, 144 | break_first: bool=True, same_line: bool=False) -> None: 145 | """Formats a ternary chain (a ? b : c ? ... : z) operation.""" 146 | if same_line: assert len(conditionals) == 1 147 | if len(conditionals) > 1: assert break_first 148 | assert len(values) == (len(conditionals) + 1) 149 | 150 | output_list = [] 151 | # Single ternary operator 152 | if len(conditionals) == 1: 153 | output = "{} {} (".format(lhs, assign) 154 | pad_same_line = self.spacing if break_first else len(output) 155 | 156 | if break_first: 157 | output_list.append(output) 158 | output = "{}{} ?".format(self.tab(), conditionals[0]) 159 | 160 | else: output += "{} ?".format(conditionals[0]) 161 | pad_staggered = len(output) + 1 162 | 163 | # Both values on the same line 164 | if same_line: 165 | output_list.append(output) 166 | assert isinstance(values[0], str) 167 | assert isinstance(values[1], str) 168 | output = "{}{} : {});".format(" " * pad_same_line, 169 | values[0], values[1]) 170 | output_list.append(output) 171 | 172 | # Values on different lines 173 | else: 174 | value = self._align_ternary_value( 175 | values[0], pad_staggered) 176 | 177 | value[0] = output + " " + value[0] 178 | value[-1] = value[-1] + " :" 179 | output_list.extend(value) 180 | 181 | value = self._align_ternary_value( 182 | values[1], pad_staggered) 183 | 184 | value[0] = (" " * pad_staggered) + value[0] 185 | value[-1] = value[-1] + ");" 186 | output_list.extend(value) 187 | 188 | # Operator chain 189 | else: 190 | output_list.append("{} {} (".format(lhs, assign)) 191 | pad_max = self.spacing + max([len(x) for x in conditionals]) 192 | pad_rhs = pad_max + len(" ? ") 193 | 194 | for i, conditional in enumerate(conditionals): 195 | lhs_pad = pad_max - len(conditional) 196 | output = "{}{} ? ".format(" " * lhs_pad, conditional) 197 | 198 | value = self._align_ternary_value(values[i], pad_rhs) 199 | value[0] = output + value[0] 200 | value[-1] = value[-1] + " :" 201 | output_list.extend(value) 202 | 203 | # Last value 204 | value = self._align_ternary_value(values[-1], pad_rhs) 205 | value[0] = (" " * pad_rhs) + value[0] 206 | value[-1] = value[-1] + ");" 207 | output_list.extend(value) 208 | 209 | self.emit(output_list) 210 | 211 | 212 | def start_block(self, name: str) -> None: 213 | """Start a generic begin/end block.""" 214 | self.emit("{} begin".format(name)) 215 | self.stack.append(name) 216 | self.inc_level() 217 | 218 | 219 | def end_block(self, name: str) -> None: 220 | """End generic begin/end block.""" 221 | self.dec_level() 222 | self.emit("end") 223 | assert self.stack.pop() == name 224 | 225 | 226 | def start_conditional(self, type: str, condition: 227 | str | List[str]) -> None: 228 | """Start a conditional (if, else) block.""" 229 | assert type in ["if", "else", "else if"] 230 | 231 | if type == "else": 232 | self.emit("else begin") 233 | else: 234 | self.emit("{} (".format(type), True, 0, False) 235 | self.emit(condition, False, len(type) + 2, False) 236 | self.emit(") begin", False, 0, True) 237 | 238 | self.stack.append(type) 239 | self.inc_level() 240 | 241 | 242 | def end_conditional(self, type: str) -> None: 243 | """Ends the current conditional block.""" 244 | self.dec_level() 245 | self.emit("end") 246 | assert self.stack.pop() == type 247 | 248 | 249 | def start_for(self, var: str, condition: str) -> None: 250 | """Start a for block.""" 251 | self.emit("for ({0} = 0; {1}; {0} = {0} + 1) begin" 252 | .format(var, condition)) 253 | 254 | self.stack.append("for") 255 | self.inc_level() 256 | 257 | 258 | def end_for(self) -> None: 259 | """Ends for block.""" 260 | self.dec_level() 261 | self.emit("end") 262 | assert self.stack.pop() == "for" 263 | 264 | 265 | def start_switch(self, name: str) -> None: 266 | """Start a new switch/case block.""" 267 | self.emit("case ({})".format(name)) 268 | self.stack.append("switch") 269 | 270 | 271 | def end_switch(self) -> None: 272 | """End case block.""" 273 | self.emit("endcase") 274 | assert self.stack.pop() == "switch" 275 | 276 | 277 | def start_case(self, casename: str) -> None: 278 | """Start a new switch/case statement.""" 279 | self.emit("{}: begin".format(casename)) 280 | self.stack.append("case") 281 | self.inc_level() 282 | 283 | 284 | def end_case(self) -> None: 285 | """End current case.""" 286 | self.dec_level() 287 | self.emit("end") 288 | assert self.stack.pop() == "case" 289 | 290 | def start_ifdef(self, condition: str) -> None: 291 | """Start a new ifdef block.""" 292 | self.emit("`ifdef {}".format(condition)) 293 | self.stack.append("ifdef") 294 | 295 | 296 | def end_ifdef(self) -> None: 297 | """End current ifdef block.""" 298 | self.emit("`endif") 299 | assert self.stack.pop() == "ifdef" 300 | -------------------------------------------------------------------------------- /hardware/bbq/ip/.gitignore: -------------------------------------------------------------------------------- 1 | .qsys_edit 2 | *.ip 3 | 4 | my_pll 5 | 6 | # Will be generated from template. 7 | my_pll.tcl 8 | -------------------------------------------------------------------------------- /hardware/bbq/ip/my_pll.tcl.template: -------------------------------------------------------------------------------- 1 | package require -exact qsys 18.0 2 | 3 | # create the system "my_pll" 4 | proc do_create_my_pll {} { 5 | set out_freq {{{out_freq}}} 6 | 7 | # create the system 8 | create_system my_pll 9 | set_project_property DEVICE {1SM21BHU2F53E1VG} 10 | set_project_property DEVICE_FAMILY {Stratix 10} 11 | set_project_property HIDE_FROM_IP_CATALOG {true} 12 | set_use_testbench_naming_pattern 0 {} 13 | 14 | # add the components 15 | add_instance iopll_0 altera_iopll 19.3.0 16 | set_instance_parameter_value iopll_0 {gui_active_clk} {0} 17 | set_instance_parameter_value iopll_0 {gui_c_cnt_in_src0} {c_m_cnt_in_src_ph_mux_clk} 18 | set_instance_parameter_value iopll_0 {gui_c_cnt_in_src1} {c_m_cnt_in_src_ph_mux_clk} 19 | set_instance_parameter_value iopll_0 {gui_c_cnt_in_src2} {c_m_cnt_in_src_ph_mux_clk} 20 | set_instance_parameter_value iopll_0 {gui_c_cnt_in_src3} {c_m_cnt_in_src_ph_mux_clk} 21 | set_instance_parameter_value iopll_0 {gui_c_cnt_in_src4} {c_m_cnt_in_src_ph_mux_clk} 22 | set_instance_parameter_value iopll_0 {gui_c_cnt_in_src5} {c_m_cnt_in_src_ph_mux_clk} 23 | set_instance_parameter_value iopll_0 {gui_c_cnt_in_src6} {c_m_cnt_in_src_ph_mux_clk} 24 | set_instance_parameter_value iopll_0 {gui_c_cnt_in_src7} {c_m_cnt_in_src_ph_mux_clk} 25 | set_instance_parameter_value iopll_0 {gui_c_cnt_in_src8} {c_m_cnt_in_src_ph_mux_clk} 26 | set_instance_parameter_value iopll_0 {gui_cal_code_hex_file} {iossm.hex} 27 | set_instance_parameter_value iopll_0 {gui_cal_converge} {0} 28 | set_instance_parameter_value iopll_0 {gui_cal_error} {cal_clean} 29 | set_instance_parameter_value iopll_0 {gui_cascade_counter0} {0} 30 | set_instance_parameter_value iopll_0 {gui_cascade_counter1} {0} 31 | set_instance_parameter_value iopll_0 {gui_cascade_counter10} {0} 32 | set_instance_parameter_value iopll_0 {gui_cascade_counter11} {0} 33 | set_instance_parameter_value iopll_0 {gui_cascade_counter12} {0} 34 | set_instance_parameter_value iopll_0 {gui_cascade_counter13} {0} 35 | set_instance_parameter_value iopll_0 {gui_cascade_counter14} {0} 36 | set_instance_parameter_value iopll_0 {gui_cascade_counter15} {0} 37 | set_instance_parameter_value iopll_0 {gui_cascade_counter16} {0} 38 | set_instance_parameter_value iopll_0 {gui_cascade_counter17} {0} 39 | set_instance_parameter_value iopll_0 {gui_cascade_counter2} {0} 40 | set_instance_parameter_value iopll_0 {gui_cascade_counter3} {0} 41 | set_instance_parameter_value iopll_0 {gui_cascade_counter4} {0} 42 | set_instance_parameter_value iopll_0 {gui_cascade_counter5} {0} 43 | set_instance_parameter_value iopll_0 {gui_cascade_counter6} {0} 44 | set_instance_parameter_value iopll_0 {gui_cascade_counter7} {0} 45 | set_instance_parameter_value iopll_0 {gui_cascade_counter8} {0} 46 | set_instance_parameter_value iopll_0 {gui_cascade_counter9} {0} 47 | set_instance_parameter_value iopll_0 {gui_cascade_outclk_index} {0} 48 | set_instance_parameter_value iopll_0 {gui_clk_bad} {0} 49 | set_instance_parameter_value iopll_0 {gui_clock_name_global} {0} 50 | set_instance_parameter_value iopll_0 {gui_clock_name_string0} {outclk0} 51 | set_instance_parameter_value iopll_0 {gui_clock_name_string1} {outclk1} 52 | set_instance_parameter_value iopll_0 {gui_clock_name_string10} {outclk10} 53 | set_instance_parameter_value iopll_0 {gui_clock_name_string11} {outclk11} 54 | set_instance_parameter_value iopll_0 {gui_clock_name_string12} {outclk12} 55 | set_instance_parameter_value iopll_0 {gui_clock_name_string13} {outclk13} 56 | set_instance_parameter_value iopll_0 {gui_clock_name_string14} {outclk14} 57 | set_instance_parameter_value iopll_0 {gui_clock_name_string15} {outclk15} 58 | set_instance_parameter_value iopll_0 {gui_clock_name_string16} {outclk16} 59 | set_instance_parameter_value iopll_0 {gui_clock_name_string17} {outclk17} 60 | set_instance_parameter_value iopll_0 {gui_clock_name_string2} {outclk2} 61 | set_instance_parameter_value iopll_0 {gui_clock_name_string3} {outclk3} 62 | set_instance_parameter_value iopll_0 {gui_clock_name_string4} {outclk4} 63 | set_instance_parameter_value iopll_0 {gui_clock_name_string5} {outclk5} 64 | set_instance_parameter_value iopll_0 {gui_clock_name_string6} {outclk6} 65 | set_instance_parameter_value iopll_0 {gui_clock_name_string7} {outclk7} 66 | set_instance_parameter_value iopll_0 {gui_clock_name_string8} {outclk8} 67 | set_instance_parameter_value iopll_0 {gui_clock_name_string9} {outclk9} 68 | set_instance_parameter_value iopll_0 {gui_clock_to_compensate} {0} 69 | set_instance_parameter_value iopll_0 {gui_debug_mode} {0} 70 | set_instance_parameter_value iopll_0 {gui_divide_factor_c0} {6} 71 | set_instance_parameter_value iopll_0 {gui_divide_factor_c1} {6} 72 | set_instance_parameter_value iopll_0 {gui_divide_factor_c10} {6} 73 | set_instance_parameter_value iopll_0 {gui_divide_factor_c11} {6} 74 | set_instance_parameter_value iopll_0 {gui_divide_factor_c12} {6} 75 | set_instance_parameter_value iopll_0 {gui_divide_factor_c13} {6} 76 | set_instance_parameter_value iopll_0 {gui_divide_factor_c14} {6} 77 | set_instance_parameter_value iopll_0 {gui_divide_factor_c15} {6} 78 | set_instance_parameter_value iopll_0 {gui_divide_factor_c16} {6} 79 | set_instance_parameter_value iopll_0 {gui_divide_factor_c17} {6} 80 | set_instance_parameter_value iopll_0 {gui_divide_factor_c2} {6} 81 | set_instance_parameter_value iopll_0 {gui_divide_factor_c3} {6} 82 | set_instance_parameter_value iopll_0 {gui_divide_factor_c4} {6} 83 | set_instance_parameter_value iopll_0 {gui_divide_factor_c5} {6} 84 | set_instance_parameter_value iopll_0 {gui_divide_factor_c6} {6} 85 | set_instance_parameter_value iopll_0 {gui_divide_factor_c7} {6} 86 | set_instance_parameter_value iopll_0 {gui_divide_factor_c8} {6} 87 | set_instance_parameter_value iopll_0 {gui_divide_factor_c9} {6} 88 | set_instance_parameter_value iopll_0 {gui_divide_factor_n} {1} 89 | set_instance_parameter_value iopll_0 {gui_dps_cntr} {C0} 90 | set_instance_parameter_value iopll_0 {gui_dps_dir} {Positive} 91 | set_instance_parameter_value iopll_0 {gui_dps_num} {1} 92 | set_instance_parameter_value iopll_0 {gui_dsm_out_sel} {1st_order} 93 | set_instance_parameter_value iopll_0 {gui_duty_cycle0} {50.0} 94 | set_instance_parameter_value iopll_0 {gui_duty_cycle1} {50.0} 95 | set_instance_parameter_value iopll_0 {gui_duty_cycle10} {50.0} 96 | set_instance_parameter_value iopll_0 {gui_duty_cycle11} {50.0} 97 | set_instance_parameter_value iopll_0 {gui_duty_cycle12} {50.0} 98 | set_instance_parameter_value iopll_0 {gui_duty_cycle13} {50.0} 99 | set_instance_parameter_value iopll_0 {gui_duty_cycle14} {50.0} 100 | set_instance_parameter_value iopll_0 {gui_duty_cycle15} {50.0} 101 | set_instance_parameter_value iopll_0 {gui_duty_cycle16} {50.0} 102 | set_instance_parameter_value iopll_0 {gui_duty_cycle17} {50.0} 103 | set_instance_parameter_value iopll_0 {gui_duty_cycle2} {50.0} 104 | set_instance_parameter_value iopll_0 {gui_duty_cycle3} {50.0} 105 | set_instance_parameter_value iopll_0 {gui_duty_cycle4} {50.0} 106 | set_instance_parameter_value iopll_0 {gui_duty_cycle5} {50.0} 107 | set_instance_parameter_value iopll_0 {gui_duty_cycle6} {50.0} 108 | set_instance_parameter_value iopll_0 {gui_duty_cycle7} {50.0} 109 | set_instance_parameter_value iopll_0 {gui_duty_cycle8} {50.0} 110 | set_instance_parameter_value iopll_0 {gui_duty_cycle9} {50.0} 111 | set_instance_parameter_value iopll_0 {gui_en_adv_params} {0} 112 | set_instance_parameter_value iopll_0 {gui_en_dps_ports} {0} 113 | set_instance_parameter_value iopll_0 {gui_en_extclkout_ports} {0} 114 | set_instance_parameter_value iopll_0 {gui_en_lvds_ports} {Disabled} 115 | set_instance_parameter_value iopll_0 {gui_en_phout_ports} {0} 116 | set_instance_parameter_value iopll_0 {gui_en_reconf} {0} 117 | set_instance_parameter_value iopll_0 {gui_enable_cascade_in} {0} 118 | set_instance_parameter_value iopll_0 {gui_enable_cascade_out} {0} 119 | set_instance_parameter_value iopll_0 {gui_enable_mif_dps} {0} 120 | set_instance_parameter_value iopll_0 {gui_enable_output_counter_cascading} {0} 121 | set_instance_parameter_value iopll_0 {gui_enable_permit_cal} {0} 122 | set_instance_parameter_value iopll_0 {gui_existing_mif_file_path} {~/pll.mif} 123 | set_instance_parameter_value iopll_0 {gui_extclkout_0_source} {C0} 124 | set_instance_parameter_value iopll_0 {gui_extclkout_1_source} {C0} 125 | set_instance_parameter_value iopll_0 {gui_feedback_clock} {Global Clock} 126 | set_instance_parameter_value iopll_0 {gui_fix_vco_frequency} {0} 127 | set_instance_parameter_value iopll_0 {gui_fixed_vco_frequency} {600.0} 128 | set_instance_parameter_value iopll_0 {gui_fixed_vco_frequency_ps} {1667.0} 129 | set_instance_parameter_value iopll_0 {gui_frac_multiply_factor} {1.0} 130 | set_instance_parameter_value iopll_0 {gui_fractional_cout} {32} 131 | set_instance_parameter_value iopll_0 {gui_include_iossm} {0} 132 | set_instance_parameter_value iopll_0 {gui_location_type} {I/O Bank} 133 | set_instance_parameter_value iopll_0 {gui_lock_setting} {Low Lock Time} 134 | set_instance_parameter_value iopll_0 {gui_mif_config_name} {unnamed} 135 | set_instance_parameter_value iopll_0 {gui_mif_gen_options} {Generate New MIF File} 136 | set_instance_parameter_value iopll_0 {gui_multiply_factor} {15} 137 | set_instance_parameter_value iopll_0 {gui_new_mif_file_path} {~/pll.mif} 138 | set_instance_parameter_value iopll_0 {gui_number_of_clocks} {1} 139 | set_instance_parameter_value iopll_0 {gui_operation_mode} {direct} 140 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency0} $out_freq 141 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency1} {500.0} 142 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency10} {100.0} 143 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency11} {100.0} 144 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency12} {100.0} 145 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency13} {100.0} 146 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency14} {100.0} 147 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency15} {100.0} 148 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency16} {100.0} 149 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency17} {100.0} 150 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency2} {100.0} 151 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency3} {100.0} 152 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency4} {100.0} 153 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency5} {100.0} 154 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency6} {100.0} 155 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency7} {100.0} 156 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency8} {100.0} 157 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency9} {100.0} 158 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps0} {6666.667} 159 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps1} {2000.0} 160 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps10} {10000.0} 161 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps11} {10000.0} 162 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps12} {10000.0} 163 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps13} {10000.0} 164 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps14} {10000.0} 165 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps15} {10000.0} 166 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps16} {10000.0} 167 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps17} {10000.0} 168 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps2} {10000.0} 169 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps3} {10000.0} 170 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps4} {10000.0} 171 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps5} {10000.0} 172 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps6} {10000.0} 173 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps7} {10000.0} 174 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps8} {10000.0} 175 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps9} {10000.0} 176 | set_instance_parameter_value iopll_0 {gui_parameter_table_hex_file} {seq_params_sim.hex} 177 | set_instance_parameter_value iopll_0 {gui_phase_shift0} {0.0} 178 | set_instance_parameter_value iopll_0 {gui_phase_shift1} {0.0} 179 | set_instance_parameter_value iopll_0 {gui_phase_shift10} {0.0} 180 | set_instance_parameter_value iopll_0 {gui_phase_shift11} {0.0} 181 | set_instance_parameter_value iopll_0 {gui_phase_shift12} {0.0} 182 | set_instance_parameter_value iopll_0 {gui_phase_shift13} {0.0} 183 | set_instance_parameter_value iopll_0 {gui_phase_shift14} {0.0} 184 | set_instance_parameter_value iopll_0 {gui_phase_shift15} {0.0} 185 | set_instance_parameter_value iopll_0 {gui_phase_shift16} {0.0} 186 | set_instance_parameter_value iopll_0 {gui_phase_shift17} {0.0} 187 | set_instance_parameter_value iopll_0 {gui_phase_shift2} {0.0} 188 | set_instance_parameter_value iopll_0 {gui_phase_shift3} {0.0} 189 | set_instance_parameter_value iopll_0 {gui_phase_shift4} {0.0} 190 | set_instance_parameter_value iopll_0 {gui_phase_shift5} {0.0} 191 | set_instance_parameter_value iopll_0 {gui_phase_shift6} {0.0} 192 | set_instance_parameter_value iopll_0 {gui_phase_shift7} {0.0} 193 | set_instance_parameter_value iopll_0 {gui_phase_shift8} {0.0} 194 | set_instance_parameter_value iopll_0 {gui_phase_shift9} {0.0} 195 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg0} {0.0} 196 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg1} {0.0} 197 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg10} {0.0} 198 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg11} {0.0} 199 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg12} {0.0} 200 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg13} {0.0} 201 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg14} {0.0} 202 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg15} {0.0} 203 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg16} {0.0} 204 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg17} {0.0} 205 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg2} {0.0} 206 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg3} {0.0} 207 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg4} {0.0} 208 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg5} {0.0} 209 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg6} {0.0} 210 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg7} {0.0} 211 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg8} {0.0} 212 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg9} {0.0} 213 | set_instance_parameter_value iopll_0 {gui_phout_division} {1} 214 | set_instance_parameter_value iopll_0 {gui_pll_auto_reset} {0} 215 | set_instance_parameter_value iopll_0 {gui_pll_bandwidth_preset} {Low} 216 | set_instance_parameter_value iopll_0 {gui_pll_cal_done} {0} 217 | set_instance_parameter_value iopll_0 {gui_pll_cascading_mode} {adjpllin} 218 | set_instance_parameter_value iopll_0 {gui_pll_freqcal_en} {1} 219 | set_instance_parameter_value iopll_0 {gui_pll_freqcal_req_flag} {1} 220 | set_instance_parameter_value iopll_0 {gui_pll_m_cnt_in_src} {c_m_cnt_in_src_ph_mux_clk} 221 | set_instance_parameter_value iopll_0 {gui_pll_mode} {Integer-N PLL} 222 | set_instance_parameter_value iopll_0 {gui_pll_tclk_mux_en} {0} 223 | set_instance_parameter_value iopll_0 {gui_pll_tclk_sel} {pll_tclk_m_src} 224 | set_instance_parameter_value iopll_0 {gui_pll_type} {S10_Simple} 225 | set_instance_parameter_value iopll_0 {gui_pll_vco_freq_band_0} {pll_freq_clk0_disabled} 226 | set_instance_parameter_value iopll_0 {gui_pll_vco_freq_band_1} {pll_freq_clk1_disabled} 227 | set_instance_parameter_value iopll_0 {gui_prot_mode} {UNUSED} 228 | set_instance_parameter_value iopll_0 {gui_ps_units0} {ps} 229 | set_instance_parameter_value iopll_0 {gui_ps_units1} {ps} 230 | set_instance_parameter_value iopll_0 {gui_ps_units10} {ps} 231 | set_instance_parameter_value iopll_0 {gui_ps_units11} {ps} 232 | set_instance_parameter_value iopll_0 {gui_ps_units12} {ps} 233 | set_instance_parameter_value iopll_0 {gui_ps_units13} {ps} 234 | set_instance_parameter_value iopll_0 {gui_ps_units14} {ps} 235 | set_instance_parameter_value iopll_0 {gui_ps_units15} {ps} 236 | set_instance_parameter_value iopll_0 {gui_ps_units16} {ps} 237 | set_instance_parameter_value iopll_0 {gui_ps_units17} {ps} 238 | set_instance_parameter_value iopll_0 {gui_ps_units2} {ps} 239 | set_instance_parameter_value iopll_0 {gui_ps_units3} {ps} 240 | set_instance_parameter_value iopll_0 {gui_ps_units4} {ps} 241 | set_instance_parameter_value iopll_0 {gui_ps_units5} {ps} 242 | set_instance_parameter_value iopll_0 {gui_ps_units6} {ps} 243 | set_instance_parameter_value iopll_0 {gui_ps_units7} {ps} 244 | set_instance_parameter_value iopll_0 {gui_ps_units8} {ps} 245 | set_instance_parameter_value iopll_0 {gui_ps_units9} {ps} 246 | set_instance_parameter_value iopll_0 {gui_refclk1_frequency} {100.0} 247 | set_instance_parameter_value iopll_0 {gui_refclk_might_change} {0} 248 | set_instance_parameter_value iopll_0 {gui_refclk_switch} {0} 249 | set_instance_parameter_value iopll_0 {gui_reference_clock_frequency} {100.0} 250 | set_instance_parameter_value iopll_0 {gui_reference_clock_frequency_ps} {10000.0} 251 | set_instance_parameter_value iopll_0 {gui_skip_sdc_generation} {0} 252 | set_instance_parameter_value iopll_0 {gui_switchover_delay} {0} 253 | set_instance_parameter_value iopll_0 {gui_switchover_mode} {Automatic Switchover} 254 | set_instance_parameter_value iopll_0 {gui_use_NDFB_modes} {0} 255 | set_instance_parameter_value iopll_0 {gui_use_coreclk} {0} 256 | set_instance_parameter_value iopll_0 {gui_use_locked} {1} 257 | set_instance_parameter_value iopll_0 {gui_use_logical} {0} 258 | set_instance_parameter_value iopll_0 {gui_usr_device_speed_grade} {1} 259 | set_instance_parameter_value iopll_0 {gui_vco_frequency} {1500.0} 260 | set_instance_parameter_value iopll_0 {hp_qsys_scripting_mode} {0} 261 | set_instance_property iopll_0 AUTO_EXPORT true 262 | 263 | # add wirelevel expressions 264 | 265 | # add the exports 266 | set_interface_property reset EXPORT_OF iopll_0.reset 267 | set_interface_property refclk EXPORT_OF iopll_0.refclk 268 | set_interface_property locked EXPORT_OF iopll_0.locked 269 | set_interface_property outclk0 EXPORT_OF iopll_0.outclk0 270 | 271 | # set the the module properties 272 | set_module_property BONUS_DATA { 273 | 274 | 275 | 276 | 277 | 278 | } 279 | set_module_property FILE {my_pll.ip} 280 | set_module_property GENERATION_ID {0x00000000} 281 | set_module_property NAME {my_pll} 282 | 283 | # save the system 284 | sync_sysinfo_parameters 285 | save_system my_pll 286 | } 287 | 288 | # create all the systems, from bottom up 289 | do_create_my_pll 290 | -------------------------------------------------------------------------------- /hardware/bbq/quartus/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !*.qpf 4 | !*.qsf 5 | !*.sdc 6 | -------------------------------------------------------------------------------- /hardware/bbq/quartus/bbq.qpf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------- # 2 | # 3 | # Copyright (C) 2019 Intel Corporation. All rights reserved. 4 | # Your use of Intel Corporation's design tools, logic functions 5 | # and other software and tools, and any partner logic 6 | # functions, and any output files from any of the foregoing 7 | # (including device programming or simulation files), and any 8 | # associated documentation or information are expressly subject 9 | # to the terms and conditions of the Intel Program License 10 | # Subscription Agreement, the Intel Quartus Prime License Agreement, 11 | # the Intel FPGA IP License Agreement, or other applicable license 12 | # agreement, including, without limitation, that your use is for 13 | # the sole purpose of programming logic devices manufactured by 14 | # Intel and sold by Intel or its authorized distributors. Please 15 | # refer to the applicable agreement for further details, at 16 | # https://fpgasoftware.intel.com/eula. 17 | # 18 | # -------------------------------------------------------------------------- # 19 | # 20 | # Quartus Prime 21 | # Version 19.3.0 Build 222 09/23/2019 SC Pro Edition 22 | # Date created = 16:59:58 January 20, 2023 23 | # 24 | # -------------------------------------------------------------------------- # 25 | 26 | QUARTUS_VERSION = "19.3" 27 | DATE = "16:59:58 January 20, 2023" 28 | 29 | # Revisions 30 | 31 | PROJECT_REVISION = "bbq" 32 | -------------------------------------------------------------------------------- /hardware/bbq/quartus/bbq.qsf: -------------------------------------------------------------------------------- 1 | 2 | # Project-Wide Assignments 3 | # ======================== 4 | set_global_assignment -name ORIGINAL_QUARTUS_VERSION 19.3.0 5 | set_global_assignment -name PROJECT_CREATION_TIME_DATE "13:24:03 JANUARY 20, 2023" 6 | set_global_assignment -name LAST_QUARTUS_VERSION "19.3.0 Pro Edition" 7 | set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files 8 | 9 | # Pin & Location Assignments 10 | # ========================== 11 | set_location_assignment PIN_BL14 -to cpu_resetn 12 | set_location_assignment PIN_AT13 -to in_clk100 13 | set_location_assignment PIN_AU13 -to "in_clk100(n)" 14 | set_location_assignment PIN_BG12 -to bbq_out 15 | 16 | # Classic Timing Assignments 17 | # ========================== 18 | set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 19 | set_global_assignment -name MAX_CORE_JUNCTION_TEMP 100 20 | set_global_assignment -name TIMING_ANALYZER_MULTICORNER_ANALYSIS ON 21 | 22 | # Analysis & Synthesis Assignments 23 | # ================================ 24 | set_global_assignment -name TOP_LEVEL_ENTITY top 25 | set_global_assignment -name FAMILY "Stratix 10" 26 | set_global_assignment -name SEARCH_PATH ../src/common 27 | 28 | # Fitter Assignments 29 | # ================== 30 | set_global_assignment -name DEVICE 1SM21BHU2F53E1VG 31 | set_instance_assignment -name IO_STANDARD LVDS -to in_clk100 -entity top 32 | set_instance_assignment -name IO_STANDARD LVDS -to "in_clk100(n)" -entity top 33 | set_instance_assignment -name IO_STANDARD "1.8 V" -to cpu_resetn -entity top 34 | set_instance_assignment -name IO_STANDARD "1.8 V" -to bbq_out -entity top 35 | 36 | # Ordering Sensitive Assignments 37 | # ============================== 38 | 39 | set_global_assignment -name OPTIMIZATION_MODE "SUPERIOR PERFORMANCE WITH MAXIMUM PLACEMENT EFFORT" 40 | set_global_assignment -name ENABLE_INTERMEDIATE_SNAPSHOTS ON 41 | set_global_assignment -name FAST_PRESERVE OFF -entity top 42 | 43 | set_global_assignment -name SYSTEMVERILOG_FILE ../src/top.sv 44 | set_global_assignment -name SYSTEMVERILOG_FILE ../src/bbq.sv 45 | set_global_assignment -name SYSTEMVERILOG_FILE ../src/ffs.sv 46 | set_global_assignment -name SYSTEMVERILOG_FILE ../src/heap_ops.sv 47 | set_global_assignment -name VERILOG_FILE ../src/common/bram_simple2port.v 48 | set_global_assignment -name VERILOG_FILE ../src/common/sc_fifo.v 49 | set_global_assignment -name IP_FILE ../ip/my_pll.ip 50 | 51 | set_global_assignment -name SDC_ENTITY_FILE bbq.sdc -entity top 52 | -------------------------------------------------------------------------------- /hardware/bbq/quartus/bbq.sdc: -------------------------------------------------------------------------------- 1 | 2 | # create_clock -period 10.00 -name in_clk100 [get_ports in_clk100] 3 | 4 | # Not needed for Stratix 10 5 | # derive_pll_clocks 6 | 7 | derive_clock_uncertainty 8 | -------------------------------------------------------------------------------- /hardware/bbq/scripts/bisect_fmax.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Usage: ELEMENT_BITS=XXX BITMAP_WIDTH=YYY NUM_LEVELS=ZZZ \ 4 | # [MIN_FREQ=AAA] [MAX_FREQ=BBB] [PRECISION=CCC] \ 5 | # ./bisect_fmax.sh [seed1] [seed2] ... 6 | # 7 | # Given a design configuration, performs a bisection search to 8 | # find the target Fmax that closes timing. Tries as many seeds 9 | # as specified, using a single process for synthesis. 10 | # 11 | PROJECT_NAME="bbq" 12 | 13 | CUR_DIR=$(pwd) 14 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 15 | PROJECT_DIR="${SCRIPT_DIR}/.." 16 | 17 | if [ $# -eq 0 ]; then 18 | echo "Must specify seeds." 19 | exit 1 20 | fi 21 | 22 | SEEDS=$@ 23 | 24 | # If MIN_FREQ is not defined, use the default. 25 | if [ -z ${MIN_FREQ} ]; then 26 | MIN_FREQ=50 27 | echo "MIN_FREQ is not defined, using ${MIN_FREQ} MHz." 28 | fi 29 | 30 | # If MAX_FREQ is not defined, use the default. 31 | if [ -z ${MAX_FREQ} ]; then 32 | MAX_FREQ=600 33 | echo "MAX_FREQ is not defined, using ${MAX_FREQ} MHz." 34 | fi 35 | 36 | # If PRECISION is not defined, use the default. 37 | if [ -z ${PRECISION} ]; then 38 | PRECISION=3 39 | echo "PRECISION is not defined, using ${PRECISION} MHz." 40 | 41 | elif [ ${PRECISION} -lt 1 ]; then 42 | echo "PRECISION must be greater than 0." 43 | exit 1 44 | fi 45 | 46 | # Outputs 47 | best_fmax=0 48 | best_seed=-1 49 | output_dir="${PROJECT_DIR}/quartus/bisect_fmax" 50 | 51 | # Report files 52 | timing_report="${PROJECT_DIR}/quartus/output_files/${PROJECT_NAME}.sta.rpt" 53 | fitter_report="${PROJECT_DIR}/quartus/output_files/${PROJECT_NAME}.fit.summary" 54 | 55 | # Setup 56 | rm -rf ${output_dir} 57 | rm -f ${timing_report} 58 | rm -f ${fitter_report} 59 | mkdir -p ${output_dir} 60 | 61 | # Housekeeping 62 | fmax_lower=0 63 | fmax_upper=${MAX_FREQ} 64 | current_freq=$(( ${MAX_FREQ} / 2 )) 65 | 66 | while true 67 | do 68 | # Setup for the next iteration 69 | rm -rf ${PROJECT_DIR}/quartus/output_files 70 | 71 | # Print start message and run the setup script for the current fmax 72 | echo "Attempting synthesis with target fmax ${current_freq} MHz" 73 | ${PROJECT_DIR}/setup.sh ${current_freq} 74 | if [ $? -ne 0 ]; then 75 | echo "Setup script failed for ${current_freq} MHz, exiting." 76 | exit 1 77 | fi 78 | 79 | timing_success=0 80 | for seed in ${SEEDS[@]}; do 81 | 82 | # First, run synthesis for this seed 83 | ${SCRIPT_DIR}/synthesize.sh ${seed} 84 | if [ $? -ne 0 ]; then 85 | echo "Synthesis script failed for ${current_freq} MHz and seed ${seed}, skipping." 86 | continue 87 | fi 88 | # If the timing report is clear, declare success 89 | if [ -f "${timing_report}" ]; then 90 | timing_success=1 91 | if grep -qcm1 "Timing requirements not met" ${timing_report}; then 92 | timing_success=0; 93 | fi 94 | fi 95 | # Found a seed that works, stop early 96 | if [ ${timing_success} -eq 1 ]; then 97 | best_fmax=${current_freq} 98 | best_seed=${seed} 99 | 100 | # Copy the reports to the output directory 101 | cp ${timing_report} ${output_dir}/ 102 | cp ${fitter_report} ${output_dir}/ 103 | break 104 | fi 105 | done 106 | 107 | if [ ${timing_success} -eq 1 ]; then 108 | # Found a new lower bound 109 | fmax_lower=${current_freq} 110 | else 111 | # Synthesis failed, found a new upper bound 112 | fmax_upper=${current_freq} 113 | fi 114 | # Update frequency estimate 115 | current_freq=$(( (${fmax_lower} + ${fmax_upper}) / 2 )) 116 | 117 | if (( ${current_freq} < ${MIN_FREQ} )); then 118 | echo "Warning: bisect_fmax reached MIN_FREQ, design may not be synthesizable." 119 | break 120 | 121 | elif (( ${fmax_upper} - ${fmax_lower} <= ${PRECISION} )); then 122 | break # Found the frequency 123 | fi 124 | done 125 | 126 | if [ ${best_fmax} -ne 0 ]; then 127 | echo "Best fmax: ${best_fmax}, seed: ${best_seed}" | tee ${output_dir}/fmax.txt 128 | fi 129 | 130 | # Announce that it is over. 131 | tput bel 132 | -------------------------------------------------------------------------------- /hardware/bbq/scripts/sweep_bisect_fmax.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Usage: [MIN_FREQ=AAA] [MAX_FREQ=BBB] [PRECISION=CCC] \ 4 | # [NUM_PROCS=DDD] ./sweep_bisect_fmax.sh [seed1] [seed2] ... 5 | # 6 | PROJECT_NAME="bbq" 7 | 8 | CUR_DIR=$(pwd) 9 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 10 | PROJECT_DIR="${SCRIPT_DIR}/.." 11 | 12 | if [ $# -eq 0 ]; then 13 | echo "Must specify seeds." 14 | exit 1 15 | fi 16 | 17 | # If NUM_PROCS is not defined, use the default. 18 | if [ -z ${NUM_PROCS} ]; then 19 | NUM_PROCS=8 20 | echo "NUM_PROCS is not defined, using ${NUM_PROCS}." 21 | fi 22 | 23 | # Exit when error occurs. 24 | set -e 25 | trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG 26 | trap 'echo "\"${last_command}\" command exited with code $?."' EXIT 27 | 28 | rm -rf ${PROJECT_DIR}/quartus/sweep_bisect_fmax 29 | mkdir -p ${PROJECT_DIR}/quartus/sweep_bisect_fmax 30 | 31 | tmp_dir="/tmp/${PROJECT_NAME}" 32 | rm -rf ${tmp_dir} 33 | cp -r ${PROJECT_DIR} ${tmp_dir} 34 | rm -rf ${tmp_dir}/quartus/sweep_bisect_fmax 35 | 36 | jobs="sweep_bisect_fmax_jobs.txt" 37 | rm -f ${jobs} 38 | 39 | max_num_priorities=32768 40 | # Number of element bits 41 | for n in 12 15 17 42 | do 43 | # Bitmap widths 44 | for b in 2 4 8 16 32 45 | do 46 | # Number of levels 47 | for l in 3 4 5 6 8 12 15 48 | do 49 | num_priorities=$((${b}**${l})) 50 | if [[ ${num_priorities} -le ${max_num_priorities} ]] 51 | then 52 | midfix="l${l}_b${b}_n${n}" 53 | 54 | dst_dir=${PROJECT_DIR}/quartus/sweep_bisect_fmax/${midfix} 55 | rm -rf ${dst_dir} 56 | cp -r ${tmp_dir} ${dst_dir} 57 | 58 | echo "ELEMENT_BITS=${n} BITMAP_WIDTH=${b} NUM_LEVELS=${l}"\ 59 | "${dst_dir}/scripts/bisect_fmax.sh $@ | tee"\ 60 | "${dst_dir}/bisect_fmax_log.txt" >> ${jobs} 61 | else 62 | break 63 | fi 64 | done 65 | done 66 | done 67 | 68 | rm -rf ${tmp_dir} 69 | parallel -j${NUM_PROCS} < ${jobs} 70 | rm -f ${jobs} 71 | -------------------------------------------------------------------------------- /hardware/bbq/scripts/sweep_params.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Usage: ./sweep_params.sh [SEED] 4 | # 5 | PROJECT_NAME="bbq" 6 | 7 | CUR_DIR=$(pwd) 8 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 9 | PROJECT_DIR="${SCRIPT_DIR}/.." 10 | 11 | SEED=${1:-"0"} 12 | 13 | # Exit when error occurs. 14 | set -e 15 | trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG 16 | trap 'echo "\"${last_command}\" command exited with code $?."' EXIT 17 | 18 | rm -rf ${PROJECT_DIR}/quartus/sweep_params 19 | mkdir -p ${PROJECT_DIR}/quartus/sweep_params 20 | 21 | tmp_dir="/tmp/${PROJECT_NAME}" 22 | rm -rf ${tmp_dir} 23 | cp -r ${PROJECT_DIR} ${tmp_dir} 24 | rm -rf ${tmp_dir}/quartus/sweep_params 25 | 26 | jobs="sweep_params_jobs.txt" 27 | rm -f ${jobs} 28 | 29 | max_num_priorities=32768 30 | # Number of element bits 31 | for n in 12 15 17 32 | do 33 | # Bitmap widths 34 | for b in 2 4 8 16 32 35 | do 36 | # Number of levels 37 | for l in 3 4 5 6 8 12 15 38 | do 39 | num_priorities=$((${b}**${l})) 40 | if [[ ${num_priorities} -le ${max_num_priorities} ]] 41 | then 42 | midfix="l${l}_b${b}_n${n}" 43 | 44 | dst_dir=${PROJECT_DIR}/quartus/sweep_params/${midfix} 45 | rm -rf ${dst_dir} 46 | cp -r ${tmp_dir} ${dst_dir} 47 | 48 | echo "ELEMENT_BITS=${n} BITMAP_WIDTH=${b} NUM_LEVELS=${l} \ 49 | ${dst_dir}/scripts/synthesize.sh ${SEED}" >> ${jobs} 50 | else 51 | break 52 | fi 53 | done 54 | done 55 | done 56 | 57 | rm -rf ${tmp_dir} 58 | parallel -j4 < ${jobs} 59 | rm -f ${jobs} 60 | -------------------------------------------------------------------------------- /hardware/bbq/scripts/sweep_seeds.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Usage: ELEMENT_BITS=XXX BITMAP_WIDTH=YYY NUM_LEVELS=ZZZ \ 4 | # ./sweep_seeds.sh [seed1] [seed2] ... 5 | # 6 | # Launches as many workers as seeds that you specify. 7 | # 8 | PROJECT_NAME="bbq" 9 | 10 | CUR_DIR=$(pwd) 11 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 12 | PROJECT_DIR="${SCRIPT_DIR}/.." 13 | 14 | if [ $# -eq 0 ]; then 15 | echo "Must specify seeds." 16 | exit 1 17 | fi 18 | 19 | SEEDS=$@ 20 | 21 | # Exit when error occurs. 22 | set -e 23 | trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG 24 | trap 'echo "\"${last_command}\" command exited with code $?."' EXIT 25 | 26 | rm -rf ${PROJECT_DIR}/quartus/sweep_seeds 27 | mkdir -p ${PROJECT_DIR}/quartus/sweep_seeds 28 | 29 | tmp_dir="/tmp/${PROJECT_NAME}" 30 | rm -rf ${tmp_dir} 31 | cp -r ${PROJECT_DIR} ${tmp_dir} 32 | rm -rf ${tmp_dir}/quartus/sweep_seeds 33 | 34 | for seed in $SEEDS; do 35 | dst_dir=${PROJECT_DIR}/quartus/sweep_seeds/${seed} 36 | rm -rf ${dst_dir} 37 | cp -r ${tmp_dir} ${dst_dir} 38 | done 39 | 40 | rm -rf ${tmp_dir} 41 | 42 | parallel "${PROJECT_DIR}/quartus/sweep_seeds/{}/scripts/synthesize.sh {}" ::: $SEEDS 43 | -------------------------------------------------------------------------------- /hardware/bbq/scripts/synthesize.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Usage: ELEMENT_BITS=XXX BITMAP_WIDTH=YYY \ 4 | # NUM_LEVELS=ZZZ ./synthesize.sh [SEED] 5 | # 6 | PROJECT_NAME="bbq" 7 | 8 | CUR_DIR=$(pwd) 9 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 10 | PROJECT_DIR="${SCRIPT_DIR}/.." 11 | 12 | SEED=${1:-"0"} 13 | 14 | # If ELEMENT_BITS is not defined, exit. 15 | if [ -z ${ELEMENT_BITS} ]; then 16 | echo "ELEMENT_BITS is not defined. Exiting." 17 | exit 1 18 | fi 19 | 20 | # If BITMAP_WIDTH is not defined, exit. 21 | if [ -z ${BITMAP_WIDTH} ]; then 22 | echo "BITMAP_WIDTH is not defined. Exiting." 23 | exit 1 24 | fi 25 | 26 | # If NUM_LEVELS is not defined, exit. 27 | if [ -z ${NUM_LEVELS} ]; then 28 | echo "NUM_LEVELS is not defined. Exiting." 29 | exit 1 30 | fi 31 | 32 | echo "SEED=${SEED}" 33 | 34 | PROJECT_OUTPUT_DIRECTORY="output_files" 35 | QUARTUS_STA_LOG_FILE="quartus_sta.log" 36 | 37 | # Exit when error occurs. 38 | set -e 39 | trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG 40 | trap 'echo "\"${last_command}\" command exited with code $?."' EXIT 41 | 42 | # Re-generate bbq.sv with the appropriate number of levels 43 | cd ${PROJECT_DIR}/generator 44 | rm -f ../src/bbq.sv 45 | python3 bbq.py ${NUM_LEVELS} > ../src/bbq.sv 46 | 47 | cd ${PROJECT_DIR}/quartus 48 | 49 | start=$(date +%s.%N) 50 | # Generate IPs if necessary. 51 | quartus_ipgenerate ${PROJECT_NAME} 52 | 53 | quartus_syn --read_settings_files=on --write_settings_files=off ${PROJECT_NAME} \ 54 | -c ${PROJECT_NAME} --set=VERILOG_MACRO=BITMAP_WIDTH=${BITMAP_WIDTH} \ 55 | --set=VERILOG_MACRO=ELEMENT_BITS=${ELEMENT_BITS} \ 56 | --set=VERILOG_MACRO=NUM_LEVELS=${NUM_LEVELS} 57 | 58 | quartus_fit --read_settings_files=on --write_settings_files=off ${PROJECT_NAME} \ 59 | -c ${PROJECT_NAME} --seed=${SEED} 60 | 61 | # We use script instead of tee to capture the output and display it while 62 | # preserving colors. 63 | script --flush --quiet --return ${QUARTUS_STA_LOG_FILE} \ 64 | --command "quartus_sta ${PROJECT_NAME} -c ${PROJECT_NAME} --mode=finalize" 65 | 66 | quartus_asm --read_settings_files=on --write_settings_files=off ${PROJECT_NAME} \ 67 | -c ${PROJECT_NAME} 68 | 69 | dur=$(echo "$(date +%s.%N) - ${start}" | bc) 70 | printf "Synthesis completed in %.6f seconds\n" ${dur} 71 | 72 | # Show Fmax. 73 | grep -C2 "; Fmax" "${PROJECT_OUTPUT_DIRECTORY}/${PROJECT_NAME}.sta.rpt" 74 | 75 | if grep -q "Timing requirements not met" ${QUARTUS_STA_LOG_FILE}; then 76 | # Show slack. 77 | grep -C 10 "Timing requirements not met" ${QUARTUS_STA_LOG_FILE} 78 | RED='\033[0;31m' 79 | NC='\033[0m' # No Color. 80 | echo -e "${RED}===========================${NC}" 81 | echo -e "${RED}Timing requirements not met${NC}" 82 | echo -e "${RED}===========================${NC}" 83 | fi 84 | 85 | echo "Done (L=${NUM_LEVELS}, BM=${BITMAP_WIDTH}, log2(N)=${ELEMENT_BITS}, seed=${SEED})" 86 | 87 | # Announce that it is over. 88 | tput bel 89 | -------------------------------------------------------------------------------- /hardware/bbq/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Usage: ./setup.sh FREQ_MHZ 4 | # 5 | # Generates the required IPs for the project. FREQ_MHZ is the frequency of the 6 | # PLL in MHz. It must be an integer. 7 | 8 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 9 | 10 | if [ $# -eq 0 ]; then 11 | echo "Must specify frequency in MHz." 12 | exit 1 13 | fi 14 | 15 | FREQ=$1 16 | 17 | # Check if FREQ is an integer. 18 | if ! [[ $FREQ =~ ^[0-9]+$ ]]; then 19 | echo "Frequency must be an integer." 20 | exit 1 21 | fi 22 | 23 | cd $SCRIPT_DIR/ip 24 | rm -rf my_pll 25 | rm -f my_pll.tcl 26 | sed "s/{{{out_freq}}}/${FREQ}.0/g" my_pll.tcl.template > my_pll.tcl 27 | qsys-script --script=my_pll.tcl --quartus-project=../quartus/bbq.qsf 28 | -------------------------------------------------------------------------------- /hardware/bbq/src/common/bram_simple2port.v: -------------------------------------------------------------------------------- 1 | // (C) 2001-2019 Intel Corporation. All rights reserved. 2 | // Your use of Intel Corporation's design tools, logic functions and other 3 | // software and tools, and its AMPP partner logic functions, and any output 4 | // files from any of the foregoing (including device programming or simulation 5 | // files), and any associated documentation or information are expressly subject 6 | // to the terms and conditions of the Intel Program License Subscription 7 | // Agreement, Intel FPGA IP License Agreement, or other applicable 8 | // license agreement, including, without limitation, that your use is for the 9 | // sole purpose of programming logic devices manufactured by Intel and sold by 10 | // Intel or its authorized distributors. Please refer to the applicable 11 | // agreement for further details. 12 | 13 | 14 | 15 | // synopsys translate_off 16 | `timescale 1 ps / 1 ps 17 | // synopsys translate_on 18 | module bram_simple2port ( 19 | clock, 20 | data, 21 | rdaddress, 22 | rden, 23 | wraddress, 24 | wren, 25 | q); 26 | 27 | parameter DWIDTH = 16; 28 | parameter AWIDTH = 9; 29 | parameter DEPTH = 512; 30 | parameter IS_OUTDATA_REG = 1; 31 | 32 | localparam OUTDATA_REG = ( 33 | (IS_OUTDATA_REG == 0) ? "UNREGISTERED" : "CLOCK0"); 34 | 35 | input clock; 36 | input [DWIDTH-1:0] data; 37 | input [AWIDTH-1:0] rdaddress; 38 | input rden; 39 | input [AWIDTH-1:0] wraddress; 40 | input wren; 41 | output [DWIDTH-1:0] q; 42 | `ifndef ALTERA_RESERVED_QIS 43 | // synopsys translate_off 44 | `endif 45 | tri1 clock; 46 | tri1 rden; 47 | tri0 wren; 48 | `ifndef ALTERA_RESERVED_QIS 49 | // synopsys translate_on 50 | `endif 51 | 52 | wire [DWIDTH-1:0] sub_wire0; 53 | wire [DWIDTH-1:0] q = sub_wire0[DWIDTH-1:0]; 54 | 55 | altera_syncram altera_syncram_component ( 56 | .address_a (wraddress), 57 | .address_b (rdaddress), 58 | .clock0 (clock), 59 | .data_a (data), 60 | .rden_b (rden), 61 | .wren_a (wren), 62 | .q_b (sub_wire0), 63 | .aclr0 (1'b0), 64 | .aclr1 (1'b0), 65 | .address2_a (1'b1), 66 | .address2_b (1'b1), 67 | .addressstall_a (1'b0), 68 | .addressstall_b (1'b0), 69 | .byteena_a (1'b1), 70 | .byteena_b (1'b1), 71 | .clock1 (1'b1), 72 | .clocken0 (1'b1), 73 | .clocken1 (1'b1), 74 | .clocken2 (1'b1), 75 | .clocken3 (1'b1), 76 | .data_b ({DWIDTH{1'b1}}), 77 | .eccencbypass (1'b0), 78 | .eccencparity (8'b0), 79 | .eccstatus (), 80 | .q_a (), 81 | .rden_a (1'b1), 82 | .sclr (1'b0), 83 | .wren_b (1'b0)); 84 | defparam 85 | altera_syncram_component.address_aclr_b = "NONE", 86 | altera_syncram_component.address_reg_b = "CLOCK0", 87 | altera_syncram_component.clock_enable_input_a = "BYPASS", 88 | altera_syncram_component.clock_enable_input_b = "BYPASS", 89 | altera_syncram_component.clock_enable_output_b = "BYPASS", 90 | altera_syncram_component.enable_ecc = "FALSE", 91 | altera_syncram_component.intended_device_family = "Stratix 10", 92 | altera_syncram_component.lpm_type = "altera_syncram", 93 | altera_syncram_component.numwords_a = DEPTH, 94 | altera_syncram_component.numwords_b = DEPTH, 95 | altera_syncram_component.operation_mode = "DUAL_PORT", 96 | altera_syncram_component.outdata_aclr_b = "NONE", 97 | altera_syncram_component.outdata_sclr_b = "NONE", 98 | altera_syncram_component.outdata_reg_b = OUTDATA_REG, 99 | altera_syncram_component.power_up_uninitialized = "FALSE", 100 | altera_syncram_component.ram_block_type = "M20K", 101 | altera_syncram_component.rdcontrol_reg_b = "CLOCK0", 102 | altera_syncram_component.read_during_write_mode_mixed_ports = "DONT_CARE", 103 | altera_syncram_component.widthad_a = AWIDTH, 104 | altera_syncram_component.widthad_b = AWIDTH, 105 | altera_syncram_component.width_a = DWIDTH, 106 | altera_syncram_component.width_b = DWIDTH, 107 | altera_syncram_component.width_byteena_a = 1; 108 | 109 | endmodule 110 | -------------------------------------------------------------------------------- /hardware/bbq/src/common/sc_fifo.v: -------------------------------------------------------------------------------- 1 | // (C) 2001-2019 Intel Corporation. All rights reserved. 2 | // Your use of Intel Corporation's design tools, logic functions and other 3 | // software and tools, and its AMPP partner logic functions, and any output 4 | // files from any of the foregoing (including device programming or simulation 5 | // files), and any associated documentation or information are expressly subject 6 | // to the terms and conditions of the Intel Program License Subscription 7 | // Agreement, Intel FPGA IP License Agreement, or other applicable 8 | // license agreement, including, without limitation, that your use is for the 9 | // sole purpose of programming logic devices manufactured by Intel and sold by 10 | // Intel or its authorized distributors. Please refer to the applicable 11 | // agreement for further details. 12 | 13 | 14 | 15 | // synopsys translate_off 16 | `timescale 1 ps / 1 ps 17 | // synopsys translate_on 18 | module sc_fifo ( 19 | clock, 20 | data, 21 | rdreq, 22 | wrreq, 23 | empty, 24 | full, 25 | q, 26 | usedw); 27 | 28 | parameter DWIDTH = 8; 29 | parameter DEPTH = 2048; 30 | parameter IS_SHOWAHEAD = 0; 31 | parameter IS_OUTDATA_REG = 0; 32 | 33 | localparam LOG_DEPTH = $clog2(DEPTH); 34 | localparam LPM_SHOWAHEAD = ( 35 | (IS_SHOWAHEAD == 0) ? "OFF" : "ON"); 36 | 37 | localparam ADD_RAM_OUTPUT_REGISTER = ( 38 | (IS_OUTDATA_REG == 0) ? "OFF" : "ON"); 39 | 40 | input clock; 41 | input [DWIDTH-1:0] data; 42 | input rdreq; 43 | input wrreq; 44 | output empty; 45 | output full; 46 | output [DWIDTH-1:0] q; 47 | output [LOG_DEPTH-1:0] usedw; 48 | 49 | wire sub_wire0; 50 | wire sub_wire1; 51 | wire [DWIDTH-1:0] sub_wire2; 52 | wire [LOG_DEPTH-1:0] sub_wire3; 53 | wire empty = sub_wire0; 54 | wire full = sub_wire1; 55 | wire [DWIDTH-1:0] q = sub_wire2[DWIDTH-1:0]; 56 | wire [LOG_DEPTH-1:0] usedw = sub_wire3[LOG_DEPTH-1:0]; 57 | 58 | scfifo scfifo_component ( 59 | .clock (clock), 60 | .data (data), 61 | .rdreq (rdreq), 62 | .wrreq (wrreq), 63 | .empty (sub_wire0), 64 | .full (sub_wire1), 65 | .q (sub_wire2), 66 | .usedw (sub_wire3), 67 | .aclr (1'b0), 68 | .almost_empty (), 69 | .almost_full (), 70 | .eccstatus (), 71 | .sclr (1'b0)); 72 | defparam 73 | scfifo_component.add_ram_output_register = ADD_RAM_OUTPUT_REGISTER, 74 | scfifo_component.enable_ecc = "FALSE", 75 | scfifo_component.intended_device_family = "Stratix 10", 76 | scfifo_component.lpm_numwords = DEPTH, 77 | scfifo_component.lpm_showahead = LPM_SHOWAHEAD, 78 | scfifo_component.lpm_type = "scfifo", 79 | scfifo_component.lpm_width = DWIDTH, 80 | scfifo_component.lpm_widthu = LOG_DEPTH, 81 | scfifo_component.overflow_checking = "ON", 82 | scfifo_component.underflow_checking = "ON", 83 | scfifo_component.use_eab = "ON"; 84 | 85 | endmodule 86 | -------------------------------------------------------------------------------- /hardware/bbq/src/ffs.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * Find first-set bits (MSb, LSb). 3 | */ 4 | module ffs #( 5 | parameter WIDTH_LOG = 4, 6 | localparam WIDTH = (1 << WIDTH_LOG) 7 | ) ( 8 | input logic [WIDTH-1:0] x, 9 | output logic [WIDTH_LOG-1:0] msb, 10 | output logic [WIDTH_LOG-1:0] lsb, 11 | output logic [WIDTH-1:0] msb_onehot, 12 | output logic [WIDTH-1:0] lsb_onehot, 13 | output logic zero 14 | ); 15 | 16 | integer i, width; 17 | logic [WIDTH-1:0] y; 18 | logic [WIDTH-1:0] part_msb; 19 | logic [WIDTH-1:0] part_lsb; 20 | 21 | // Zero input? 22 | assign zero = (x == 0); 23 | 24 | // Leading one (MSb) detector 25 | always @(*) begin 26 | msb = 0; 27 | part_msb = x; 28 | for (i = (WIDTH_LOG-1); i >= 0; i = i - 1) begin 29 | width = 1 << i; 30 | if (|(part_msb >> width)) begin 31 | msb[i] = 1; 32 | end 33 | part_msb = msb[i] ? (part_msb >> width) : 34 | (part_msb & ((1'd1 << width) - 1'd1)); 35 | end 36 | msb_onehot = (1 << msb); 37 | lsb_onehot = (((~x) + 1) & x); 38 | end 39 | 40 | // Reverse bit order for LSb detection 41 | always @(*) begin 42 | for (i = (WIDTH-1); i >= 0; i = i - 1) begin 43 | y[i] = x[(WIDTH-1) - i]; 44 | end 45 | end 46 | 47 | // Trailing one (LSb) detector 48 | // TODO(natre): Optimize impl. 49 | always @(*) begin 50 | lsb = 0; 51 | part_lsb = y; 52 | for (i = (WIDTH_LOG-1); i >= 0; i = i - 1) begin 53 | width = 1 << i; 54 | if (|(part_lsb >> width)) begin 55 | lsb[i] = 1; 56 | end 57 | part_lsb = lsb[i] ? (part_lsb >> width) : 58 | (part_lsb & ((1'd1 << width) - 1'd1)); 59 | end 60 | lsb = ~lsb; 61 | end 62 | 63 | endmodule 64 | -------------------------------------------------------------------------------- /hardware/bbq/src/heap_ops.sv: -------------------------------------------------------------------------------- 1 | package heap_ops; 2 | 3 | typedef enum logic [1:0] { 4 | HEAP_OP_ENQUE = 0, 5 | HEAP_OP_DEQUE_MIN, 6 | HEAP_OP_DEQUE_MAX 7 | } heap_op_t; 8 | 9 | endpackage 10 | -------------------------------------------------------------------------------- /hardware/bbq/src/top.sv: -------------------------------------------------------------------------------- 1 | `timescale 1 ps / 1 ps 2 | 3 | import heap_ops::*; 4 | 5 | `ifndef ELEMENT_BITS 6 | `define ELEMENT_BITS 17 7 | `endif // ELEMENT_BITS 8 | 9 | `ifndef BITMAP_WIDTH 10 | `define BITMAP_WIDTH 32 11 | `endif // BITMAP_WIDTH 12 | 13 | `ifndef NUM_LEVELS 14 | `define NUM_LEVELS 3 15 | `endif // NUM_LEVELS 16 | 17 | module top ( 18 | input in_clk100, 19 | input cpu_resetn, 20 | output logic bbq_out 21 | ); 22 | 23 | ///////////////////////// 24 | // dev_clr sync-reset 25 | ///////////////////////// 26 | wire arst, user_clk; 27 | assign arst = ~cpu_resetn; 28 | 29 | my_pll user_pll ( 30 | .rst (~cpu_resetn), 31 | .refclk (in_clk100), 32 | .locked (), 33 | .outclk_0 (user_clk) 34 | ); 35 | 36 | /** 37 | * BBQ. 38 | */ 39 | // Heap parameters 40 | localparam NB_LEVELS = `NUM_LEVELS; 41 | localparam HEAP_BITMAP_WIDTH = `BITMAP_WIDTH; 42 | localparam HEAP_ENTRY_DWIDTH = `ELEMENT_BITS; 43 | localparam HEAP_MAX_NUM_ENTRIES = ((1 << `ELEMENT_BITS) - 1); 44 | localparam HEAP_NUM_PRIORITIES = (HEAP_BITMAP_WIDTH ** NB_LEVELS); 45 | localparam HEAP_ENTRY_AWIDTH = ($clog2(HEAP_MAX_NUM_ENTRIES)); 46 | localparam HEAP_PRIORITY_AWIDTH = ($clog2(HEAP_NUM_PRIORITIES)); 47 | 48 | // Local typedefs 49 | typedef logic [HEAP_ENTRY_DWIDTH-1:0] heap_entry_data_t; 50 | typedef logic [HEAP_PRIORITY_AWIDTH-1:0] heap_priority_t; 51 | 52 | // Global state 53 | logic init_done; 54 | logic [63:0] counter; 55 | 56 | // Heap signals 57 | logic heap_ready; 58 | logic heap_in_valid; 59 | heap_op_t heap_in_op_type; 60 | heap_entry_data_t heap_in_data; 61 | heap_priority_t heap_in_priority; 62 | 63 | always @(posedge user_clk) begin 64 | if (arst) begin 65 | counter <= 0; 66 | init_done <= 0; 67 | end 68 | else begin 69 | heap_in_data <= 0; 70 | heap_in_valid <= 0; 71 | heap_in_priority <= 0; 72 | heap_in_op_type <= HEAP_OP_ENQUE; 73 | 74 | init_done <= (init_done | heap_ready); 75 | if (init_done) begin 76 | counter <= counter + 1; 77 | 78 | heap_in_valid <= 1; 79 | heap_in_data <= counter[HEAP_ENTRY_DWIDTH-1:0]; 80 | heap_in_priority <= counter[HEAP_PRIORITY_AWIDTH-1:0]; 81 | heap_in_op_type <= (counter[0] == 0) ? HEAP_OP_ENQUE : HEAP_OP_DEQUE_MIN; 82 | end 83 | end 84 | end 85 | 86 | localparam HEAP_PRIORITY_BUCKETS_AWIDTH = ($clog2(HEAP_NUM_PRIORITIES)); 87 | 88 | logic heap_out_valid; 89 | heap_op_t heap_out_op_type; 90 | logic [HEAP_ENTRY_DWIDTH-1:0] heap_out_he_data; 91 | logic [HEAP_PRIORITY_BUCKETS_AWIDTH-1:0] heap_out_he_priority; 92 | 93 | logic [31:0] out_placeholder; 94 | logic bbq_out_r; 95 | 96 | // Make sure we use all the outputs. 97 | always_comb begin 98 | out_placeholder = 0; 99 | out_placeholder ^= heap_out_op_type; 100 | out_placeholder ^= heap_out_he_data; 101 | out_placeholder ^= heap_out_he_priority; 102 | 103 | bbq_out_r = ^out_placeholder ^ heap_out_valid; 104 | end 105 | 106 | always_ff @(posedge user_clk) begin 107 | bbq_out <= bbq_out_r; 108 | end 109 | 110 | // BBQ instance 111 | bbq #( 112 | .HEAP_BITMAP_WIDTH(HEAP_BITMAP_WIDTH), 113 | .HEAP_ENTRY_DWIDTH(HEAP_ENTRY_DWIDTH), 114 | .HEAP_MAX_NUM_ENTRIES(HEAP_MAX_NUM_ENTRIES) 115 | ) 116 | bbq_inst ( 117 | .clk(user_clk), 118 | .rst(arst), 119 | .ready(heap_ready), 120 | .in_valid(heap_in_valid), 121 | .in_op_type(heap_in_op_type), 122 | .in_he_data(heap_in_data), 123 | .in_he_priority(heap_in_priority), 124 | .out_valid(heap_out_valid), 125 | .out_op_type(heap_out_op_type), 126 | .out_he_data(heap_out_he_data), 127 | .out_he_priority(heap_out_he_priority) 128 | ); 129 | 130 | endmodule 131 | -------------------------------------------------------------------------------- /hardware/bbq/tb/.gitignore: -------------------------------------------------------------------------------- 1 | transcript 2 | work/ 3 | 4 | -------------------------------------------------------------------------------- /hardware/bbq/tb/README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ## BBQ Testbench 4 | 5 | This simulation testbench contains two test suites: one for the `bbq` module, and another for the `ffs` (Find-First Set) module. To run them, first ensure that the `src` directory contains a `bbq.sv` source file (as described [here](../README.md#generating-bbqs-source-code)). Also ensure that `modelsim_ase/linux` and `modelsim_ase/linuxaloem` (or equivalent) are on your PATH. Finally, from this directory, run the following snippet: 6 | ``` 7 | for i in ffs bbq; do 8 | echo "Starting testbench for ${i}" 9 | cd ${i}; ./run_test.sh; cd ..; 10 | echo "" 11 | done 12 | ``` 13 | 14 |
15 | -------------------------------------------------------------------------------- /hardware/bbq/tb/bbq/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source ../run_common.sh 3 | 4 | run_testcase () { 5 | # Setup 6 | run_vlib 7 | run_vlog ../../src/common/bram_simple2port.v 8 | run_vlog ../../src/common/sc_fifo.v 9 | run_vlog ../../src/ffs.sv 10 | run_vlog ../../src/heap_ops.sv 11 | run_vlog ../../src/bbq.sv 12 | run_vlog +define+TEST_CASE=\"$1\" tb_bbq.sv 13 | 14 | # Run simulation 15 | display_testcase_progress $1 16 | run_vsim tb_bbq 17 | run_report $1 18 | } 19 | 20 | declare -a testcases=( 21 | 'TEST_BASIC_ENQUE' 22 | 'TEST_BASIC_DEQUE_MIN' 23 | 'TEST_BASIC_DEQUE_MAX' 24 | 'TEST_HEAP_PROPERTY' 25 | 'TEST_CAPACITY_LIMITS' 26 | 'TEST_PIPELINING_ENQUE_ENQUE' 27 | 'TEST_PIPELINING_ENQUE_DEQUE' 28 | 'TEST_PIPELINING_DEQUE_DEQUE_MIN' 29 | 'TEST_PIPELINING_DEQUE_DEQUE_MAX' 30 | # TODO(natre): Mixed pipelining 31 | 'TEST_DEQUE_FIFO' 32 | 'TEST_RESET' 33 | ) 34 | 35 | max_testcase_name_length ${testcases[@]} 36 | for c in ${testcases[@]}; do 37 | run_testcase $c 38 | done 39 | -------------------------------------------------------------------------------- /hardware/bbq/tb/ffs/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source ../run_common.sh 3 | 4 | run_testcase () { 5 | # Setup 6 | run_vlib 7 | run_vlog ../../src/ffs.sv 8 | run_vlog +define+TEST_CASE=\"$1\" tb_ffs.sv 9 | 10 | # Run simulation 11 | display_testcase_progress $1 12 | run_vsim tb_ffs 13 | run_report $1 14 | } 15 | 16 | declare -a testcases=( 17 | 'TEST_ZERO' 18 | 'TEST_LSB_SET' 19 | 'TEST_MSB_SET' 20 | 'TEST_ALL_SET' 21 | 'TEST_RANDOM_BITMAP' 22 | ) 23 | 24 | max_testcase_name_length ${testcases[@]} 25 | for c in ${testcases[@]}; do 26 | run_testcase $c 27 | done 28 | -------------------------------------------------------------------------------- /hardware/bbq/tb/ffs/tb_ffs.sv: -------------------------------------------------------------------------------- 1 | `timescale 1 ns/10 ps 2 | 3 | module tb_ffs; 4 | 5 | // Simulation parameters 6 | localparam WIDTH = 16; 7 | localparam PERIOD = 10; 8 | localparam WIDTH_LOG = $clog2(WIDTH); 9 | 10 | `ifndef TEST_CASE 11 | $error("FAIL: No test case specified"); 12 | `endif 13 | 14 | /** 15 | * List of tests: 16 | * --------------------- 17 | * TEST_ZERO 18 | * TEST_LSB_SET 19 | * TEST_MSB_SET 20 | * TEST_ALL_SET 21 | * TEST_RANDOM_BITMAP 22 | */ 23 | 24 | // Global state 25 | logic clk; 26 | logic rst; 27 | logic zero; 28 | logic [WIDTH-1:0] x; 29 | logic [WIDTH_LOG-1:0] msb; 30 | logic [WIDTH_LOG-1:0] lsb; 31 | logic [WIDTH-1:0] x_initval; 32 | 33 | initial x = 0; 34 | initial clk = 0; 35 | initial rst = 1; 36 | always #(PERIOD) clk = ~clk; 37 | 38 | if (`TEST_CASE == "TEST_ZERO") begin 39 | // Ensure zero is correctly asserted 40 | assign x_initval = 16'b0; 41 | 42 | always @(posedge clk) begin 43 | if (!rst) begin 44 | if (!zero) begin 45 | $display("FAIL %s: Zero was not asserted", `TEST_CASE); 46 | $finish; 47 | end 48 | else begin 49 | $display("PASS %s", `TEST_CASE); 50 | $finish; 51 | end 52 | end 53 | end 54 | end 55 | 56 | else if (`TEST_CASE == "TEST_LSB_SET") begin 57 | // Ensure output is correct when the LSB is set 58 | assign x_initval = 16'b0000000000000001; 59 | 60 | always @(posedge clk) begin 61 | if (!rst) begin 62 | if (zero) begin 63 | $display("FAIL %s: Zero incorrectly asserted", `TEST_CASE); 64 | $finish; 65 | end 66 | else if (lsb != 0 || msb != 0) begin 67 | $display("FAIL %s: ", `TEST_CASE, 68 | "Incorrect output. Expected (lsb=0, msb=0) ", 69 | "for x=%b, got (lsb=%0d, msb=%0d)", x, lsb, msb); 70 | $finish; 71 | end 72 | else begin 73 | $display("PASS %s", `TEST_CASE); 74 | $finish; 75 | end 76 | end 77 | end 78 | end 79 | 80 | else if (`TEST_CASE == "TEST_MSB_SET") begin 81 | // Ensure output is correct when the MSB is set 82 | assign x_initval = 16'b1000000000000000; 83 | 84 | always @(posedge clk) begin 85 | if (!rst) begin 86 | if (zero) begin 87 | $display("FAIL %s: Zero incorrectly asserted", `TEST_CASE); 88 | $finish; 89 | end 90 | else if (lsb != 15 || msb != 15) begin 91 | $display("FAIL %s: ", `TEST_CASE, 92 | "Incorrect output. Expected (lsb=15, msb=15) ", 93 | "for x=%b, got (lsb=%0d, msb=%0d)", x, lsb, msb); 94 | $finish; 95 | end 96 | else begin 97 | $display("PASS %s", `TEST_CASE); 98 | $finish; 99 | end 100 | end 101 | end 102 | end 103 | 104 | else if (`TEST_CASE == "TEST_ALL_SET") begin 105 | // Ensure output is correct when all bits are set 106 | assign x_initval = 16'b1111111111111111; 107 | 108 | always @(posedge clk) begin 109 | if (!rst) begin 110 | if (zero) begin 111 | $display("FAIL %s: Zero incorrectly asserted", `TEST_CASE); 112 | $finish; 113 | end 114 | else if (lsb != 0 || msb != 15) begin 115 | $display("FAIL %s: ", `TEST_CASE, 116 | "Incorrect output. Expected (lsb=0, msb=15) ", 117 | "for x=%b, got (lsb=%0d, msb=%0d)", x, lsb, msb); 118 | $finish; 119 | end 120 | else begin 121 | $display("PASS %s", `TEST_CASE); 122 | $finish; 123 | end 124 | end 125 | end 126 | end 127 | 128 | else if (`TEST_CASE == "TEST_RANDOM_BITMAP") begin 129 | // Ensure output is correct when random bits are set 130 | assign x_initval = 16'b0011100010101010; 131 | 132 | always @(posedge clk) begin 133 | if (!rst) begin 134 | if (zero) begin 135 | $display("FAIL %s: Zero incorrectly asserted", `TEST_CASE); 136 | $finish; 137 | end 138 | else if (lsb != 1 || msb != 13) begin 139 | $display("FAIL %s: ", `TEST_CASE, 140 | "Incorrect output. Expected (lsb=1, msb=13) ", 141 | "for x=%b, got (lsb=%0d, msb=%0d)", x, lsb, msb); 142 | $finish; 143 | end 144 | else begin 145 | $display("PASS %s", `TEST_CASE); 146 | $finish; 147 | end 148 | end 149 | end 150 | end 151 | 152 | else begin 153 | $error("FAIL: Unknown test %s", `TEST_CASE); 154 | end 155 | 156 | // Value initialization logic 157 | always @(posedge clk) begin 158 | if (rst) begin 159 | rst <= 0; 160 | x <= x_initval; 161 | end 162 | end 163 | 164 | // FFS instance 165 | ffs #( 166 | .WIDTH_LOG(WIDTH_LOG) 167 | ) 168 | ffs_instance ( 169 | .x(x), 170 | .lsb(lsb), 171 | .msb(msb), 172 | .zero(zero) 173 | ); 174 | 175 | endmodule 176 | -------------------------------------------------------------------------------- /hardware/bbq/tb/run_common.sh: -------------------------------------------------------------------------------- 1 | RED='\033[0;31m' 2 | GREEN='\033[0;32m' 3 | NC='\033[0m' # No Color 4 | 5 | run_vlib () { 6 | rm -rf work 7 | rm -f vsim.wlf 8 | 9 | if [[ -n ${DEBUG} ]]; then 10 | vlib work 11 | else 12 | vlib work > /dev/null 2>&1 13 | fi 14 | } 15 | 16 | run_vlog () { 17 | if [[ -n ${DEBUG} ]]; then 18 | vlog +define+SIM +define+DEBUG "$@" -sv 19 | else 20 | vlog +define+SIM "$@" -sv > /dev/null 2>&1 21 | fi 22 | } 23 | 24 | run_vsim () { 25 | if [[ -n ${DEBUG} ]]; then 26 | OUTPUT=$(vsim -L altera_ver -L lpm_ver -L sgate_ver \ 27 | -L altera_mf_ver -L altera_lnsim_ver \ 28 | -c -do "run -all" $1) 29 | else 30 | OUTPUT=$(vsim -L altera_ver -L lpm_ver -L sgate_ver \ 31 | -L altera_mf_ver -L altera_lnsim_ver \ 32 | -c -do "run -all" $1 | grep -e "PASS" -e "FAIL") 33 | fi 34 | } 35 | 36 | run_report () { 37 | if grep -q "FAIL" <<< ${OUTPUT} 38 | then 39 | printf "${RED}${OUTPUT}${NC}\n" 40 | elif grep -q "PASS $1" <<< ${OUTPUT} 41 | then 42 | if [[ -n ${DEBUG} ]]; then 43 | printf "${GREEN}${OUTPUT}${NC}\n" 44 | else 45 | printf "${GREEN}PASS${NC}\n" 46 | fi 47 | else 48 | printf "${RED}Test not run\n${OUTPUT}${NC}\n" 49 | fi 50 | } 51 | 52 | max_testcase_name_length() { 53 | MAX_LENGTH=0 54 | local array=("$@") 55 | for testcase in ${array[@]}; do 56 | if ((${#testcase} > ${MAX_LENGTH})); 57 | then 58 | MAX_LENGTH=${#testcase} 59 | fi 60 | done 61 | } 62 | 63 | display_testcase_progress() { 64 | local testcase=$1 65 | local testcase_name_length=${#testcase} 66 | 67 | printf "Running ${testcase}... " 68 | padding=$((MAX_LENGTH - testcase_name_length)) 69 | printf '%*s' ${padding} "" 70 | } 71 | -------------------------------------------------------------------------------- /hardware/bmw/ip/.gitignore: -------------------------------------------------------------------------------- 1 | .qsys_edit 2 | *.ip 3 | 4 | my_pll 5 | 6 | # Will be generated from template. 7 | my_pll.tcl 8 | -------------------------------------------------------------------------------- /hardware/bmw/ip/my_pll.tcl.template: -------------------------------------------------------------------------------- 1 | package require -exact qsys 18.0 2 | 3 | # create the system "my_pll" 4 | proc do_create_my_pll {} { 5 | set out_freq {{{out_freq}}} 6 | 7 | # create the system 8 | create_system my_pll 9 | set_project_property DEVICE {1SM21BHU2F53E1VG} 10 | set_project_property DEVICE_FAMILY {Stratix 10} 11 | set_project_property HIDE_FROM_IP_CATALOG {true} 12 | set_use_testbench_naming_pattern 0 {} 13 | 14 | # add the components 15 | add_instance iopll_0 altera_iopll 19.3.0 16 | set_instance_parameter_value iopll_0 {gui_active_clk} {0} 17 | set_instance_parameter_value iopll_0 {gui_c_cnt_in_src0} {c_m_cnt_in_src_ph_mux_clk} 18 | set_instance_parameter_value iopll_0 {gui_c_cnt_in_src1} {c_m_cnt_in_src_ph_mux_clk} 19 | set_instance_parameter_value iopll_0 {gui_c_cnt_in_src2} {c_m_cnt_in_src_ph_mux_clk} 20 | set_instance_parameter_value iopll_0 {gui_c_cnt_in_src3} {c_m_cnt_in_src_ph_mux_clk} 21 | set_instance_parameter_value iopll_0 {gui_c_cnt_in_src4} {c_m_cnt_in_src_ph_mux_clk} 22 | set_instance_parameter_value iopll_0 {gui_c_cnt_in_src5} {c_m_cnt_in_src_ph_mux_clk} 23 | set_instance_parameter_value iopll_0 {gui_c_cnt_in_src6} {c_m_cnt_in_src_ph_mux_clk} 24 | set_instance_parameter_value iopll_0 {gui_c_cnt_in_src7} {c_m_cnt_in_src_ph_mux_clk} 25 | set_instance_parameter_value iopll_0 {gui_c_cnt_in_src8} {c_m_cnt_in_src_ph_mux_clk} 26 | set_instance_parameter_value iopll_0 {gui_cal_code_hex_file} {iossm.hex} 27 | set_instance_parameter_value iopll_0 {gui_cal_converge} {0} 28 | set_instance_parameter_value iopll_0 {gui_cal_error} {cal_clean} 29 | set_instance_parameter_value iopll_0 {gui_cascade_counter0} {0} 30 | set_instance_parameter_value iopll_0 {gui_cascade_counter1} {0} 31 | set_instance_parameter_value iopll_0 {gui_cascade_counter10} {0} 32 | set_instance_parameter_value iopll_0 {gui_cascade_counter11} {0} 33 | set_instance_parameter_value iopll_0 {gui_cascade_counter12} {0} 34 | set_instance_parameter_value iopll_0 {gui_cascade_counter13} {0} 35 | set_instance_parameter_value iopll_0 {gui_cascade_counter14} {0} 36 | set_instance_parameter_value iopll_0 {gui_cascade_counter15} {0} 37 | set_instance_parameter_value iopll_0 {gui_cascade_counter16} {0} 38 | set_instance_parameter_value iopll_0 {gui_cascade_counter17} {0} 39 | set_instance_parameter_value iopll_0 {gui_cascade_counter2} {0} 40 | set_instance_parameter_value iopll_0 {gui_cascade_counter3} {0} 41 | set_instance_parameter_value iopll_0 {gui_cascade_counter4} {0} 42 | set_instance_parameter_value iopll_0 {gui_cascade_counter5} {0} 43 | set_instance_parameter_value iopll_0 {gui_cascade_counter6} {0} 44 | set_instance_parameter_value iopll_0 {gui_cascade_counter7} {0} 45 | set_instance_parameter_value iopll_0 {gui_cascade_counter8} {0} 46 | set_instance_parameter_value iopll_0 {gui_cascade_counter9} {0} 47 | set_instance_parameter_value iopll_0 {gui_cascade_outclk_index} {0} 48 | set_instance_parameter_value iopll_0 {gui_clk_bad} {0} 49 | set_instance_parameter_value iopll_0 {gui_clock_name_global} {0} 50 | set_instance_parameter_value iopll_0 {gui_clock_name_string0} {outclk0} 51 | set_instance_parameter_value iopll_0 {gui_clock_name_string1} {outclk1} 52 | set_instance_parameter_value iopll_0 {gui_clock_name_string10} {outclk10} 53 | set_instance_parameter_value iopll_0 {gui_clock_name_string11} {outclk11} 54 | set_instance_parameter_value iopll_0 {gui_clock_name_string12} {outclk12} 55 | set_instance_parameter_value iopll_0 {gui_clock_name_string13} {outclk13} 56 | set_instance_parameter_value iopll_0 {gui_clock_name_string14} {outclk14} 57 | set_instance_parameter_value iopll_0 {gui_clock_name_string15} {outclk15} 58 | set_instance_parameter_value iopll_0 {gui_clock_name_string16} {outclk16} 59 | set_instance_parameter_value iopll_0 {gui_clock_name_string17} {outclk17} 60 | set_instance_parameter_value iopll_0 {gui_clock_name_string2} {outclk2} 61 | set_instance_parameter_value iopll_0 {gui_clock_name_string3} {outclk3} 62 | set_instance_parameter_value iopll_0 {gui_clock_name_string4} {outclk4} 63 | set_instance_parameter_value iopll_0 {gui_clock_name_string5} {outclk5} 64 | set_instance_parameter_value iopll_0 {gui_clock_name_string6} {outclk6} 65 | set_instance_parameter_value iopll_0 {gui_clock_name_string7} {outclk7} 66 | set_instance_parameter_value iopll_0 {gui_clock_name_string8} {outclk8} 67 | set_instance_parameter_value iopll_0 {gui_clock_name_string9} {outclk9} 68 | set_instance_parameter_value iopll_0 {gui_clock_to_compensate} {0} 69 | set_instance_parameter_value iopll_0 {gui_debug_mode} {0} 70 | set_instance_parameter_value iopll_0 {gui_divide_factor_c0} {6} 71 | set_instance_parameter_value iopll_0 {gui_divide_factor_c1} {6} 72 | set_instance_parameter_value iopll_0 {gui_divide_factor_c10} {6} 73 | set_instance_parameter_value iopll_0 {gui_divide_factor_c11} {6} 74 | set_instance_parameter_value iopll_0 {gui_divide_factor_c12} {6} 75 | set_instance_parameter_value iopll_0 {gui_divide_factor_c13} {6} 76 | set_instance_parameter_value iopll_0 {gui_divide_factor_c14} {6} 77 | set_instance_parameter_value iopll_0 {gui_divide_factor_c15} {6} 78 | set_instance_parameter_value iopll_0 {gui_divide_factor_c16} {6} 79 | set_instance_parameter_value iopll_0 {gui_divide_factor_c17} {6} 80 | set_instance_parameter_value iopll_0 {gui_divide_factor_c2} {6} 81 | set_instance_parameter_value iopll_0 {gui_divide_factor_c3} {6} 82 | set_instance_parameter_value iopll_0 {gui_divide_factor_c4} {6} 83 | set_instance_parameter_value iopll_0 {gui_divide_factor_c5} {6} 84 | set_instance_parameter_value iopll_0 {gui_divide_factor_c6} {6} 85 | set_instance_parameter_value iopll_0 {gui_divide_factor_c7} {6} 86 | set_instance_parameter_value iopll_0 {gui_divide_factor_c8} {6} 87 | set_instance_parameter_value iopll_0 {gui_divide_factor_c9} {6} 88 | set_instance_parameter_value iopll_0 {gui_divide_factor_n} {1} 89 | set_instance_parameter_value iopll_0 {gui_dps_cntr} {C0} 90 | set_instance_parameter_value iopll_0 {gui_dps_dir} {Positive} 91 | set_instance_parameter_value iopll_0 {gui_dps_num} {1} 92 | set_instance_parameter_value iopll_0 {gui_dsm_out_sel} {1st_order} 93 | set_instance_parameter_value iopll_0 {gui_duty_cycle0} {50.0} 94 | set_instance_parameter_value iopll_0 {gui_duty_cycle1} {50.0} 95 | set_instance_parameter_value iopll_0 {gui_duty_cycle10} {50.0} 96 | set_instance_parameter_value iopll_0 {gui_duty_cycle11} {50.0} 97 | set_instance_parameter_value iopll_0 {gui_duty_cycle12} {50.0} 98 | set_instance_parameter_value iopll_0 {gui_duty_cycle13} {50.0} 99 | set_instance_parameter_value iopll_0 {gui_duty_cycle14} {50.0} 100 | set_instance_parameter_value iopll_0 {gui_duty_cycle15} {50.0} 101 | set_instance_parameter_value iopll_0 {gui_duty_cycle16} {50.0} 102 | set_instance_parameter_value iopll_0 {gui_duty_cycle17} {50.0} 103 | set_instance_parameter_value iopll_0 {gui_duty_cycle2} {50.0} 104 | set_instance_parameter_value iopll_0 {gui_duty_cycle3} {50.0} 105 | set_instance_parameter_value iopll_0 {gui_duty_cycle4} {50.0} 106 | set_instance_parameter_value iopll_0 {gui_duty_cycle5} {50.0} 107 | set_instance_parameter_value iopll_0 {gui_duty_cycle6} {50.0} 108 | set_instance_parameter_value iopll_0 {gui_duty_cycle7} {50.0} 109 | set_instance_parameter_value iopll_0 {gui_duty_cycle8} {50.0} 110 | set_instance_parameter_value iopll_0 {gui_duty_cycle9} {50.0} 111 | set_instance_parameter_value iopll_0 {gui_en_adv_params} {0} 112 | set_instance_parameter_value iopll_0 {gui_en_dps_ports} {0} 113 | set_instance_parameter_value iopll_0 {gui_en_extclkout_ports} {0} 114 | set_instance_parameter_value iopll_0 {gui_en_lvds_ports} {Disabled} 115 | set_instance_parameter_value iopll_0 {gui_en_phout_ports} {0} 116 | set_instance_parameter_value iopll_0 {gui_en_reconf} {0} 117 | set_instance_parameter_value iopll_0 {gui_enable_cascade_in} {0} 118 | set_instance_parameter_value iopll_0 {gui_enable_cascade_out} {0} 119 | set_instance_parameter_value iopll_0 {gui_enable_mif_dps} {0} 120 | set_instance_parameter_value iopll_0 {gui_enable_output_counter_cascading} {0} 121 | set_instance_parameter_value iopll_0 {gui_enable_permit_cal} {0} 122 | set_instance_parameter_value iopll_0 {gui_existing_mif_file_path} {~/pll.mif} 123 | set_instance_parameter_value iopll_0 {gui_extclkout_0_source} {C0} 124 | set_instance_parameter_value iopll_0 {gui_extclkout_1_source} {C0} 125 | set_instance_parameter_value iopll_0 {gui_feedback_clock} {Global Clock} 126 | set_instance_parameter_value iopll_0 {gui_fix_vco_frequency} {0} 127 | set_instance_parameter_value iopll_0 {gui_fixed_vco_frequency} {600.0} 128 | set_instance_parameter_value iopll_0 {gui_fixed_vco_frequency_ps} {1667.0} 129 | set_instance_parameter_value iopll_0 {gui_frac_multiply_factor} {1.0} 130 | set_instance_parameter_value iopll_0 {gui_fractional_cout} {32} 131 | set_instance_parameter_value iopll_0 {gui_include_iossm} {0} 132 | set_instance_parameter_value iopll_0 {gui_location_type} {I/O Bank} 133 | set_instance_parameter_value iopll_0 {gui_lock_setting} {Low Lock Time} 134 | set_instance_parameter_value iopll_0 {gui_mif_config_name} {unnamed} 135 | set_instance_parameter_value iopll_0 {gui_mif_gen_options} {Generate New MIF File} 136 | set_instance_parameter_value iopll_0 {gui_multiply_factor} {15} 137 | set_instance_parameter_value iopll_0 {gui_new_mif_file_path} {~/pll.mif} 138 | set_instance_parameter_value iopll_0 {gui_number_of_clocks} {1} 139 | set_instance_parameter_value iopll_0 {gui_operation_mode} {direct} 140 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency0} $out_freq 141 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency1} {500.0} 142 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency10} {100.0} 143 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency11} {100.0} 144 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency12} {100.0} 145 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency13} {100.0} 146 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency14} {100.0} 147 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency15} {100.0} 148 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency16} {100.0} 149 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency17} {100.0} 150 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency2} {100.0} 151 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency3} {100.0} 152 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency4} {100.0} 153 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency5} {100.0} 154 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency6} {100.0} 155 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency7} {100.0} 156 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency8} {100.0} 157 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency9} {100.0} 158 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps0} {6666.667} 159 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps1} {2000.0} 160 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps10} {10000.0} 161 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps11} {10000.0} 162 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps12} {10000.0} 163 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps13} {10000.0} 164 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps14} {10000.0} 165 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps15} {10000.0} 166 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps16} {10000.0} 167 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps17} {10000.0} 168 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps2} {10000.0} 169 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps3} {10000.0} 170 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps4} {10000.0} 171 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps5} {10000.0} 172 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps6} {10000.0} 173 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps7} {10000.0} 174 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps8} {10000.0} 175 | set_instance_parameter_value iopll_0 {gui_output_clock_frequency_ps9} {10000.0} 176 | set_instance_parameter_value iopll_0 {gui_parameter_table_hex_file} {seq_params_sim.hex} 177 | set_instance_parameter_value iopll_0 {gui_phase_shift0} {0.0} 178 | set_instance_parameter_value iopll_0 {gui_phase_shift1} {0.0} 179 | set_instance_parameter_value iopll_0 {gui_phase_shift10} {0.0} 180 | set_instance_parameter_value iopll_0 {gui_phase_shift11} {0.0} 181 | set_instance_parameter_value iopll_0 {gui_phase_shift12} {0.0} 182 | set_instance_parameter_value iopll_0 {gui_phase_shift13} {0.0} 183 | set_instance_parameter_value iopll_0 {gui_phase_shift14} {0.0} 184 | set_instance_parameter_value iopll_0 {gui_phase_shift15} {0.0} 185 | set_instance_parameter_value iopll_0 {gui_phase_shift16} {0.0} 186 | set_instance_parameter_value iopll_0 {gui_phase_shift17} {0.0} 187 | set_instance_parameter_value iopll_0 {gui_phase_shift2} {0.0} 188 | set_instance_parameter_value iopll_0 {gui_phase_shift3} {0.0} 189 | set_instance_parameter_value iopll_0 {gui_phase_shift4} {0.0} 190 | set_instance_parameter_value iopll_0 {gui_phase_shift5} {0.0} 191 | set_instance_parameter_value iopll_0 {gui_phase_shift6} {0.0} 192 | set_instance_parameter_value iopll_0 {gui_phase_shift7} {0.0} 193 | set_instance_parameter_value iopll_0 {gui_phase_shift8} {0.0} 194 | set_instance_parameter_value iopll_0 {gui_phase_shift9} {0.0} 195 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg0} {0.0} 196 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg1} {0.0} 197 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg10} {0.0} 198 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg11} {0.0} 199 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg12} {0.0} 200 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg13} {0.0} 201 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg14} {0.0} 202 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg15} {0.0} 203 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg16} {0.0} 204 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg17} {0.0} 205 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg2} {0.0} 206 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg3} {0.0} 207 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg4} {0.0} 208 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg5} {0.0} 209 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg6} {0.0} 210 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg7} {0.0} 211 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg8} {0.0} 212 | set_instance_parameter_value iopll_0 {gui_phase_shift_deg9} {0.0} 213 | set_instance_parameter_value iopll_0 {gui_phout_division} {1} 214 | set_instance_parameter_value iopll_0 {gui_pll_auto_reset} {0} 215 | set_instance_parameter_value iopll_0 {gui_pll_bandwidth_preset} {Low} 216 | set_instance_parameter_value iopll_0 {gui_pll_cal_done} {0} 217 | set_instance_parameter_value iopll_0 {gui_pll_cascading_mode} {adjpllin} 218 | set_instance_parameter_value iopll_0 {gui_pll_freqcal_en} {1} 219 | set_instance_parameter_value iopll_0 {gui_pll_freqcal_req_flag} {1} 220 | set_instance_parameter_value iopll_0 {gui_pll_m_cnt_in_src} {c_m_cnt_in_src_ph_mux_clk} 221 | set_instance_parameter_value iopll_0 {gui_pll_mode} {Integer-N PLL} 222 | set_instance_parameter_value iopll_0 {gui_pll_tclk_mux_en} {0} 223 | set_instance_parameter_value iopll_0 {gui_pll_tclk_sel} {pll_tclk_m_src} 224 | set_instance_parameter_value iopll_0 {gui_pll_type} {S10_Simple} 225 | set_instance_parameter_value iopll_0 {gui_pll_vco_freq_band_0} {pll_freq_clk0_disabled} 226 | set_instance_parameter_value iopll_0 {gui_pll_vco_freq_band_1} {pll_freq_clk1_disabled} 227 | set_instance_parameter_value iopll_0 {gui_prot_mode} {UNUSED} 228 | set_instance_parameter_value iopll_0 {gui_ps_units0} {ps} 229 | set_instance_parameter_value iopll_0 {gui_ps_units1} {ps} 230 | set_instance_parameter_value iopll_0 {gui_ps_units10} {ps} 231 | set_instance_parameter_value iopll_0 {gui_ps_units11} {ps} 232 | set_instance_parameter_value iopll_0 {gui_ps_units12} {ps} 233 | set_instance_parameter_value iopll_0 {gui_ps_units13} {ps} 234 | set_instance_parameter_value iopll_0 {gui_ps_units14} {ps} 235 | set_instance_parameter_value iopll_0 {gui_ps_units15} {ps} 236 | set_instance_parameter_value iopll_0 {gui_ps_units16} {ps} 237 | set_instance_parameter_value iopll_0 {gui_ps_units17} {ps} 238 | set_instance_parameter_value iopll_0 {gui_ps_units2} {ps} 239 | set_instance_parameter_value iopll_0 {gui_ps_units3} {ps} 240 | set_instance_parameter_value iopll_0 {gui_ps_units4} {ps} 241 | set_instance_parameter_value iopll_0 {gui_ps_units5} {ps} 242 | set_instance_parameter_value iopll_0 {gui_ps_units6} {ps} 243 | set_instance_parameter_value iopll_0 {gui_ps_units7} {ps} 244 | set_instance_parameter_value iopll_0 {gui_ps_units8} {ps} 245 | set_instance_parameter_value iopll_0 {gui_ps_units9} {ps} 246 | set_instance_parameter_value iopll_0 {gui_refclk1_frequency} {100.0} 247 | set_instance_parameter_value iopll_0 {gui_refclk_might_change} {0} 248 | set_instance_parameter_value iopll_0 {gui_refclk_switch} {0} 249 | set_instance_parameter_value iopll_0 {gui_reference_clock_frequency} {100.0} 250 | set_instance_parameter_value iopll_0 {gui_reference_clock_frequency_ps} {10000.0} 251 | set_instance_parameter_value iopll_0 {gui_skip_sdc_generation} {0} 252 | set_instance_parameter_value iopll_0 {gui_switchover_delay} {0} 253 | set_instance_parameter_value iopll_0 {gui_switchover_mode} {Automatic Switchover} 254 | set_instance_parameter_value iopll_0 {gui_use_NDFB_modes} {0} 255 | set_instance_parameter_value iopll_0 {gui_use_coreclk} {0} 256 | set_instance_parameter_value iopll_0 {gui_use_locked} {1} 257 | set_instance_parameter_value iopll_0 {gui_use_logical} {0} 258 | set_instance_parameter_value iopll_0 {gui_usr_device_speed_grade} {1} 259 | set_instance_parameter_value iopll_0 {gui_vco_frequency} {1500.0} 260 | set_instance_parameter_value iopll_0 {hp_qsys_scripting_mode} {0} 261 | set_instance_property iopll_0 AUTO_EXPORT true 262 | 263 | # add wirelevel expressions 264 | 265 | # add the exports 266 | set_interface_property reset EXPORT_OF iopll_0.reset 267 | set_interface_property refclk EXPORT_OF iopll_0.refclk 268 | set_interface_property locked EXPORT_OF iopll_0.locked 269 | set_interface_property outclk0 EXPORT_OF iopll_0.outclk0 270 | 271 | # set the the module properties 272 | set_module_property BONUS_DATA { 273 | 274 | 275 | 276 | 277 | 278 | } 279 | set_module_property FILE {my_pll.ip} 280 | set_module_property GENERATION_ID {0x00000000} 281 | set_module_property NAME {my_pll} 282 | 283 | # save the system 284 | sync_sysinfo_parameters 285 | save_system my_pll 286 | } 287 | 288 | # create all the systems, from bottom up 289 | do_create_my_pll 290 | -------------------------------------------------------------------------------- /hardware/bmw/quartus/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !*.qpf 4 | !*.qsf 5 | !*.sdc 6 | -------------------------------------------------------------------------------- /hardware/bmw/quartus/bmw.qpf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------- # 2 | # 3 | # Copyright (C) 2019 Intel Corporation. All rights reserved. 4 | # Your use of Intel Corporation's design tools, logic functions 5 | # and other software and tools, and any partner logic 6 | # functions, and any output files from any of the foregoing 7 | # (including device programming or simulation files), and any 8 | # associated documentation or information are expressly subject 9 | # to the terms and conditions of the Intel Program License 10 | # Subscription Agreement, the Intel Quartus Prime License Agreement, 11 | # the Intel FPGA IP License Agreement, or other applicable license 12 | # agreement, including, without limitation, that your use is for 13 | # the sole purpose of programming logic devices manufactured by 14 | # Intel and sold by Intel or its authorized distributors. Please 15 | # refer to the applicable agreement for further details, at 16 | # https://fpgasoftware.intel.com/eula. 17 | # 18 | # -------------------------------------------------------------------------- # 19 | # 20 | # Quartus Prime 21 | # Version 19.3.0 Build 222 09/23/2019 SC Pro Edition 22 | # Date created = 18:26:26 January 19, 2023 23 | # 24 | # -------------------------------------------------------------------------- # 25 | 26 | QUARTUS_VERSION = "19.3" 27 | DATE = "18:26:26 January 19, 2023" 28 | 29 | # Revisions 30 | 31 | PROJECT_REVISION = "bmw" 32 | -------------------------------------------------------------------------------- /hardware/bmw/quartus/bmw.qsf: -------------------------------------------------------------------------------- 1 | 2 | # Project-Wide Assignments 3 | # ======================== 4 | set_global_assignment -name ORIGINAL_QUARTUS_VERSION 19.3.0 5 | set_global_assignment -name PROJECT_CREATION_TIME_DATE "13:24:03 JANUARY 20, 2023" 6 | set_global_assignment -name LAST_QUARTUS_VERSION "19.3.0 Pro Edition" 7 | set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files 8 | 9 | # Pin & Location Assignments 10 | # ========================== 11 | set_location_assignment PIN_BL14 -to cpu_resetn 12 | set_location_assignment PIN_AT13 -to in_clk100 13 | set_location_assignment PIN_AU13 -to "in_clk100(n)" 14 | set_location_assignment PIN_BG12 -to bmw_out 15 | 16 | # Classic Timing Assignments 17 | # ========================== 18 | set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 19 | set_global_assignment -name MAX_CORE_JUNCTION_TEMP 100 20 | set_global_assignment -name TIMING_ANALYZER_MULTICORNER_ANALYSIS ON 21 | 22 | # Analysis & Synthesis Assignments 23 | # ================================ 24 | set_global_assignment -name TOP_LEVEL_ENTITY top 25 | set_global_assignment -name FAMILY "Stratix 10" 26 | set_global_assignment -name SEARCH_PATH ../src/common 27 | 28 | # Fitter Assignments 29 | # ================== 30 | set_global_assignment -name DEVICE 1SM21BHU2F53E1VG 31 | set_instance_assignment -name IO_STANDARD LVDS -to in_clk100 -entity top 32 | set_instance_assignment -name IO_STANDARD LVDS -to "in_clk100(n)" -entity top 33 | set_instance_assignment -name IO_STANDARD "1.8 V" -to cpu_resetn -entity top 34 | set_instance_assignment -name IO_STANDARD "1.8 V" -to bmw_out -entity top 35 | 36 | # Ordering Sensitive Assignments 37 | # ============================== 38 | 39 | set_global_assignment -name OPTIMIZATION_MODE "SUPERIOR PERFORMANCE WITH MAXIMUM PLACEMENT EFFORT" 40 | set_global_assignment -name ENABLE_INTERMEDIATE_SNAPSHOTS ON 41 | set_global_assignment -name FAST_PRESERVE OFF -entity top 42 | 43 | set_global_assignment -name VERILOG_CONSTANT_LOOP_LIMIT 1000000 44 | 45 | set_global_assignment -name SYSTEMVERILOG_FILE ../src/top.sv 46 | set_global_assignment -name SYSTEMVERILOG_FILE ../src/bmw_sram_top.sv 47 | set_global_assignment -name SYSTEMVERILOG_FILE ../src/bmw_sram.sv 48 | set_global_assignment -name SYSTEMVERILOG_FILE ../src/infer_sdram.sv 49 | set_global_assignment -name VERILOG_FILE ../src/common/bram_simple2port.v 50 | set_global_assignment -name IP_FILE ../ip/my_pll.ip 51 | 52 | set_global_assignment -name SDC_ENTITY_FILE bmw.sdc -entity top 53 | -------------------------------------------------------------------------------- /hardware/bmw/quartus/bmw.sdc: -------------------------------------------------------------------------------- 1 | 2 | # create_clock -period 10.00 -name in_clk100 [get_ports in_clk100] 3 | 4 | # Not needed for Stratix 10 5 | # derive_pll_clocks 6 | 7 | derive_clock_uncertainty 8 | -------------------------------------------------------------------------------- /hardware/bmw/scripts/bisect_fmax.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Usage: PRIORITY_BITS=XXX LEVELS=YYY \ 4 | # [MIN_FREQ=AAA] [MAX_FREQ=BBB] [PRECISION=CCC] \ 5 | # ./bisect_fmax.sh [seed1] [seed2] ... 6 | # 7 | # Given a design configuration, performs a bisection search to 8 | # find the target Fmax that closes timing. Tries as many seeds 9 | # as specified, using a single process for synthesis. 10 | # 11 | PROJECT_NAME="bmw" 12 | 13 | CUR_DIR=$(pwd) 14 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 15 | PROJECT_DIR="${SCRIPT_DIR}/.." 16 | 17 | if [ $# -eq 0 ]; then 18 | echo "Must specify seeds." 19 | exit 1 20 | fi 21 | 22 | SEEDS=$@ 23 | 24 | # If MIN_FREQ is not defined, use the default. 25 | if [ -z ${MIN_FREQ} ]; then 26 | MIN_FREQ=50 27 | echo "MIN_FREQ is not defined, using ${MIN_FREQ} MHz." 28 | fi 29 | 30 | # If MAX_FREQ is not defined, use the default. 31 | if [ -z ${MAX_FREQ} ]; then 32 | MAX_FREQ=300 33 | echo "MAX_FREQ is not defined, using ${MAX_FREQ} MHz." 34 | fi 35 | 36 | # If PRECISION is not defined, use the default. 37 | if [ -z ${PRECISION} ]; then 38 | PRECISION=3 39 | echo "PRECISION is not defined, using ${PRECISION} MHz." 40 | 41 | elif [ ${PRECISION} -lt 1 ]; then 42 | echo "PRECISION must be greater than 0." 43 | exit 1 44 | fi 45 | 46 | # Outputs 47 | best_fmax=0 48 | best_seed=-1 49 | output_dir="${PROJECT_DIR}/quartus/bisect_fmax" 50 | 51 | # Report files 52 | timing_report="${PROJECT_DIR}/quartus/output_files/${PROJECT_NAME}.sta.rpt" 53 | fitter_report="${PROJECT_DIR}/quartus/output_files/${PROJECT_NAME}.fit.summary" 54 | 55 | # Setup 56 | rm -rf ${output_dir} 57 | rm -f ${timing_report} 58 | rm -f ${fitter_report} 59 | mkdir -p ${output_dir} 60 | 61 | # Housekeeping 62 | fmax_lower=0 63 | fmax_upper=${MAX_FREQ} 64 | current_freq=$(( ${MAX_FREQ} / 2 )) 65 | 66 | while true 67 | do 68 | # Setup for the next iteration 69 | rm -rf ${PROJECT_DIR}/quartus/output_files 70 | 71 | # Print start message and run the setup script for the current fmax 72 | echo "Attempting synthesis with target fmax ${current_freq} MHz" 73 | ${PROJECT_DIR}/setup.sh ${current_freq} 74 | if [ $? -ne 0 ]; then 75 | echo "Setup script failed for ${current_freq} MHz, exiting." 76 | exit 1 77 | fi 78 | 79 | timing_success=0 80 | for seed in ${SEEDS[@]}; do 81 | 82 | # First, run synthesis for this seed (2-hour timeout) 83 | timeout -k 60 2h ${SCRIPT_DIR}/synthesize.sh ${seed} 84 | retcode=$? 85 | if [ ${retcode} -eq 124 ]; then 86 | echo "Synthesis script timed out for ${current_freq} MHz and seed ${seed}, skipping." 87 | continue 88 | elif [ ${retcode} -ne 0 ]; then 89 | echo "Synthesis script failed for ${current_freq} MHz and seed ${seed}, skipping." 90 | continue 91 | fi 92 | # If the timing report is clear, declare success 93 | if [ -f "${timing_report}" ]; then 94 | timing_success=1 95 | if grep -qcm1 "Timing requirements not met" ${timing_report}; then 96 | timing_success=0; 97 | fi 98 | fi 99 | # Found a seed that works, stop early 100 | if [ ${timing_success} -eq 1 ]; then 101 | best_fmax=${current_freq} 102 | best_seed=${seed} 103 | 104 | # Copy the reports to the output directory 105 | cp ${timing_report} ${output_dir}/ 106 | cp ${fitter_report} ${output_dir}/ 107 | break 108 | fi 109 | done 110 | 111 | if [ ${timing_success} -eq 1 ]; then 112 | # Found a new lower bound 113 | fmax_lower=${current_freq} 114 | else 115 | # Synthesis failed, found a new upper bound 116 | fmax_upper=${current_freq} 117 | fi 118 | # Update frequency estimate 119 | current_freq=$(( (${fmax_lower} + ${fmax_upper}) / 2 )) 120 | 121 | if (( ${current_freq} < ${MIN_FREQ} )); then 122 | echo "Warning: bisect_fmax reached MIN_FREQ, design may not be synthesizable." 123 | break 124 | 125 | elif (( ${fmax_upper} - ${fmax_lower} <= ${PRECISION} )); then 126 | break # Found the frequency 127 | fi 128 | done 129 | 130 | if [ ${best_fmax} -ne 0 ]; then 131 | echo "Best fmax: ${best_fmax}, seed: ${best_seed}" | tee ${output_dir}/fmax.txt 132 | fi 133 | 134 | # Announce that it is over. 135 | tput bel 136 | -------------------------------------------------------------------------------- /hardware/bmw/scripts/sweep_bisect_fmax.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Usage: [MIN_FREQ=AAA] [MAX_FREQ=BBB] [PRECISION=CCC] \ 4 | # [NUM_PROCS=DDD] ./sweep_bisect_fmax.sh [seed1] [seed2] ... 5 | # 6 | PROJECT_NAME="bmw" 7 | 8 | CUR_DIR=$(pwd) 9 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 10 | PROJECT_DIR="${SCRIPT_DIR}/.." 11 | 12 | if [ $# -eq 0 ]; then 13 | echo "Must specify seeds." 14 | exit 1 15 | fi 16 | 17 | # If NUM_PROCS is not defined, use the default. 18 | if [ -z ${NUM_PROCS} ]; then 19 | NUM_PROCS=8 20 | echo "NUM_PROCS is not defined, using ${NUM_PROCS}." 21 | fi 22 | 23 | # Exit when error occurs. 24 | set -e 25 | trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG 26 | trap 'echo "\"${last_command}\" command exited with code $?."' EXIT 27 | 28 | rm -rf ${PROJECT_DIR}/quartus/sweep_bisect_fmax 29 | mkdir -p ${PROJECT_DIR}/quartus/sweep_bisect_fmax 30 | 31 | tmp_dir="/tmp/${PROJECT_NAME}" 32 | rm -rf ${tmp_dir} 33 | cp -r ${PROJECT_DIR} ${tmp_dir} 34 | rm -rf ${tmp_dir}/quartus/sweep_bisect_fmax 35 | 36 | jobs="sweep_bisect_fmax_jobs.txt" 37 | rm -f ${jobs} 38 | 39 | # Number of priority bits 40 | for p in 8 9 12 15 41 | do 42 | # Number of levels 43 | for l in 5 6 7 8 9 44 | do 45 | midfix="p${p}_l${l}" 46 | 47 | dst_dir=${PROJECT_DIR}/quartus/sweep_bisect_fmax/${midfix} 48 | rm -rf ${dst_dir} 49 | cp -r ${tmp_dir} ${dst_dir} 50 | 51 | echo "PRIORITY_BITS=${p} LEVELS=${l}"\ 52 | "${dst_dir}/scripts/bisect_fmax.sh $@ | tee"\ 53 | "${dst_dir}/bisect_fmax_log.txt" >> ${jobs} 54 | done 55 | done 56 | 57 | rm -rf ${tmp_dir} 58 | parallel -j${NUM_PROCS} < ${jobs} 59 | rm -f ${jobs} 60 | -------------------------------------------------------------------------------- /hardware/bmw/scripts/synthesize.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Usage: PRIORITY_BITS=XXX LEVELS=YYY ./synthesize.sh [SEED] 4 | # 5 | PROJECT_NAME="bmw" 6 | 7 | CUR_DIR=$(pwd) 8 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 9 | PROJECT_DIR="${SCRIPT_DIR}/.." 10 | 11 | SEED=${1:-"0"} 12 | 13 | # If PRIORITY_BITS is not defined, exit. 14 | if [ -z ${PRIORITY_BITS} ]; then 15 | echo "PRIORITY_BITS is not defined. Exiting." 16 | exit 1 17 | fi 18 | 19 | # If LEVELS is not defined, exit. 20 | if [ -z ${LEVELS} ]; then 21 | echo "LEVELS is not defined. Exiting." 22 | exit 1 23 | fi 24 | 25 | echo "SEED=${SEED}" 26 | 27 | PROJECT_OUTPUT_DIRECTORY="output_files" 28 | QUARTUS_STA_LOG_FILE="quartus_sta.log" 29 | 30 | # Exit when error occurs. 31 | set -e 32 | trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG 33 | trap 'echo "\"${last_command}\" command exited with code $?."' EXIT 34 | 35 | cd ${PROJECT_DIR}/quartus 36 | 37 | start=$(date +%s.%N) 38 | # Generate IPs if necessary. 39 | quartus_ipgenerate ${PROJECT_NAME} 40 | 41 | quartus_syn --read_settings_files=on --write_settings_files=off ${PROJECT_NAME} \ 42 | -c ${PROJECT_NAME} --set=VERILOG_MACRO=LEVELS=${LEVELS} \ 43 | --set=VERILOG_MACRO=PRIORITY_BITS=${PRIORITY_BITS} 44 | 45 | quartus_fit --read_settings_files=on --write_settings_files=off ${PROJECT_NAME} \ 46 | -c ${PROJECT_NAME} --seed=${SEED} 47 | 48 | # We use script instead of tee to capture the output and display it while 49 | # preserving colors. 50 | script --flush --quiet --return ${QUARTUS_STA_LOG_FILE} \ 51 | --command "quartus_sta ${PROJECT_NAME} -c ${PROJECT_NAME} --mode=finalize" 52 | 53 | quartus_asm --read_settings_files=on --write_settings_files=off ${PROJECT_NAME} \ 54 | -c ${PROJECT_NAME} 55 | 56 | dur=$(echo "$(date +%s.%N) - ${start}" | bc) 57 | printf "Synthesis completed in %.6f seconds\n" ${dur} 58 | 59 | # Show Fmax. 60 | grep -C2 "; Fmax" "${PROJECT_OUTPUT_DIRECTORY}/${PROJECT_NAME}.sta.rpt" 61 | 62 | if grep -q "Timing requirements not met" ${QUARTUS_STA_LOG_FILE}; then 63 | # Show slack. 64 | grep -C 10 "Timing requirements not met" ${QUARTUS_STA_LOG_FILE} 65 | RED='\033[0;31m' 66 | NC='\033[0m' # No Color. 67 | echo -e "${RED}===========================${NC}" 68 | echo -e "${RED}Timing requirements not met${NC}" 69 | echo -e "${RED}===========================${NC}" 70 | fi 71 | 72 | echo "Done (L=${LEVELS}, P=${PRIORITY_BITS}, seed=${SEED})" 73 | 74 | # Announce that it is over. 75 | tput bel 76 | -------------------------------------------------------------------------------- /hardware/bmw/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Usage: ./setup.sh FREQ_MHZ 4 | # 5 | # Generates the required IPs for the project. FREQ_MHZ is the frequency of the 6 | # PLL in MHz. It must be an integer. 7 | 8 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 9 | 10 | if [ $# -eq 0 ]; then 11 | echo "Must specify frequency in MHz." 12 | exit 1 13 | fi 14 | 15 | FREQ=$1 16 | 17 | # Check if FREQ is an integer. 18 | if ! [[ $FREQ =~ ^[0-9]+$ ]]; then 19 | echo "Frequency must be an integer." 20 | exit 1 21 | fi 22 | 23 | cd $SCRIPT_DIR/ip 24 | rm -rf my_pll 25 | rm -f my_pll.tcl 26 | sed "s/{{{out_freq}}}/${FREQ}.0/g" my_pll.tcl.template > my_pll.tcl 27 | qsys-script --script=my_pll.tcl --quartus-project=../quartus/bmw.qsf 28 | -------------------------------------------------------------------------------- /hardware/bmw/src/bmw_sram_top.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 10ps 2 | /*----------------------------------------------------------------------------- 3 | 4 | Proprietary and Confidential Information 5 | 6 | Module: PIFO_SRAM_TOP.v 7 | Author: Zhiyu Zhang 8 | Date : 03/10/2023 9 | 10 | Description: Top-level module that contains n levels (n is parameterizable) 11 | of PIFO components (In this version, PIFO storage elements are 12 | SRAM instead of FFs. This makes the whole PIFO tree more expandable.). 13 | 14 | Issues: 15 | 16 | -----------------------------------------------------------------------------*/ 17 | 18 | //----------------------------------------------------------------------------- 19 | // Module Port Definition 20 | //----------------------------------------------------------------------------- 21 | module bmw_sram_top 22 | #( 23 | parameter PTW = 16, // Payload data width 24 | parameter MTW = 0, // Metadata width 25 | parameter CTW = 10, // Counter width 26 | parameter ADW = 20, // Address width 27 | parameter LEVEL = 8 // Sub-tree level 28 | )( 29 | // Clock and Reset 30 | input i_clk, 31 | input i_arst_n, 32 | 33 | // Push and Pop port to the whole PIFO tree 34 | input i_push, 35 | input [(MTW+PTW)-1:0] i_push_data, 36 | 37 | input i_pop, 38 | output [(MTW+PTW)-1:0] o_pop_data 39 | ); 40 | //----------------------------------------------------------------------------- 41 | // Include Files 42 | //----------------------------------------------------------------------------- 43 | 44 | //----------------------------------------------------------------------------- 45 | // Parameters 46 | //----------------------------------------------------------------------------- 47 | 48 | //----------------------------------------------------------------------------- 49 | // Functions and Tasks 50 | //----------------------------------------------------------------------------- 51 | 52 | 53 | function integer find_level; 54 | input integer a; 55 | integer i,j,k; 56 | begin 57 | k=0; 58 | find_level=0; 59 | for (i=0;i ADDR_WIDTH %d : DATA_WIDTH %d : ARCH %d i.e. target %s : RDW_MODE %d i.e. %s ", ADDR_WIDTH,DATA_WIDTH, ARCH , ARCH ? "MLAB" : "M20K", RDW_MODE, RDW_MODE ? "New Data on Simul RW same addr" : "Old Data on Simul RW same addr"); 182 | $display("\n"); 183 | end 184 | `endif 185 | 186 | 187 | 188 | endmodule 189 | -------------------------------------------------------------------------------- /hardware/bmw/src/top.sv: -------------------------------------------------------------------------------- 1 | `timescale 1 ps / 1 ps 2 | 3 | module top ( 4 | input in_clk100, 5 | input cpu_resetn, 6 | output logic bmw_out 7 | ); 8 | 9 | wire rst, user_clk; 10 | assign rst = ~cpu_resetn; 11 | 12 | my_pll user_pll ( 13 | .rst (rst), 14 | .refclk (in_clk100), 15 | .locked (), 16 | .outclk_0 (user_clk) 17 | ); 18 | 19 | `ifndef LEVELS 20 | `define LEVELS 8 21 | `endif // LEVELS 22 | 23 | `ifndef PRIORITY_BITS 24 | `define PRIORITY_BITS 16 25 | `endif // PRIORITY_BITS 26 | 27 | localparam ORDER = 4; // Hardcoded in the design. 28 | 29 | localparam NB_ELEMENTS = ORDER * (1 - ORDER ** `LEVELS) / (1 - ORDER); 30 | localparam PTW = `PRIORITY_BITS; // Payload data width (weight) 31 | localparam MTW = $clog2(NB_ELEMENTS); // Metadata width. 32 | localparam CTW = $clog2(NB_ELEMENTS); // Counter width. 33 | localparam ADW = $clog2(ORDER**`LEVELS); // Address width (used to index nodes 34 | // in a given tree level). 35 | 36 | logic i_push; 37 | logic i_pop; 38 | 39 | logic [(MTW+PTW)-1:0] i_push_data; 40 | logic [(MTW+PTW)-1:0] o_pop_data; 41 | 42 | always_ff @(posedge user_clk) begin 43 | if (rst) begin 44 | i_push <= 0; 45 | i_pop <= 1; 46 | i_push_data <= 0; 47 | end else begin 48 | i_push <= !i_push; 49 | i_pop <= !i_pop; 50 | i_push_data <= i_push_data + 1; 51 | end 52 | end 53 | 54 | always_ff @(posedge user_clk) begin 55 | bmw_out <= ^o_pop_data; 56 | end 57 | 58 | bmw_sram_top #( 59 | .PTW (PTW), 60 | .MTW (MTW), 61 | .CTW (CTW), 62 | .ADW (ADW), 63 | .LEVEL (`LEVELS) 64 | ) bmw_sram_top_inst ( 65 | .i_clk (user_clk), 66 | .i_arst_n (~rst), 67 | .i_push (i_push), 68 | .i_push_data (i_push_data), 69 | .i_pop (i_pop), 70 | .o_pop_data (o_pop_data) 71 | ); 72 | 73 | endmodule 74 | -------------------------------------------------------------------------------- /hardware/pieo/ip/.gitignore: -------------------------------------------------------------------------------- 1 | .qsys_edit 2 | *.ip 3 | 4 | my_pll 5 | 6 | # Will be generated from template. 7 | my_pll.tcl 8 | -------------------------------------------------------------------------------- /hardware/pieo/quartus/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !*.qpf 4 | !*.qsf 5 | !*.sdc 6 | -------------------------------------------------------------------------------- /hardware/pieo/quartus/pieo.qpf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------- # 2 | # 3 | # Copyright (C) 2019 Intel Corporation. All rights reserved. 4 | # Your use of Intel Corporation's design tools, logic functions 5 | # and other software and tools, and any partner logic 6 | # functions, and any output files from any of the foregoing 7 | # (including device programming or simulation files), and any 8 | # associated documentation or information are expressly subject 9 | # to the terms and conditions of the Intel Program License 10 | # Subscription Agreement, the Intel Quartus Prime License Agreement, 11 | # the Intel FPGA IP License Agreement, or other applicable license 12 | # agreement, including, without limitation, that your use is for 13 | # the sole purpose of programming logic devices manufactured by 14 | # Intel and sold by Intel or its authorized distributors. Please 15 | # refer to the applicable agreement for further details, at 16 | # https://fpgasoftware.intel.com/eula. 17 | # 18 | # -------------------------------------------------------------------------- # 19 | # 20 | # Quartus Prime 21 | # Version 19.3.0 Build 222 09/23/2019 SC Pro Edition 22 | # Date created = 18:26:26 January 19, 2023 23 | # 24 | # -------------------------------------------------------------------------- # 25 | 26 | QUARTUS_VERSION = "19.3" 27 | DATE = "18:26:26 January 19, 2023" 28 | 29 | # Revisions 30 | 31 | PROJECT_REVISION = "pieo" 32 | -------------------------------------------------------------------------------- /hardware/pieo/quartus/pieo.qsf: -------------------------------------------------------------------------------- 1 | 2 | # Project-Wide Assignments 3 | # ======================== 4 | set_global_assignment -name ORIGINAL_QUARTUS_VERSION 19.3.0 5 | set_global_assignment -name PROJECT_CREATION_TIME_DATE "13:24:03 JANUARY 20, 2023" 6 | set_global_assignment -name LAST_QUARTUS_VERSION "19.3.0 Pro Edition" 7 | set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files 8 | 9 | # Pin & Location Assignments 10 | # ========================== 11 | set_location_assignment PIN_BL14 -to cpu_resetn 12 | set_location_assignment PIN_AT13 -to in_clk100 13 | set_location_assignment PIN_AU13 -to "in_clk100(n)" 14 | set_location_assignment PIN_BG12 -to pieo_out 15 | 16 | # Classic Timing Assignments 17 | # ========================== 18 | set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 19 | set_global_assignment -name MAX_CORE_JUNCTION_TEMP 100 20 | set_global_assignment -name TIMING_ANALYZER_MULTICORNER_ANALYSIS ON 21 | 22 | # Analysis & Synthesis Assignments 23 | # ================================ 24 | set_global_assignment -name TOP_LEVEL_ENTITY top 25 | set_global_assignment -name FAMILY "Stratix 10" 26 | set_global_assignment -name SEARCH_PATH ../src/common 27 | 28 | # Fitter Assignments 29 | # ================== 30 | set_global_assignment -name DEVICE 1SM21BHU2F53E1VG 31 | set_instance_assignment -name IO_STANDARD LVDS -to in_clk100 -entity top 32 | set_instance_assignment -name IO_STANDARD LVDS -to "in_clk100(n)" -entity top 33 | set_instance_assignment -name IO_STANDARD "1.8 V" -to cpu_resetn -entity top 34 | set_instance_assignment -name IO_STANDARD "1.8 V" -to pieo_out -entity top 35 | 36 | # Ordering Sensitive Assignments 37 | # ============================== 38 | 39 | set_global_assignment -name OPTIMIZATION_MODE "SUPERIOR PERFORMANCE WITH MAXIMUM PLACEMENT EFFORT" 40 | set_global_assignment -name ENABLE_INTERMEDIATE_SNAPSHOTS ON 41 | set_global_assignment -name FAST_PRESERVE OFF -entity top 42 | 43 | set_global_assignment -name SYSTEMVERILOG_FILE ../src/top.sv 44 | set_global_assignment -name SYSTEMVERILOG_FILE ../src/pieo.sv 45 | set_global_assignment -name SYSTEMVERILOG_FILE ../src/pieo_datatypes.sv 46 | set_global_assignment -name IP_FILE ../ip/my_pll.ip 47 | 48 | set_global_assignment -name SDC_ENTITY_FILE pieo.sdc -entity top 49 | -------------------------------------------------------------------------------- /hardware/pieo/quartus/pieo.sdc: -------------------------------------------------------------------------------- 1 | 2 | # create_clock -period 10.00 -name in_clk100 [get_ports in_clk100] 3 | 4 | # Not needed for Stratix 10 5 | # derive_pll_clocks 6 | 7 | derive_clock_uncertainty 8 | -------------------------------------------------------------------------------- /hardware/pieo/scripts/bisect_fmax.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Usage: ELEMENT_BITS=XXX PRIORITY_BITS=YYY \ 4 | # [MIN_FREQ=AAA] [MAX_FREQ=BBB] [PRECISION=CCC] \ 5 | # ./bisect_fmax.sh [seed1] [seed2] ... 6 | # 7 | # Given a design configuration, performs a bisection search to 8 | # find the target Fmax that closes timing. Tries as many seeds 9 | # as specified, using a single process for synthesis. 10 | # 11 | PROJECT_NAME="pieo" 12 | 13 | CUR_DIR=$(pwd) 14 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 15 | PROJECT_DIR="${SCRIPT_DIR}/.." 16 | 17 | if [ $# -eq 0 ]; then 18 | echo "Must specify seeds." 19 | exit 1 20 | fi 21 | 22 | SEEDS=$@ 23 | 24 | # If MIN_FREQ is not defined, use the default. 25 | if [ -z ${MIN_FREQ} ]; then 26 | MIN_FREQ=50 27 | echo "MIN_FREQ is not defined, using ${MIN_FREQ} MHz." 28 | fi 29 | 30 | # If MAX_FREQ is not defined, use the default. 31 | if [ -z ${MAX_FREQ} ]; then 32 | MAX_FREQ=400 33 | echo "MAX_FREQ is not defined, using ${MAX_FREQ} MHz." 34 | fi 35 | 36 | # If PRECISION is not defined, use the default. 37 | if [ -z ${PRECISION} ]; then 38 | PRECISION=3 39 | echo "PRECISION is not defined, using ${PRECISION} MHz." 40 | 41 | elif [ ${PRECISION} -lt 1 ]; then 42 | echo "PRECISION must be greater than 0." 43 | exit 1 44 | fi 45 | 46 | # Outputs 47 | best_fmax=0 48 | best_seed=-1 49 | output_dir="${PROJECT_DIR}/quartus/bisect_fmax" 50 | 51 | # Report files 52 | timing_report="${PROJECT_DIR}/quartus/output_files/${PROJECT_NAME}.sta.rpt" 53 | fitter_report="${PROJECT_DIR}/quartus/output_files/${PROJECT_NAME}.fit.summary" 54 | 55 | # Setup 56 | rm -rf ${output_dir} 57 | rm -f ${timing_report} 58 | rm -f ${fitter_report} 59 | mkdir -p ${output_dir} 60 | 61 | # Housekeeping 62 | fmax_lower=0 63 | fmax_upper=${MAX_FREQ} 64 | current_freq=$(( ${MAX_FREQ} / 2 )) 65 | 66 | while true 67 | do 68 | # Setup for the next iteration 69 | rm -rf ${PROJECT_DIR}/quartus/output_files 70 | 71 | # Print start message and run the setup script for the current fmax 72 | echo "Attempting synthesis with target fmax ${current_freq} MHz" 73 | ${PROJECT_DIR}/setup.sh ${current_freq} 74 | if [ $? -ne 0 ]; then 75 | echo "Setup script failed for ${current_freq} MHz, exiting." 76 | exit 1 77 | fi 78 | 79 | timing_success=0 80 | for seed in ${SEEDS[@]}; do 81 | 82 | # First, run synthesis for this seed (8-hour timeout) 83 | timeout -k 60 8h ${SCRIPT_DIR}/synthesize.sh ${seed} 84 | retcode=$? 85 | if [ ${retcode} -eq 124 ]; then 86 | echo "Synthesis script timed out for ${current_freq} MHz and seed ${seed}, skipping." 87 | continue 88 | elif [ ${retcode} -ne 0 ]; then 89 | echo "Synthesis script failed for ${current_freq} MHz and seed ${seed}, skipping." 90 | continue 91 | fi 92 | # If the timing report is clear, declare success 93 | if [ -f "${timing_report}" ]; then 94 | timing_success=1 95 | if grep -qcm1 "Timing requirements not met" ${timing_report}; then 96 | timing_success=0; 97 | fi 98 | fi 99 | # Found a seed that works, stop early 100 | if [ ${timing_success} -eq 1 ]; then 101 | best_fmax=${current_freq} 102 | best_seed=${seed} 103 | 104 | # Copy the reports to the output directory 105 | cp ${timing_report} ${output_dir}/ 106 | cp ${fitter_report} ${output_dir}/ 107 | break 108 | fi 109 | done 110 | 111 | if [ ${timing_success} -eq 1 ]; then 112 | # Found a new lower bound 113 | fmax_lower=${current_freq} 114 | else 115 | # Synthesis failed, found a new upper bound 116 | fmax_upper=${current_freq} 117 | fi 118 | # Update frequency estimate 119 | current_freq=$(( (${fmax_lower} + ${fmax_upper}) / 2 )) 120 | 121 | if (( ${current_freq} < ${MIN_FREQ} )); then 122 | echo "Warning: bisect_fmax reached MIN_FREQ, design may not be synthesizable." 123 | break 124 | 125 | elif (( ${fmax_upper} - ${fmax_lower} <= ${PRECISION} )); then 126 | break # Found the frequency 127 | fi 128 | done 129 | 130 | if [ ${best_fmax} -ne 0 ]; then 131 | echo "Best fmax: ${best_fmax}, seed: ${best_seed}" | tee ${output_dir}/fmax.txt 132 | fi 133 | 134 | # Announce that it is over. 135 | tput bel 136 | -------------------------------------------------------------------------------- /hardware/pieo/scripts/sweep_bisect_fmax.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Usage: [MIN_FREQ=AAA] [MAX_FREQ=BBB] [PRECISION=CCC] \ 4 | # [NUM_PROCS=DDD] ./sweep_bisect_fmax.sh [seed1] [seed2] ... 5 | # 6 | PROJECT_NAME="pieo" 7 | 8 | CUR_DIR=$(pwd) 9 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 10 | PROJECT_DIR="${SCRIPT_DIR}/.." 11 | 12 | if [ $# -eq 0 ]; then 13 | echo "Must specify seeds." 14 | exit 1 15 | fi 16 | 17 | # If NUM_PROCS is not defined, use the default. 18 | if [ -z ${NUM_PROCS} ]; then 19 | NUM_PROCS=8 20 | echo "NUM_PROCS is not defined, using ${NUM_PROCS}." 21 | fi 22 | 23 | # Exit when error occurs. 24 | set -e 25 | trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG 26 | trap 'echo "\"${last_command}\" command exited with code $?."' EXIT 27 | 28 | rm -rf ${PROJECT_DIR}/quartus/sweep_bisect_fmax 29 | mkdir -p ${PROJECT_DIR}/quartus/sweep_bisect_fmax 30 | 31 | tmp_dir="/tmp/${PROJECT_NAME}" 32 | rm -rf ${tmp_dir} 33 | cp -r ${PROJECT_DIR} ${tmp_dir} 34 | rm -rf ${tmp_dir}/quartus/sweep_bisect_fmax 35 | 36 | jobs="sweep_bisect_fmax_jobs.txt" 37 | rm -f ${jobs} 38 | 39 | # Number of priority bits 40 | for p in 8 9 12 15 41 | do 42 | # Number of element bits 43 | for n in 7 8 9 10 11 12 13 14 15 16 44 | do 45 | midfix="p${p}_n${n}" 46 | 47 | dst_dir=${PROJECT_DIR}/quartus/sweep_bisect_fmax/${midfix} 48 | rm -rf ${dst_dir} 49 | cp -r ${tmp_dir} ${dst_dir} 50 | 51 | echo "ELEMENT_BITS=${n} PRIORITY_BITS=${p}"\ 52 | "${dst_dir}/scripts/bisect_fmax.sh $@ | tee"\ 53 | "${dst_dir}/bisect_fmax_log.txt" >> ${jobs} 54 | done 55 | done 56 | 57 | rm -rf ${tmp_dir} 58 | parallel -j${NUM_PROCS} < ${jobs} 59 | rm -f ${jobs} 60 | -------------------------------------------------------------------------------- /hardware/pieo/scripts/synthesize.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Usage: ELEMENT_BITS=XXX PRIORITY_BITS=YYY \ 4 | # ./synthesize.sh [SEED] 5 | # 6 | PROJECT_NAME="pieo" 7 | 8 | CUR_DIR=$(pwd) 9 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 10 | PROJECT_DIR="${SCRIPT_DIR}/.." 11 | 12 | SEED=${1:-"0"} 13 | 14 | # If ELEMENT_BITS is not defined, exit. 15 | if [ -z ${ELEMENT_BITS} ]; then 16 | echo "ELEMENT_BITS is not defined. Exiting." 17 | exit 1 18 | fi 19 | 20 | # If PRIORITY_BITS is not defined, exit. 21 | if [ -z ${PRIORITY_BITS} ]; then 22 | echo "PRIORITY_BITS is not defined. Exiting." 23 | exit 1 24 | fi 25 | 26 | echo "SEED=${SEED}" 27 | 28 | PROJECT_OUTPUT_DIRECTORY="output_files" 29 | QUARTUS_STA_LOG_FILE="quartus_sta.log" 30 | 31 | # Exit when error occurs. 32 | set -e 33 | trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG 34 | trap 'echo "\"${last_command}\" command exited with code $?."' EXIT 35 | 36 | cd ${PROJECT_DIR}/quartus 37 | 38 | start=$(date +%s.%N) 39 | # Generate IPs if necessary. 40 | quartus_ipgenerate ${PROJECT_NAME} 41 | 42 | quartus_syn --read_settings_files=on --write_settings_files=off ${PROJECT_NAME} \ 43 | -c ${PROJECT_NAME} --set=VERILOG_MACRO=PRIORITY_BITS=${PRIORITY_BITS} \ 44 | --set=VERILOG_MACRO=ELEMENT_BITS=${ELEMENT_BITS} 45 | 46 | quartus_fit --read_settings_files=on --write_settings_files=off ${PROJECT_NAME} \ 47 | -c ${PROJECT_NAME} --seed=${SEED} 48 | 49 | # We use script instead of tee to capture the output and display it while 50 | # preserving colors. 51 | script --flush --quiet --return ${QUARTUS_STA_LOG_FILE} \ 52 | --command "quartus_sta ${PROJECT_NAME} -c ${PROJECT_NAME} --mode=finalize" 53 | 54 | quartus_asm --read_settings_files=on --write_settings_files=off ${PROJECT_NAME} \ 55 | -c ${PROJECT_NAME} 56 | 57 | dur=$(echo "$(date +%s.%N) - ${start}" | bc) 58 | printf "Synthesis completed in %.6f seconds\n" ${dur} 59 | 60 | # Show Fmax. 61 | grep -C2 "; Fmax" "${PROJECT_OUTPUT_DIRECTORY}/${PROJECT_NAME}.sta.rpt" 62 | 63 | if grep -q "Timing requirements not met" ${QUARTUS_STA_LOG_FILE}; then 64 | # Show slack. 65 | grep -C 10 "Timing requirements not met" ${QUARTUS_STA_LOG_FILE} 66 | RED='\033[0;31m' 67 | NC='\033[0m' # No Color. 68 | echo -e "${RED}===========================${NC}" 69 | echo -e "${RED}Timing requirements not met${NC}" 70 | echo -e "${RED}===========================${NC}" 71 | fi 72 | 73 | echo "Done (P=${PRIORITY_BITS}, log2(N)=${ELEMENT_BITS}, seed=${SEED})" 74 | 75 | # Announce that it is over. 76 | tput bel 77 | -------------------------------------------------------------------------------- /hardware/pieo/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Usage: ./setup.sh FREQ_MHZ 4 | # 5 | # Generates the required IPs for the project. FREQ_MHZ is the frequency of the 6 | # PLL in MHz. It must be an integer. 7 | 8 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 9 | 10 | if [ $# -eq 0 ]; then 11 | echo "Must specify frequency in MHz." 12 | exit 1 13 | fi 14 | 15 | FREQ=$1 16 | 17 | # Check if FREQ is an integer. 18 | if ! [[ $FREQ =~ ^[0-9]+$ ]]; then 19 | echo "Frequency must be an integer." 20 | exit 1 21 | fi 22 | 23 | cd $SCRIPT_DIR/ip 24 | rm -rf my_pll 25 | rm -f my_pll.tcl 26 | sed "s/{{{out_freq}}}/${FREQ}.0/g" my_pll.tcl.template > my_pll.tcl 27 | qsys-script --script=my_pll.tcl --quartus-project=../quartus/pieo.qsf 28 | -------------------------------------------------------------------------------- /hardware/pieo/src/common/dual_port_bram.v: -------------------------------------------------------------------------------- 1 | // synopsys translate_off 2 | `timescale 1 ns / 1 ps 3 | // synopsys translate_on 4 | 5 | module alt_ram 6 | #( 7 | parameter RAM_WIDTH = 1, 8 | parameter RAM_ADDR_BITS = 1, 9 | parameter USE_OUTPUT_REGISTER = 0, 10 | parameter INIT_FILE = "" 11 | ) 12 | ( 13 | address_a, 14 | address_b, 15 | clock, 16 | data_a, 17 | data_b, 18 | rden_a, 19 | rden_b, 20 | wren_a, 21 | wren_b, 22 | q_a, 23 | q_b); 24 | 25 | input [RAM_ADDR_BITS-1:0] address_a; 26 | input [RAM_ADDR_BITS-1:0] address_b; 27 | input clock; 28 | input [RAM_WIDTH-1:0] data_a; 29 | input [RAM_WIDTH-1:0] data_b; 30 | input rden_a; 31 | input rden_b; 32 | input wren_a; 33 | input wren_b; 34 | output [RAM_WIDTH-1:0] q_a; 35 | output [RAM_WIDTH-1:0] q_b; 36 | `ifndef ALTERA_RESERVED_QIS 37 | // synopsys translate_off 38 | `endif 39 | tri1 clock; 40 | tri1 rden_a; 41 | tri1 rden_b; 42 | tri0 wren_a; 43 | tri0 wren_b; 44 | `ifndef ALTERA_RESERVED_QIS 45 | // synopsys translate_on 46 | `endif 47 | 48 | localparam OUT_REG = (USE_OUTPUT_REGISTER) ? "CLOCK0" : "UNREGISTERED"; 49 | 50 | 51 | wire [RAM_WIDTH-1:0] sub_wire0; 52 | wire [RAM_WIDTH-1:0] sub_wire1; 53 | wire [RAM_WIDTH-1:0] q_a = sub_wire0[RAM_WIDTH-1:0]; 54 | wire [RAM_WIDTH-1:0] q_b = sub_wire1[RAM_WIDTH-1:0]; 55 | 56 | altsyncram altsyncram_component ( 57 | .clock0 (clock), 58 | .wren_a (wren_a), 59 | .address_b (address_b), 60 | .data_b (data_b), 61 | .rden_a (rden_a), 62 | .wren_b (wren_b), 63 | .address_a (address_a), 64 | .data_a (data_a), 65 | .rden_b (rden_b), 66 | .q_a (sub_wire0), 67 | .q_b (sub_wire1), 68 | .aclr0 (1'b0), 69 | .aclr1 (1'b0), 70 | .addressstall_a (1'b0), 71 | .addressstall_b (1'b0), 72 | .byteena_a (1'b1), 73 | .byteena_b (1'b1), 74 | .clock1 (1'b1), 75 | .clocken0 (1'b1), 76 | .clocken1 (1'b1), 77 | .clocken2 (1'b1), 78 | .clocken3 (1'b1), 79 | .eccstatus ()); 80 | defparam 81 | altsyncram_component.address_reg_b = "CLOCK0", 82 | altsyncram_component.clock_enable_input_a = "BYPASS", 83 | altsyncram_component.clock_enable_input_b = "BYPASS", 84 | altsyncram_component.clock_enable_output_a = "BYPASS", 85 | altsyncram_component.clock_enable_output_b = "BYPASS", 86 | altsyncram_component.indata_reg_b = "CLOCK0", 87 | `ifdef NO_PLI 88 | altsyncram_component.init_file = "somefile.rif" 89 | `else 90 | altsyncram_component.init_file = INIT_FILE 91 | `endif 92 | , 93 | altsyncram_component.intended_device_family = "Stratix V", 94 | altsyncram_component.lpm_type = "altsyncram", 95 | altsyncram_component.numwords_a = 2**RAM_ADDR_BITS, 96 | altsyncram_component.numwords_b = 2**RAM_ADDR_BITS, 97 | altsyncram_component.operation_mode = "BIDIR_DUAL_PORT", 98 | altsyncram_component.outdata_aclr_a = "NONE", 99 | altsyncram_component.outdata_aclr_b = "NONE", 100 | altsyncram_component.outdata_reg_a = OUT_REG, 101 | altsyncram_component.outdata_reg_b = OUT_REG, 102 | altsyncram_component.power_up_uninitialized = "FALSE", 103 | altsyncram_component.read_during_write_mode_mixed_ports = "DONT_CARE", 104 | altsyncram_component.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ", 105 | altsyncram_component.read_during_write_mode_port_b = "NEW_DATA_NO_NBE_READ", 106 | altsyncram_component.widthad_a = RAM_ADDR_BITS, 107 | altsyncram_component.widthad_b = RAM_ADDR_BITS, 108 | altsyncram_component.width_a = RAM_WIDTH, 109 | altsyncram_component.width_b = RAM_WIDTH, 110 | altsyncram_component.width_byteena_a = 1, 111 | altsyncram_component.width_byteena_b = 1, 112 | altsyncram_component.wrcontrol_wraddress_reg_b = "CLOCK0"; 113 | 114 | endmodule 115 | 116 | module dual_port_bram # 117 | ( 118 | parameter RAM_WIDTH = 32, 119 | parameter RAM_ADDR_BITS = 10, 120 | parameter RAM_LINES = (2**RAM_ADDR_BITS), 121 | parameter USE_OUTPUT_REGISTER = 0, 122 | parameter INIT_FILE = "" 123 | ) 124 | ( 125 | input clk, 126 | 127 | input [RAM_WIDTH-1:0] Data_In_A, 128 | input [RAM_ADDR_BITS-1:0] Addr_A, 129 | input En_A, 130 | input Wen_A, 131 | output [RAM_WIDTH-1:0] Data_Out_A, 132 | 133 | input [RAM_WIDTH-1:0] Data_In_B, 134 | input [RAM_ADDR_BITS-1:0] Addr_B, 135 | input En_B, 136 | input Wen_B, 137 | output [RAM_WIDTH-1:0] Data_Out_B 138 | 139 | ); 140 | 141 | 142 | alt_ram #( 143 | .RAM_WIDTH( RAM_WIDTH ), 144 | .RAM_ADDR_BITS( RAM_ADDR_BITS ), 145 | .USE_OUTPUT_REGISTER( USE_OUTPUT_REGISTER ), 146 | .INIT_FILE( INIT_FILE ) 147 | ) 148 | bram 149 | ( 150 | .clock( clk ), 151 | 152 | .address_a( Addr_A ), 153 | .rden_a( En_A & ~Wen_A ), 154 | .wren_a( En_A & Wen_A ), 155 | .data_a( Data_In_A ), 156 | .q_a( Data_Out_A ), 157 | 158 | .address_b( Addr_B ), 159 | .rden_b( En_B & ~Wen_B), 160 | .wren_b( En_B & Wen_B ), 161 | .data_b( Data_In_B ), 162 | .q_b( Data_Out_B ) 163 | ); 164 | 165 | endmodule 166 | -------------------------------------------------------------------------------- /hardware/pieo/src/pieo_datatypes.sv: -------------------------------------------------------------------------------- 1 | `ifndef PIEO_DATATYPES 2 | `define PIEO_DATATYPES 3 | 4 | package pieo_datatypes; 5 | 6 | // Original parameters. 7 | // localparam LIST_SIZE = (2**6); 8 | // localparam ID_LOG = $clog2(LIST_SIZE); 9 | // localparam RANK_LOG = 16; 10 | // localparam TIME_LOG = 16; 11 | 12 | // localparam NUM_OF_ELEMENTS_PER_SUBLIST = (2**3); //sqrt(LIST_SIZE) 13 | // localparam NUM_OF_SUBLIST = (2**4); //2*NUM_OF_ELEMENTS_PER_SUBLIST 14 | 15 | // localparam ID_LOG = `ID_LOG; // Log of the number of elements. 16 | // localparam RANK_LOG = `RANK_LOG; 17 | 18 | // `ifndef ELEMENT_BITS 19 | // `define ELEMENT_BITS 7 20 | // `endif // ELEMENT_BITS 21 | 22 | // `ifndef PRIORITY_BITS 23 | // `define PRIORITY_BITS 8 24 | // `endif // PRIORITY_BITS 25 | 26 | localparam ID_LOG = `ELEMENT_BITS; // Log of the number of elements. 27 | localparam RANK_LOG = `PRIORITY_BITS; 28 | 29 | localparam TIME_LOG = RANK_LOG; 30 | localparam LIST_SIZE = 2**ID_LOG; 31 | 32 | localparam NUM_OF_ELEMENTS_PER_SUBLIST = int'($sqrt(LIST_SIZE)); 33 | localparam NUM_OF_SUBLIST = 2 * NUM_OF_ELEMENTS_PER_SUBLIST; 34 | 35 | typedef struct packed 36 | { 37 | logic [ID_LOG-1:0] id; 38 | logic [RANK_LOG-1:0] rank; //init with infinity 39 | logic [TIME_LOG-1:0] send_time; 40 | } SublistElement; 41 | 42 | typedef struct packed 43 | { 44 | logic [$clog2(NUM_OF_SUBLIST)-1:0] id; 45 | logic [RANK_LOG-1:0] smallest_rank; //init with infinity 46 | logic [TIME_LOG-1:0] smallest_send_time; //init with infinity 47 | logic full; 48 | logic [$clog2(NUM_OF_SUBLIST/2)-1:0] num; 49 | } PointerElement; 50 | 51 | endpackage 52 | `endif 53 | -------------------------------------------------------------------------------- /hardware/pieo/src/top.sv: -------------------------------------------------------------------------------- 1 | `timescale 1 ps / 1 ps 2 | 3 | import pieo_datatypes::*; 4 | 5 | module top ( 6 | input in_clk100, 7 | input cpu_resetn, 8 | output logic pieo_out 9 | ); 10 | 11 | wire rst, user_clk; 12 | assign rst = ~cpu_resetn; 13 | 14 | my_pll user_pll ( 15 | .rst (~cpu_resetn), 16 | .refclk (in_clk100), 17 | .locked (), 18 | .outclk_0 (user_clk) 19 | ); 20 | 21 | logic pieo_reset_done_out; 22 | 23 | logic start; 24 | 25 | logic pieo_ready_for_nxt_op_out; 26 | 27 | logic enqueue_f_in; 28 | SublistElement f_in; 29 | logic enq_valid_out; 30 | logic [$clog2(NUM_OF_SUBLIST):0] f_enqueued_in_sublist_out; 31 | 32 | logic dequeue_in; 33 | logic [TIME_LOG-1:0] curr_time_in; 34 | 35 | logic dequeue_f_in; 36 | logic [ID_LOG-1:0] flow_id_in; 37 | logic [$clog2(NUM_OF_SUBLIST)-1:0] sublist_id_in; 38 | 39 | logic deq_valid_out; 40 | SublistElement deq_element_out; 41 | 42 | logic [ID_LOG:0] flow_id_moved_out; 43 | logic [$clog2(NUM_OF_SUBLIST):0] flow_id_moved_to_sublist_out; 44 | 45 | always_ff @(posedge user_clk) begin 46 | if (rst) begin 47 | start <= 0; 48 | enqueue_f_in <= 0; 49 | f_in <= 0; 50 | dequeue_in <= 0; 51 | curr_time_in <= 0; 52 | dequeue_f_in <= 0; 53 | flow_id_in <= 0; 54 | sublist_id_in <= 0; 55 | end else begin 56 | start <= !start; 57 | enqueue_f_in <= !enqueue_f_in; 58 | f_in <= f_in + 1; 59 | dequeue_in <= !dequeue_in; 60 | curr_time_in <= curr_time_in + 1; 61 | dequeue_f_in <= !dequeue_f_in; 62 | flow_id_in <= flow_id_in + 1; 63 | sublist_id_in <= sublist_id_in + 1; 64 | end 65 | end 66 | 67 | logic [31:0] out_placeholder; 68 | logic pieo_out_r; 69 | 70 | // Make sure we use all the outputs 71 | always_comb begin 72 | out_placeholder = 0; 73 | out_placeholder ^= f_enqueued_in_sublist_out; 74 | out_placeholder ^= deq_element_out; 75 | out_placeholder ^= flow_id_moved_out; 76 | out_placeholder ^= flow_id_moved_to_sublist_out; 77 | 78 | pieo_out_r = ^out_placeholder; 79 | pieo_out_r ^= pieo_reset_done_out; 80 | pieo_out_r ^= pieo_ready_for_nxt_op_out; 81 | pieo_out_r ^= deq_valid_out; 82 | end 83 | 84 | always_ff @(posedge user_clk) begin 85 | pieo_out <= pieo_out_r; 86 | end 87 | 88 | pieo pieo_inst ( 89 | .clk (user_clk), 90 | .rst (rst), 91 | .pieo_reset_done_out (pieo_reset_done_out), 92 | .start (start), 93 | .pieo_ready_for_nxt_op_out (pieo_ready_for_nxt_op_out), 94 | .enqueue_f_in (enqueue_f_in), 95 | .f_in (f_in), 96 | .enq_valid_out (enq_valid_out), 97 | .f_enqueued_in_sublist_out (f_enqueued_in_sublist_out), 98 | .dequeue_in (dequeue_in), 99 | .curr_time_in (curr_time_in), 100 | .dequeue_f_in (dequeue_f_in), 101 | .flow_id_in (flow_id_in), 102 | .sublist_id_in (sublist_id_in), 103 | .deq_valid_out (deq_valid_out), 104 | .deq_element_out (deq_element_out), 105 | .flow_id_moved_out (flow_id_moved_out), 106 | .flow_id_moved_to_sublist_out (flow_id_moved_to_sublist_out) 107 | ); 108 | 109 | endmodule 110 | -------------------------------------------------------------------------------- /hardware/pifo/ip/.gitignore: -------------------------------------------------------------------------------- 1 | .qsys_edit 2 | *.ip 3 | 4 | my_pll 5 | 6 | # Will be generated from template. 7 | my_pll.tcl 8 | -------------------------------------------------------------------------------- /hardware/pifo/quartus/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !*.qpf 4 | !*.qsf 5 | !*.sdc 6 | -------------------------------------------------------------------------------- /hardware/pifo/quartus/pifo.qpf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------- # 2 | # 3 | # Copyright (C) 2019 Intel Corporation. All rights reserved. 4 | # Your use of Intel Corporation's design tools, logic functions 5 | # and other software and tools, and any partner logic 6 | # functions, and any output files from any of the foregoing 7 | # (including device programming or simulation files), and any 8 | # associated documentation or information are expressly subject 9 | # to the terms and conditions of the Intel Program License 10 | # Subscription Agreement, the Intel Quartus Prime License Agreement, 11 | # the Intel FPGA IP License Agreement, or other applicable license 12 | # agreement, including, without limitation, that your use is for 13 | # the sole purpose of programming logic devices manufactured by 14 | # Intel and sold by Intel or its authorized distributors. Please 15 | # refer to the applicable agreement for further details, at 16 | # https://fpgasoftware.intel.com/eula. 17 | # 18 | # -------------------------------------------------------------------------- # 19 | # 20 | # Quartus Prime 21 | # Version 19.3.0 Build 222 09/23/2019 SC Pro Edition 22 | # Date created = 18:26:26 January 19, 2023 23 | # 24 | # -------------------------------------------------------------------------- # 25 | 26 | QUARTUS_VERSION = "19.3" 27 | DATE = "18:26:26 January 19, 2023" 28 | 29 | # Revisions 30 | 31 | PROJECT_REVISION = "pifo" 32 | -------------------------------------------------------------------------------- /hardware/pifo/quartus/pifo.qsf: -------------------------------------------------------------------------------- 1 | 2 | # Project-Wide Assignments 3 | # ======================== 4 | set_global_assignment -name ORIGINAL_QUARTUS_VERSION 19.3.0 5 | set_global_assignment -name PROJECT_CREATION_TIME_DATE "13:24:03 JANUARY 20, 2023" 6 | set_global_assignment -name LAST_QUARTUS_VERSION "19.3.0 Pro Edition" 7 | set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files 8 | 9 | # Pin & Location Assignments 10 | # ========================== 11 | set_location_assignment PIN_BL14 -to cpu_resetn 12 | set_location_assignment PIN_AT13 -to in_clk100 13 | set_location_assignment PIN_AU13 -to "in_clk100(n)" 14 | set_location_assignment PIN_BG12 -to pifo_out 15 | 16 | # Classic Timing Assignments 17 | # ========================== 18 | set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 19 | set_global_assignment -name MAX_CORE_JUNCTION_TEMP 100 20 | set_global_assignment -name TIMING_ANALYZER_MULTICORNER_ANALYSIS ON 21 | 22 | # Analysis & Synthesis Assignments 23 | # ================================ 24 | set_global_assignment -name TOP_LEVEL_ENTITY top 25 | set_global_assignment -name FAMILY "Stratix 10" 26 | set_global_assignment -name SEARCH_PATH ../src/common 27 | 28 | # Fitter Assignments 29 | # ================== 30 | set_global_assignment -name DEVICE 1SM21BHU2F53E1VG 31 | set_instance_assignment -name IO_STANDARD LVDS -to in_clk100 -entity top 32 | set_instance_assignment -name IO_STANDARD LVDS -to "in_clk100(n)" -entity top 33 | set_instance_assignment -name IO_STANDARD "1.8 V" -to cpu_resetn -entity top 34 | set_instance_assignment -name IO_STANDARD "1.8 V" -to pifo_out -entity top 35 | 36 | # Ordering Sensitive Assignments 37 | # ============================== 38 | 39 | set_global_assignment -name OPTIMIZATION_MODE "SUPERIOR PERFORMANCE WITH MAXIMUM PLACEMENT EFFORT" 40 | set_global_assignment -name ENABLE_INTERMEDIATE_SNAPSHOTS ON 41 | set_global_assignment -name FAST_PRESERVE OFF -entity top 42 | 43 | set_global_assignment -name SYSTEMVERILOG_FILE ../src/top.sv 44 | set_global_assignment -name SYSTEMVERILOG_FILE ../src/pifo.sv 45 | set_global_assignment -name SYSTEMVERILOG_FILE ../src/panic_pifo.sv 46 | set_global_assignment -name IP_FILE ../ip/my_pll.ip 47 | 48 | set_global_assignment -name SDC_ENTITY_FILE pifo.sdc -entity top 49 | -------------------------------------------------------------------------------- /hardware/pifo/quartus/pifo.sdc: -------------------------------------------------------------------------------- 1 | 2 | # create_clock -period 10.00 -name in_clk100 [get_ports in_clk100] 3 | 4 | # Not needed for Stratix 10 5 | # derive_pll_clocks 6 | 7 | derive_clock_uncertainty 8 | -------------------------------------------------------------------------------- /hardware/pifo/scripts/bisect_fmax.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Usage: ELEMENT_BITS=XXX PRIORITY_BITS=YYY \ 4 | # [MIN_FREQ=AAA] [MAX_FREQ=BBB] [PRECISION=CCC] \ 5 | # ./bisect_fmax.sh [seed1] [seed2] ... 6 | # 7 | # Given a design configuration, performs a bisection search to 8 | # find the target Fmax that closes timing. Tries as many seeds 9 | # as specified, using a single process for synthesis. 10 | # 11 | PROJECT_NAME="pifo" 12 | 13 | CUR_DIR=$(pwd) 14 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 15 | PROJECT_DIR="${SCRIPT_DIR}/.." 16 | 17 | if [ $# -eq 0 ]; then 18 | echo "Must specify seeds." 19 | exit 1 20 | fi 21 | 22 | SEEDS=$@ 23 | 24 | # If MIN_FREQ is not defined, use the default. 25 | if [ -z ${MIN_FREQ} ]; then 26 | MIN_FREQ=50 27 | echo "MIN_FREQ is not defined, using ${MIN_FREQ} MHz." 28 | fi 29 | 30 | # If MAX_FREQ is not defined, use the default. 31 | if [ -z ${MAX_FREQ} ]; then 32 | MAX_FREQ=250 33 | echo "MAX_FREQ is not defined, using ${MAX_FREQ} MHz." 34 | fi 35 | 36 | # If PRECISION is not defined, use the default. 37 | if [ -z ${PRECISION} ]; then 38 | PRECISION=3 39 | echo "PRECISION is not defined, using ${PRECISION} MHz." 40 | 41 | elif [ ${PRECISION} -lt 1 ]; then 42 | echo "PRECISION must be greater than 0." 43 | exit 1 44 | fi 45 | 46 | # Outputs 47 | best_fmax=0 48 | best_seed=-1 49 | output_dir="${PROJECT_DIR}/quartus/bisect_fmax" 50 | 51 | # Report files 52 | timing_report="${PROJECT_DIR}/quartus/output_files/${PROJECT_NAME}.sta.rpt" 53 | fitter_report="${PROJECT_DIR}/quartus/output_files/${PROJECT_NAME}.fit.summary" 54 | 55 | # Setup 56 | rm -rf ${output_dir} 57 | rm -f ${timing_report} 58 | rm -f ${fitter_report} 59 | mkdir -p ${output_dir} 60 | 61 | # Housekeeping 62 | fmax_lower=0 63 | fmax_upper=${MAX_FREQ} 64 | current_freq=$(( ${MAX_FREQ} / 2 )) 65 | 66 | while true 67 | do 68 | # Setup for the next iteration 69 | rm -rf ${PROJECT_DIR}/quartus/output_files 70 | 71 | # Print start message and run the setup script for the current fmax 72 | echo "Attempting synthesis with target fmax ${current_freq} MHz" 73 | ${PROJECT_DIR}/setup.sh ${current_freq} 74 | if [ $? -ne 0 ]; then 75 | echo "Setup script failed for ${current_freq} MHz, exiting." 76 | exit 1 77 | fi 78 | 79 | timing_success=0 80 | for seed in ${SEEDS[@]}; do 81 | 82 | # First, run synthesis for this seed (5-hour timeout) 83 | timeout -k 60 5h ${SCRIPT_DIR}/synthesize.sh ${seed} 84 | retcode=$? 85 | if [ ${retcode} -eq 124 ]; then 86 | echo "Synthesis script timed out for ${current_freq} MHz and seed ${seed}, skipping." 87 | continue 88 | elif [ ${retcode} -ne 0 ]; then 89 | echo "Synthesis script failed for ${current_freq} MHz and seed ${seed}, skipping." 90 | continue 91 | fi 92 | # If the timing report is clear, declare success 93 | if [ -f "${timing_report}" ]; then 94 | timing_success=1 95 | if grep -qcm1 "Timing requirements not met" ${timing_report}; then 96 | timing_success=0; 97 | fi 98 | fi 99 | # Found a seed that works, stop early 100 | if [ ${timing_success} -eq 1 ]; then 101 | best_fmax=${current_freq} 102 | best_seed=${seed} 103 | 104 | # Copy the reports to the output directory 105 | cp ${timing_report} ${output_dir}/ 106 | cp ${fitter_report} ${output_dir}/ 107 | break 108 | fi 109 | done 110 | 111 | if [ ${timing_success} -eq 1 ]; then 112 | # Found a new lower bound 113 | fmax_lower=${current_freq} 114 | else 115 | # Synthesis failed, found a new upper bound 116 | fmax_upper=${current_freq} 117 | fi 118 | # Update frequency estimate 119 | current_freq=$(( (${fmax_lower} + ${fmax_upper}) / 2 )) 120 | 121 | if (( ${current_freq} < ${MIN_FREQ} )); then 122 | echo "Warning: bisect_fmax reached MIN_FREQ, design may not be synthesizable." 123 | break 124 | 125 | elif (( ${fmax_upper} - ${fmax_lower} <= ${PRECISION} )); then 126 | break # Found the frequency 127 | fi 128 | done 129 | 130 | if [ ${best_fmax} -ne 0 ]; then 131 | echo "Best fmax: ${best_fmax}, seed: ${best_seed}" | tee ${output_dir}/fmax.txt 132 | fi 133 | 134 | # Announce that it is over. 135 | tput bel 136 | -------------------------------------------------------------------------------- /hardware/pifo/scripts/sweep_bisect_fmax.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Usage: [MIN_FREQ=AAA] [MAX_FREQ=BBB] [PRECISION=CCC] \ 4 | # [NUM_PROCS=DDD] ./sweep_bisect_fmax.sh [seed1] [seed2] ... 5 | # 6 | PROJECT_NAME="pifo" 7 | 8 | CUR_DIR=$(pwd) 9 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 10 | PROJECT_DIR="${SCRIPT_DIR}/.." 11 | 12 | if [ $# -eq 0 ]; then 13 | echo "Must specify seeds." 14 | exit 1 15 | fi 16 | 17 | # If NUM_PROCS is not defined, use the default. 18 | if [ -z ${NUM_PROCS} ]; then 19 | NUM_PROCS=8 20 | echo "NUM_PROCS is not defined, using ${NUM_PROCS}." 21 | fi 22 | 23 | # Exit when error occurs. 24 | set -e 25 | trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG 26 | trap 'echo "\"${last_command}\" command exited with code $?."' EXIT 27 | 28 | rm -rf ${PROJECT_DIR}/quartus/sweep_bisect_fmax 29 | mkdir -p ${PROJECT_DIR}/quartus/sweep_bisect_fmax 30 | 31 | tmp_dir="/tmp/${PROJECT_NAME}" 32 | rm -rf ${tmp_dir} 33 | cp -r ${PROJECT_DIR} ${tmp_dir} 34 | rm -rf ${tmp_dir}/quartus/sweep_bisect_fmax 35 | 36 | jobs="sweep_bisect_fmax_jobs.txt" 37 | rm -f ${jobs} 38 | 39 | # Number of element bits 40 | for n in 7 8 9 10 11 12 41 | do 42 | # Number of priority bits 43 | for p in 8 9 12 15 44 | do 45 | midfix="p${p}_n${n}" 46 | 47 | dst_dir=${PROJECT_DIR}/quartus/sweep_bisect_fmax/${midfix} 48 | rm -rf ${dst_dir} 49 | cp -r ${tmp_dir} ${dst_dir} 50 | 51 | echo "ELEMENT_BITS=${n} PRIORITY_BITS=${p}"\ 52 | "${dst_dir}/scripts/bisect_fmax.sh $@ | tee"\ 53 | "${dst_dir}/bisect_fmax_log.txt" >> ${jobs} 54 | done 55 | done 56 | 57 | rm -rf ${tmp_dir} 58 | parallel -j${NUM_PROCS} < ${jobs} 59 | rm -f ${jobs} 60 | -------------------------------------------------------------------------------- /hardware/pifo/scripts/synthesize.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Usage: ELEMENT_BITS=XXX PRIORITY_BITS=YYY \ 4 | # ./synthesize.sh [SEED] 5 | # 6 | PROJECT_NAME="pifo" 7 | 8 | CUR_DIR=$(pwd) 9 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 10 | PROJECT_DIR="${SCRIPT_DIR}/.." 11 | 12 | SEED=${1:-"0"} 13 | 14 | # If ELEMENT_BITS is not defined, exit. 15 | if [ -z ${ELEMENT_BITS} ]; then 16 | echo "ELEMENT_BITS is not defined. Exiting." 17 | exit 1 18 | fi 19 | 20 | # If PRIORITY_BITS is not defined, exit. 21 | if [ -z ${PRIORITY_BITS} ]; then 22 | echo "PRIORITY_BITS is not defined. Exiting." 23 | exit 1 24 | fi 25 | 26 | echo "SEED=${SEED}" 27 | 28 | PROJECT_OUTPUT_DIRECTORY="output_files" 29 | QUARTUS_STA_LOG_FILE="quartus_sta.log" 30 | 31 | # Exit when error occurs. 32 | set -e 33 | trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG 34 | trap 'echo "\"${last_command}\" command exited with code $?."' EXIT 35 | 36 | cd ${PROJECT_DIR}/quartus 37 | 38 | start=$(date +%s.%N) 39 | # Generate IPs if necessary. 40 | quartus_ipgenerate ${PROJECT_NAME} 41 | 42 | quartus_syn --read_settings_files=on --write_settings_files=off ${PROJECT_NAME} \ 43 | -c ${PROJECT_NAME} --set=VERILOG_MACRO=PRIORITY_BITS=${PRIORITY_BITS} \ 44 | --set=VERILOG_MACRO=ELEMENT_BITS=${ELEMENT_BITS} 45 | 46 | quartus_fit --read_settings_files=on --write_settings_files=off ${PROJECT_NAME} \ 47 | -c ${PROJECT_NAME} --seed=${SEED} 48 | 49 | # We use script instead of tee to capture the output and display it while 50 | # preserving colors. 51 | script --flush --quiet --return ${QUARTUS_STA_LOG_FILE} \ 52 | --command "quartus_sta ${PROJECT_NAME} -c ${PROJECT_NAME} --mode=finalize" 53 | 54 | quartus_asm --read_settings_files=on --write_settings_files=off ${PROJECT_NAME} \ 55 | -c ${PROJECT_NAME} 56 | 57 | dur=$(echo "$(date +%s.%N) - ${start}" | bc) 58 | printf "Synthesis completed in %.6f seconds\n" ${dur} 59 | 60 | # Show Fmax. 61 | grep -C2 "; Fmax" "${PROJECT_OUTPUT_DIRECTORY}/${PROJECT_NAME}.sta.rpt" 62 | 63 | if grep -q "Timing requirements not met" ${QUARTUS_STA_LOG_FILE}; then 64 | # Show slack. 65 | grep -C 10 "Timing requirements not met" ${QUARTUS_STA_LOG_FILE} 66 | RED='\033[0;31m' 67 | NC='\033[0m' # No Color. 68 | echo -e "${RED}===========================${NC}" 69 | echo -e "${RED}Timing requirements not met${NC}" 70 | echo -e "${RED}===========================${NC}" 71 | fi 72 | 73 | echo "Done (P=${PRIORITY_BITS}, log2(N)=${ELEMENT_BITS}, seed=${SEED})" 74 | 75 | # Announce that it is over. 76 | tput bel 77 | -------------------------------------------------------------------------------- /hardware/pifo/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Usage: ./setup.sh FREQ_MHZ 4 | # 5 | # Generates the required IPs for the project. FREQ_MHZ is the frequency of the 6 | # PLL in MHz. It must be an integer. 7 | 8 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 9 | 10 | if [ $# -eq 0 ]; then 11 | echo "Must specify frequency in MHz." 12 | exit 1 13 | fi 14 | 15 | FREQ=$1 16 | 17 | # Check if FREQ is an integer. 18 | if ! [[ $FREQ =~ ^[0-9]+$ ]]; then 19 | echo "Frequency must be an integer." 20 | exit 1 21 | fi 22 | 23 | cd $SCRIPT_DIR/ip 24 | rm -rf my_pll 25 | rm -f my_pll.tcl 26 | sed "s/{{{out_freq}}}/${FREQ}.0/g" my_pll.tcl.template > my_pll.tcl 27 | qsys-script --script=my_pll.tcl --quartus-project=../quartus/pifo.qsf 28 | -------------------------------------------------------------------------------- /hardware/pifo/src/pifo.sv: -------------------------------------------------------------------------------- 1 | // Extracted from: https://github.com/programmable-scheduling/pifo-hardware 2 | 3 | module pifo ( 4 | clk, rst, 5 | pop_0, oprt_0, ovld_0, opri_0, odout_0, 6 | push_1, uprt_1, upri_1, udin_1, 7 | push_2, uprt_2, upri_2, udin_2 8 | ); 9 | 10 | parameter NUMPIFO = 2**(`ELEMENT_BITS); 11 | parameter BITPORT = 1; 12 | parameter BITPRIO = `PRIORITY_BITS; 13 | parameter BITDATA = $clog2(NUMPIFO); 14 | 15 | localparam BITPIFO = $clog2(NUMPIFO); 16 | 17 | localparam FLOP_IDX = 1; 18 | 19 | input clk, rst; 20 | 21 | input pop_0; 22 | input [BITPORT-1:0] oprt_0; 23 | output ovld_0; 24 | output [BITPRIO-1:0] opri_0; 25 | output [BITDATA-1:0] odout_0; 26 | 27 | input push_1; 28 | input [BITPORT-1:0] uprt_1; 29 | input [BITPRIO-1:0] upri_1; 30 | input [BITDATA-1:0] udin_1; 31 | 32 | input push_2; 33 | input [BITPORT-1:0] uprt_2; 34 | input [BITPRIO-1:0] upri_2; 35 | input [BITDATA-1:0] udin_2; 36 | 37 | wire pop_0_del; 38 | wire [BITPORT-1:0] oprt_0_del; 39 | wire push_1_del; 40 | wire [BITPORT-1:0] uprt_1_del; 41 | wire [BITPRIO-1:0] upri_1_del; 42 | wire [BITDATA-1:0] udin_1_del; 43 | wire push_2_del; 44 | wire [BITPORT-1:0] uprt_2_del; 45 | wire [BITPRIO-1:0] upri_2_del; 46 | wire [BITDATA-1:0] udin_2_del; 47 | shift #(.BITDATA(1+BITPORT), .DELAY(FLOP_IDX)) pop_fidx_inst (.clk(clk), .din({pop_0,oprt_0}), .dout({pop_0_del,oprt_0_del})); 48 | shift #(.BITDATA(1+BITPORT+BITPRIO+BITDATA), .DELAY(FLOP_IDX)) push_1_fidx_inst (.clk(clk), .din({push_1,uprt_1,upri_1,udin_1}), .dout({push_1_del,uprt_1_del,upri_1_del,udin_1_del})); 49 | shift #(.BITDATA(1+BITPORT+BITPRIO+BITDATA), .DELAY(FLOP_IDX)) push_2_fidx_inst (.clk(clk), .din({push_2,uprt_2,upri_2,udin_2}), .dout({push_2_del,uprt_2_del,upri_2_del,udin_2_del})); 50 | 51 | reg [BITDATA-1:0] pf_data [0:NUMPIFO-1]; 52 | reg [BITPRIO-1:0] pf_prio [0:NUMPIFO-1]; 53 | reg [BITPORT-1:0] pf_port [0:NUMPIFO-1]; 54 | reg [BITPIFO :0] pf_cnt; 55 | 56 | reg pop_0_hit; 57 | reg [BITPIFO-1:0] pop_0_idx; 58 | reg [BITPIFO-1:0] push_1_idx; 59 | reg [BITPIFO-1:0] push_1_idx_raw; 60 | reg [BITPIFO-1:0] push_2_idx; 61 | reg [BITPIFO-1:0] push_2_idx_raw; 62 | reg push_hi; 63 | reg [BITPIFO-1:0] push_hi_idx; 64 | reg [BITPIFO-1:0] push_hi_idx_raw; 65 | reg [BITPRIO-1:0] push_hi_pri; 66 | reg [BITPORT-1:0] push_hi_prt; 67 | reg push_lo; 68 | reg [BITPIFO-1:0] push_lo_idx; 69 | reg [BITPIFO-1:0] push_lo_idx_raw; 70 | reg [BITPRIO-1:0] push_lo_pri; 71 | reg [BITPORT-1:0] push_lo_prt; 72 | 73 | wire pop_0_hit_del; 74 | wire [BITPIFO-1:0] pop_0_idx_del; 75 | wire [BITPIFO-1:0] push_1_idx_del; 76 | wire [BITPIFO-1:0] push_2_idx_del; 77 | wire [BITPIFO-1:0] push_1_idx_raw_del; 78 | wire [BITPIFO-1:0] push_2_idx_raw_del; 79 | wire push_hi_del; 80 | wire [BITPIFO-1:0] push_hi_idx_del; 81 | wire [BITPIFO-1:0] push_hi_idx_raw_del; 82 | wire [BITPRIO-1:0] push_hi_pri_del; 83 | wire [BITPORT-1:0] push_hi_prt_del; 84 | wire push_lo_del; 85 | wire [BITPIFO-1:0] push_lo_idx_del; 86 | wire [BITPIFO-1:0] push_lo_idx_raw_del; 87 | wire [BITPRIO-1:0] push_lo_pri_del; 88 | wire [BITPORT-1:0] push_lo_prt_del; 89 | shift #(.BITDATA(1+BITPIFO), .DELAY(FLOP_IDX)) pop_idx_del_inst (.clk(clk), .din({pop_0_hit,pop_0_idx}), .dout({pop_0_hit_del,pop_0_idx_del})); 90 | shift #(.BITDATA(2*BITPIFO), .DELAY(FLOP_IDX)) push_idx_del_inst (.clk(clk), .din({push_1_idx, push_2_idx}), .dout({push_1_idx_del,push_2_idx_del})); 91 | shift #(.BITDATA(2*BITPIFO), .DELAY(FLOP_IDX)) push_idx_raw_del_inst (.clk(clk), .din({push_1_idx_raw, push_2_idx_raw}), .dout({push_1_idx_raw_del,push_2_idx_raw_del})); 92 | shift #(.BITDATA(1+BITPIFO+BITPIFO+BITPRIO+BITPORT), .DELAY(FLOP_IDX)) push_hi_del_inst (.clk(clk), .din({push_hi, push_hi_idx, push_hi_idx_raw, push_hi_pri, push_hi_prt}), .dout({push_hi_del,push_hi_idx_del,push_hi_idx_raw_del,push_hi_pri_del, push_hi_prt_del})); 93 | shift #(.BITDATA(1+BITPIFO+BITPIFO+BITPRIO+BITPORT), .DELAY(FLOP_IDX)) push_lo_del_inst (.clk(clk), .din({push_lo, push_lo_idx, push_lo_idx_raw, push_lo_pri, push_lo_prt}), .dout({push_lo_del,push_lo_idx_del,push_lo_idx_raw_del,push_lo_pri_del, push_lo_prt_del})); 94 | 95 | 96 | 97 | reg [BITPIFO-1:0] pop_0_bmp_id; 98 | reg pop_0_bmp_hit; 99 | pop_pe_idx #(.NUMPIFO(NUMPIFO), .BITPORT(BITPORT)) pop_idx_inst (.port(oprt_0), .pf_port(pf_port), .pf_cnt(pf_cnt), .pop_idx(pop_0_bmp_id), .pop_hit(pop_0_bmp_hit)); 100 | 101 | reg [BITPIFO-1:0] push_1_bmp_id; 102 | push_pe_idx #(.NUMPIFO(NUMPIFO), .BITPRIO(BITPRIO)) push_1_idx_inst (.prio(upri_1), .pf_prio(pf_prio), .pf_cnt(pf_cnt), .push_idx(push_1_bmp_id)); 103 | 104 | reg [BITPIFO-1:0] push_2_bmp_id; 105 | push_pe_idx #(.NUMPIFO(NUMPIFO), .BITPRIO(BITPRIO)) push_2_idx_inst (.prio(upri_2), .pf_prio(pf_prio), .pf_cnt(pf_cnt), .push_idx(push_2_bmp_id)); 106 | 107 | reg pop_0_hit_tmp; 108 | reg [BITPIFO-1:0] pop_0_idx_tmp; 109 | always_comb begin 110 | pop_0_idx = pop_0_bmp_id; 111 | pop_0_hit_tmp = pop_0_bmp_hit; 112 | 113 | if(pop_0_hit_del && pop_0_idx > pop_0_idx_del) 114 | pop_0_idx = pop_0_idx -1; 115 | 116 | pop_0_idx_tmp = pop_0_idx; 117 | pop_0_idx = pop_0_idx + (push_1_del && pop_0_idx_tmp >= push_1_idx_raw_del) + (push_2_del && pop_0_idx_tmp >= push_2_idx_raw_del); 118 | 119 | if(push_hi_del && push_hi_prt_del==oprt_0) begin 120 | if(!pop_0_hit_tmp || push_hi_idx_raw_del <= pop_0_idx_tmp) begin 121 | pop_0_idx = push_hi_idx_del; 122 | pop_0_hit_tmp = 1; 123 | end 124 | end 125 | else if(push_lo_del && push_lo_prt_del==oprt_0 && (!pop_0_hit_tmp || push_lo_idx_raw_del <= pop_0_idx_tmp)) begin 126 | pop_0_idx = push_lo_idx_del; 127 | pop_0_hit_tmp = 1; 128 | end 129 | pop_0_hit = pop_0 && pop_0_hit_tmp; 130 | end 131 | 132 | always_comb begin 133 | push_1_idx = push_1_bmp_id; 134 | if(pop_0_hit_del && pop_0_idx_del < push_1_idx) 135 | push_1_idx = push_1_idx -1; 136 | push_1_idx = push_1_idx 137 | + (push_1_del && (push_1_idx_raw_del < push_1_idx || (push_1_idx_raw_del==push_1_idx && upri_1_del <= upri_1))) 138 | + (push_2_del && (push_2_idx_raw_del < push_1_idx || (push_2_idx_raw_del==push_1_idx && upri_2_del <= upri_1))); 139 | if(pop_0_hit && pop_0_idx < push_1_idx) 140 | push_1_idx = push_1_idx -1; 141 | 142 | push_1_idx_raw = push_1_idx; 143 | if(push_1 && push_2 && upri_2 < upri_1) 144 | push_1_idx = push_1_idx+1; 145 | end 146 | 147 | always_comb begin 148 | push_2_idx = push_2_bmp_id; 149 | if(pop_0_hit_del && pop_0_idx_del < push_2_idx) 150 | push_2_idx = push_2_idx -1; 151 | push_2_idx = push_2_idx 152 | + (push_1_del && (push_1_idx_raw_del < push_2_idx || (push_1_idx_raw_del==push_2_idx && upri_1_del <= upri_2))) 153 | + (push_2_del && (push_2_idx_raw_del < push_2_idx || (push_2_idx_raw_del==push_2_idx && upri_2_del <= upri_2))); 154 | if(pop_0_hit && pop_0_idx < push_2_idx) 155 | push_2_idx = push_2_idx -1; 156 | 157 | push_2_idx_raw = push_2_idx; 158 | if(push_1 && push_2 && upri_2 >= upri_1) 159 | push_2_idx = push_2_idx+1; 160 | end 161 | 162 | always_comb begin 163 | push_hi = push_1 || push_2; 164 | push_lo = push_1 && push_2; 165 | push_hi_idx = push_1_idx; 166 | push_lo_idx = push_2_idx; 167 | push_hi_idx_raw = push_1_idx_raw; 168 | push_lo_idx_raw = push_2_idx_raw; 169 | push_hi_pri = upri_1; 170 | push_lo_pri = upri_2; 171 | push_hi_prt = uprt_1; 172 | push_lo_prt = uprt_2; 173 | if((push_1 && push_2 && upri_2 < upri_1) || !push_1) begin 174 | push_hi_idx = push_2_idx; 175 | push_lo_idx = push_1_idx; 176 | push_hi_idx_raw = push_2_idx_raw; 177 | push_lo_idx_raw = push_1_idx_raw; 178 | push_hi_pri = upri_2; 179 | push_lo_pri = upri_1; 180 | push_hi_prt = uprt_2; 181 | push_lo_prt = uprt_1; 182 | end 183 | end 184 | 185 | always @(posedge clk) 186 | if(rst) 187 | pf_cnt <= 0; 188 | else 189 | pf_cnt <= pf_cnt - pop_0_hit_del + push_1_del + push_2_del; 190 | 191 | assign opri_0 = pf_prio[pop_0_idx_del]; 192 | assign odout_0 = pf_data[pop_0_idx_del]; 193 | assign ovld_0 = pop_0_hit_del; 194 | 195 | reg [NUMPIFO-1:0] pop_shift; 196 | always_comb 197 | for(integer unsigned i=0; i push_lo_idx_del && pv > 1; 208 | wire hi_move = push_hi_del && pv > push_hi_idx_del && pv > 0; 209 | wire po_move = pop_shift[pv]; 210 | wire shift_r1 = !pu1_set && !pu2_set && !lo_move && !hi_move && po_move; 211 | wire shift_l1 = !pu1_set && !pu2_set && ((pv>1 && lo_move && pop_shift[pv-2]) || (pv>0 && !lo_move && hi_move && !pop_shift[pv-1])); 212 | wire shift_l2 = !pu1_set && !pu2_set && (pv>1 && lo_move && !pop_shift[pv-2]); 213 | wire shift_no = !pu1_set && !pu2_set && !shift_r1 && !shift_l1 && !shift_l2; 214 | always_comb begin 215 | pf_data_nxt[pv] = '0; 216 | pf_prio_nxt[pv] = '0; 217 | pf_port_nxt[pv] = '0; 218 | if(pu1_set) begin 219 | pf_data_nxt[pv] = pf_data_nxt[pv] | udin_1_del; 220 | pf_prio_nxt[pv] = pf_prio_nxt[pv] | upri_1_del; 221 | pf_port_nxt[pv] = pf_port_nxt[pv] | uprt_1_del; 222 | end 223 | if(pu2_set) begin 224 | pf_data_nxt[pv] = pf_data_nxt[pv] | udin_2_del; 225 | pf_prio_nxt[pv] = pf_prio_nxt[pv] | upri_2_del; 226 | pf_port_nxt[pv] = pf_port_nxt[pv] | uprt_2_del; 227 | end 228 | if(shift_l2 && pv>1) begin 229 | pf_data_nxt[pv] = pf_data_nxt[pv] | pf_data[pv-2]; 230 | pf_prio_nxt[pv] = pf_prio_nxt[pv] | pf_prio[pv-2]; 231 | pf_port_nxt[pv] = pf_port_nxt[pv] | pf_port[pv-2]; 232 | end 233 | if(shift_l1 && pv>0) begin 234 | pf_data_nxt[pv] = pf_data_nxt[pv] | pf_data[pv-1]; 235 | pf_prio_nxt[pv] = pf_prio_nxt[pv] | pf_prio[pv-1]; 236 | pf_port_nxt[pv] = pf_port_nxt[pv] | pf_port[pv-1]; 237 | end 238 | if(shift_r1 && pv0) begin: flp_loop 277 | always @(posedge clk) 278 | din_reg[fdel_var] <= din_reg[fdel_var-1]; 279 | end else begin: nflp_loop 280 | always_comb 281 | din_reg[fdel_var] = din; 282 | end 283 | end 284 | endgenerate 285 | 286 | assign dout = din_reg[DELAY]; 287 | 288 | endmodule 289 | 290 | module priority_encode_log ( 291 | decode, 292 | encode, 293 | valid 294 | ); 295 | 296 | parameter width = 1024; 297 | parameter log_width = 10; 298 | 299 | localparam pot_width = 1 << log_width; 300 | 301 | input [width-1:0] decode; 302 | output [log_width-1:0] encode; 303 | output valid; 304 | 305 | wire [pot_width-1:0] pot_decode = {pot_width{1'b0}} | decode; 306 | 307 | reg [pot_width-1:0] part_idx [0:log_width-1]; 308 | 309 | always_comb begin 310 | part_idx[0] = 0; 311 | for(integer i=0; iprio); 366 | 367 | priority_encode_log #(.width(NUMPIFO), .log_width(BITPIFO)) push_pe (.decode(push_bmp), .encode(push_idx), .valid()); 368 | endmodule 369 | -------------------------------------------------------------------------------- /hardware/pifo/src/top.sv: -------------------------------------------------------------------------------- 1 | `timescale 1 ps / 1 ps 2 | 3 | module top ( 4 | input in_clk100, 5 | input cpu_resetn, 6 | output logic pifo_out 7 | ); 8 | 9 | wire rst, user_clk; 10 | assign rst = ~cpu_resetn; 11 | 12 | my_pll user_pll ( 13 | .rst (~cpu_resetn), 14 | .refclk (in_clk100), 15 | .locked (), 16 | .outclk_0 (user_clk) 17 | ); 18 | 19 | // Default values. 20 | // localparam NUMPIFO = 1024; // PIFO capacity. 21 | // localparam BITPORT = 8; // Number of bits to represent a logical PIFO. 22 | // localparam BITPRIO = 16; // Number of bits to represent priorities. 23 | // localparam BITDATA = 32; // Number of bits to represent data. 24 | // localparam PIFO_ID = 0; 25 | 26 | // Values from PANIC. 27 | // localparam NUMPIFO = 128; 28 | // localparam BITPORT = 1; 29 | // localparam BITPRIO = 8; 30 | // localparam BITDATA = $clog2(NUMPIFO); // PANIC uses an extra array to store 31 | // // the actual data. 32 | // localparam PIFO_ID = 0; 33 | 34 | // Using PANIC values by default as they are quicker to synthesize. 35 | `ifndef ELEMENT_BITS 36 | `define ELEMENT_BITS 7 37 | `endif // ELEMENT_BITS 38 | 39 | `ifndef PRIORITY_BITS 40 | `define PRIORITY_BITS 8 41 | `endif // PRIORITY_BITS 42 | 43 | localparam NUMPIFO = 2**(`ELEMENT_BITS); 44 | localparam BITPORT = 1; 45 | localparam BITPRIO = `PRIORITY_BITS; 46 | localparam BITDATA = $clog2(NUMPIFO); 47 | localparam PIFO_ID = 0; 48 | 49 | logic pop_0; 50 | logic [BITPORT-1:0] oprt_0; 51 | logic ovld_0; 52 | logic [BITPRIO-1:0] opri_0; 53 | logic [BITDATA-1:0] odout_0; 54 | 55 | logic push_1; 56 | logic [BITPORT-1:0] uprt_1; 57 | logic [BITPRIO-1:0] upri_1; 58 | logic [BITDATA-1:0] udin_1; 59 | logic push_1_drop; 60 | 61 | logic odrop_vld_0; 62 | logic [BITPRIO-1:0] odrop_pri_0; 63 | logic [BITDATA-1:0] odrop_dout_0; 64 | 65 | always_ff @(posedge user_clk) begin 66 | if (rst) begin 67 | pop_0 <= 0; 68 | oprt_0 <= 0; 69 | push_1 <= 0; 70 | uprt_1 <= 0; 71 | upri_1 <= 0; 72 | udin_1 <= 0; 73 | push_1_drop <= 0; 74 | end else begin 75 | pop_0 <= !pop_0; 76 | oprt_0 <= oprt_0 + 1; 77 | push_1 <= !push_1; 78 | uprt_1 <= uprt_1 + 1; 79 | upri_1 <= upri_1 + 1; 80 | udin_1 <= udin_1 + 1; 81 | push_1_drop <= !push_1_drop; 82 | end 83 | end 84 | 85 | logic [31:0] out_placeholder; 86 | logic pifo_out_r; 87 | 88 | // Make sure we use all the outputs 89 | always_comb begin 90 | out_placeholder = 0; 91 | out_placeholder ^= opri_0; 92 | out_placeholder ^= odout_0; 93 | out_placeholder ^= odrop_pri_0; 94 | out_placeholder ^= odrop_dout_0; 95 | 96 | pifo_out_r = ^out_placeholder ^ ovld_0 ^ odrop_vld_0; 97 | end 98 | 99 | always_ff @(posedge user_clk) begin 100 | pifo_out <= pifo_out_r; 101 | end 102 | 103 | pifo #( 104 | .NUMPIFO(NUMPIFO), 105 | .BITPORT(BITPORT), 106 | .BITPRIO(BITPRIO), 107 | .BITDATA(BITDATA) 108 | ) pifo_inst ( 109 | .clk (user_clk), 110 | .rst (rst), 111 | 112 | .pop_0 (pop_0), 113 | .oprt_0 (oprt_0), 114 | .ovld_0 (ovld_0), 115 | .opri_0 (opri_0), 116 | .odout_0 (odout_0), 117 | 118 | .push_1 (push_1), 119 | .uprt_1 (uprt_1), 120 | .upri_1 (upri_1), 121 | .udin_1 (udin_1), 122 | 123 | .push_2 (1'b0), 124 | .uprt_2 (), 125 | .upri_2 (), 126 | .udin_2 () 127 | ); 128 | 129 | // panic_pifo #( 130 | // .NUMPIFO(NUMPIFO), 131 | // .BITPORT(BITPORT), 132 | // .BITPRIO(BITPRIO), 133 | // .BITDATA(BITDATA), 134 | // .PIFO_ID(PIFO_ID) 135 | // ) pifo_inst ( 136 | // .clk (user_clk), 137 | // .rst (rst), 138 | 139 | // .pop_0 (pop_0), 140 | // .oprt_0 (oprt_0), 141 | // .ovld_0 (ovld_0), 142 | // .opri_0 (opri_0), 143 | // .odout_0 (odout_0), 144 | 145 | // .push_1 (push_1), 146 | // .uprt_1 (uprt_1), 147 | // .upri_1 (upri_1), 148 | // .udin_1 (udin_1), 149 | // .push_1_drop (push_1_drop), 150 | 151 | // .push_2 (1'b0), 152 | // .uprt_2 (), 153 | // .upri_2 (), 154 | // .udin_2 (), 155 | // .push_2_drop (1'b0), 156 | 157 | // .odrop_vld_0 (odrop_vld_0), 158 | // .odrop_pri_0 (odrop_pri_0), 159 | // .odrop_dout_0 (odrop_dout_0) 160 | // ); 161 | 162 | endmodule 163 | --------------------------------------------------------------------------------