├── .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 |
--------------------------------------------------------------------------------