Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
da36e1c
Copy vhdl_gen folder over to verilog_gen
JasmijnB Feb 6, 2026
33f4590
replace all vhdl_gen references to verilog_gen
JasmijnB Feb 6, 2026
837de11
rename VHDLContext to Context
JasmijnB Feb 6, 2026
0457764
Make arch variable a list instead of a string
JasmijnB Feb 9, 2026
acb68b1
Revert "Make arch variable a list instead of a string"
JasmijnB Feb 9, 2026
6880d2c
Add abstract emitter class and VHDLEmitter subclass
JasmijnB Feb 10, 2026
184def1
Change shifts to use emitter instead of context
JasmijnB Feb 10, 2026
956fa72
Adjust reduction to use Emitter instead of Context
JasmijnB Feb 10, 2026
3dd3f3f
change WrapSub to use emitter
JasmijnB Feb 10, 2026
42a260e
Adjust masking to use emitter
JasmijnB Feb 10, 2026
97c940c
Adjust Mux1HROM function to use Emitter
JasmijnB Feb 10, 2026
cebba71
Adjust "generate" function in GroupAllocator to use VHDLEmitter
JasmijnB Feb 10, 2026
38b95fe
change port init and completion string responsibility to emitter inst…
JasmijnB Feb 10, 2026
312469f
Change responsibility of register update writing to emitter from grou…
JasmijnB Feb 10, 2026
4110080
Initial VHDL-agnostic generation for the group_allocator
JasmijnB Feb 16, 2026
a31af16
Move responsibility of signal initiation implementation to the VHDL e…
JasmijnB Feb 16, 2026
cfce3b4
Make output file suffix decided by the emitter
JasmijnB Feb 16, 2026
bb622e4
Chance responsibility of formatting the when else to the emmitter
JasmijnB Feb 16, 2026
a475baf
Allow for custom indexing per emitter
JasmijnB Feb 16, 2026
4df5aa8
Make bit representation dependent on the Emitter class
JasmijnB Feb 16, 2026
e4c902f
Initial verilog emitter class
JasmijnB Feb 16, 2026
7658cad
Rewrite group allocator and vhdl emitter to allow for language-agnost…
JasmijnB Feb 17, 2026
e0dc349
Update get_definition_str to not print any register structure if ther…
JasmijnB Feb 17, 2026
70a39b5
Implement instantion code in verilog emitter
JasmijnB Feb 17, 2026
b27fcac
Add function to emitters to create new instance
JasmijnB Feb 17, 2026
8bfc08b
Remove all dependencies on Op from reduction.py
JasmijnB Feb 17, 2026
2215738
create separate __init__.py for emitter and move intermediate represe…
JasmijnB Feb 17, 2026
50290bf
rename the int_to_bin method to _int_to_bin and fix small equals sign…
JasmijnB Feb 17, 2026
11edfcd
Adjust mux to use language-agnostic emitters, add TODOs where this is…
JasmijnB Feb 17, 2026
cedc4d5
Modify conversions to use language-agnostic emitter
JasmijnB Feb 17, 2026
358ab04
Modify reduction to use language-agnostic emitter
JasmijnB Feb 17, 2026
5ef5583
Modify the dispatcher generate function to use language-agnostic emitter
JasmijnB Feb 17, 2026
83cb8db
convert dispatcher instantiation code to use emitter (not tested yet)
JasmijnB Feb 17, 2026
1a09d11
Modify qtp dispatcher generate to use emitter
JasmijnB Feb 17, 2026
5933606
rewrite instantiate in qtp dispatcher to use emitter (and fix a tiny …
JasmijnB Feb 17, 2026
e7bf18f
Move responsibility of mux index to emitters
JasmijnB Feb 18, 2026
73f310e
Fix use of Op in masking.py
JasmijnB Feb 18, 2026
e0df116
Fix conversions py wrong assignment calls
JasmijnB Feb 18, 2026
a34c366
Update arithmetic.py to use emitter
JasmijnB Feb 18, 2026
8997f54
Allow for custom size in Var representation
JasmijnB Feb 18, 2026
927b9be
Have VHDL emitter add line breaks in a when-else chain
JasmijnB Feb 18, 2026
09bd07e
Add rst and clk map in dispatcher instantiation
JasmijnB Feb 18, 2026
7765d7d
Remove unnecessary em parameter modification in group allocator
JasmijnB Feb 18, 2026
ab0a24c
Fix getnameread not indexing for the array vectors
JasmijnB Feb 18, 2026
9b43679
use context in lsq generator
JasmijnB Feb 18, 2026
96959aa
Use ctx library string
JasmijnB Feb 18, 2026
394d04e
Adjust lsq generator to use modern signals instead of util
JasmijnB Feb 18, 2026
a85e174
allow for custom reset and clock signal names
JasmijnB Feb 18, 2026
e78b866
allow for custom dynamatic compatible signal naming, not properly tes…
JasmijnB Feb 18, 2026
e60adaa
Allow for custom statements
JasmijnB Feb 20, 2026
e4021cf
Allow register type to be forced if necessary
JasmijnB Feb 20, 2026
0a2f12a
Fix bugs in verilog emitter, instantiation and register updating is c…
JasmijnB Feb 20, 2026
1964945
Update lsq and codegen to use emitter
JasmijnB Feb 20, 2026
bd1d819
update emitters to allow for later clock and reset name change
JasmijnB Feb 20, 2026
8bf2787
update lsq generator to use emitter
JasmijnB Feb 20, 2026
29aee01
Fix bug where pointers would only be instantiated when configured as …
JasmijnB Feb 20, 2026
ccfb874
modify genWrapperSlave function to use emitter
JasmijnB Feb 20, 2026
a73071e
Remove brackets for chained when-else as this is not valid vhdl syntax
JasmijnB Feb 23, 2026
72715ba
Fix invalid assigned value in dispatcher
JasmijnB Feb 23, 2026
4391fc2
Assign bits instead of values for single ' instead of "
JasmijnB Feb 23, 2026
898f6ca
change size parameter to more general Meta class to pass more informa…
JasmijnB Feb 23, 2026
aada031
allow for proper type checking of super statements such that values u…
JasmijnB Feb 23, 2026
a1c0261
fix wrong get definition string call in lsq
JasmijnB Feb 23, 2026
5d93151
change argument name for selecting hdl from "language" to "hdl"
JasmijnB Feb 23, 2026
721e02a
also allow other signal types to be forced as register
JasmijnB Feb 23, 2026
5d64142
remove assign string from assignments in a process
JasmijnB Feb 23, 2026
0e1fb22
initialise registers as register instead of wire
JasmijnB Feb 23, 2026
fe40ff1
add hdl flag to lsq generator configuration to force vhdl
JasmijnB Feb 24, 2026
b089457
add unmapped ports to lsq instantiation
JasmijnB Feb 24, 2026
cc88353
change rreq_id and wreq_id to wires instead of registers
JasmijnB Feb 24, 2026
6d95f66
have lsq generator write to correct file suffix
JasmijnB Feb 24, 2026
d9da6e6
change read logic entity to wire intead of register
JasmijnB Feb 24, 2026
43422a2
have correct neq character for vhdl
JasmijnB Feb 24, 2026
860a83f
always initialise registers
JasmijnB Feb 24, 2026
357c74a
Add BinOp.CONCAT back to vhdl emitter
JasmijnB Feb 24, 2026
66a4750
configure lsq generator call to emit verilog
JasmijnB Feb 24, 2026
68798b1
remove vhdl_gen directory
JasmijnB Feb 24, 2026
42f5f8e
Move "verilog_gen" to "core_gen"
JasmijnB Feb 24, 2026
5a2b7b4
remove unused classes and functions in utils
JasmijnB Feb 24, 2026
ad5a9ea
reformat using black
JasmijnB Feb 24, 2026
696a1de
make rreq_id and wreq_id in genWrapperSlave wires instead of registers
JasmijnB Mar 2, 2026
3b6156d
assign values instead of bits in genWrapperSlave
JasmijnB Mar 2, 2026
f8de20a
delete context as it is replaced by emitters
JasmijnB Mar 2, 2026
872da98
delete cli as it was never used
JasmijnB Mar 2, 2026
b136816
Remove Op from Ir as everything has been rewritten and it is not in u…
JasmijnB Mar 2, 2026
63b57ac
update README.md to match current implementation
JasmijnB Mar 2, 2026
4dfb59f
update readme.md
JasmijnB Mar 2, 2026
75a4333
Rename ctx to em and update documentation
JasmijnB Mar 2, 2026
aa54098
Update documentation to mention emitter instead of context
JasmijnB Mar 2, 2026
d237ffe
Update ir documentation
JasmijnB Mar 2, 2026
53027c1
Refactor emitter superclass to implement common functions and update …
JasmijnB Mar 2, 2026
5d5af7a
add helper function for binary reductions
JasmijnB Mar 23, 2026
57df7dc
fix default initial value for logicvec
JasmijnB Mar 25, 2026
fb5c54b
fix TEMP_GEN_MEM being a register, not allowing for allocation
JasmijnB Apr 30, 2026
9fef164
Fix var type of wreq_ready
JasmijnB Apr 30, 2026
fe1f89d
update syntax error in lsq.py
JasmijnB May 1, 2026
f05bca9
Update vhdl and verilog emitter to handle multi-line comments
JasmijnB May 26, 2026
2815002
Add bool_to_logic to vhdl emitter
JasmijnB May 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions data/rtl-config-verilog.json
Original file line number Diff line number Diff line change
Expand Up @@ -905,9 +905,9 @@
},
{
"name": "handshake.lsq",
"generator": "/usr/bin/env python3 $DYNAMATIC/tools/backend/lsq-generator-python/lsq-generator.py -o $OUTPUT_DIR -c $OUTPUT_DIR/$MODULE_NAME.json",
"generator": "/usr/bin/env python3 $DYNAMATIC/tools/backend/lsq-generator-python/lsq-generator.py -o $OUTPUT_DIR -c $OUTPUT_DIR/$MODULE_NAME.json --hdl verilog",
"use-json-config": "$OUTPUT_DIR/$MODULE_NAME.json",
"hdl": "vhdl",
"hdl": "verilog",
"io-kind": "flat",
"io-map": [{ "clk": "clock" }, { "rst": "reset" }, { "*": "io_*" }],
"io-signals": {
Expand Down
4 changes: 2 additions & 2 deletions data/rtl-config-vhdl.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
},
{
"name": "handshake.lsq",
"generator": "/usr/bin/env python3 $DYNAMATIC/tools/backend/lsq-generator-python/lsq-generator.py -o $OUTPUT_DIR -c $OUTPUT_DIR/$MODULE_NAME.json",
"generator": "/usr/bin/env python3 $DYNAMATIC/tools/backend/lsq-generator-python/lsq-generator.py -o $OUTPUT_DIR -c $OUTPUT_DIR/$MODULE_NAME.json --hdl vhdl",
"use-json-config": "$OUTPUT_DIR/$MODULE_NAME.json",
"hdl": "vhdl",
"io-kind": "flat",
Expand Down Expand Up @@ -374,7 +374,7 @@
},
{
"name": "handshake.lsq",
"generator": "/usr/bin/env python3 $DYNAMATIC/tools/backend/lsq-generator-python/lsq-generator.py -o $OUTPUT_DIR -c $OUTPUT_DIR/$MODULE_NAME.json",
"generator": "/usr/bin/env python3 $DYNAMATIC/tools/backend/lsq-generator-python/lsq-generator.py -o $OUTPUT_DIR -c $OUTPUT_DIR/$MODULE_NAME.json --hdl vhdl",
"use-json-config": "$OUTPUT_DIR/$MODULE_NAME.json",
"hdl": "vhdl",
"io-kind": "flat",
Expand Down
31 changes: 17 additions & 14 deletions tools/backend/lsq-generator-python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ This Python-based LSQ generator generates the LSQ design outlined in Hailin Wang
### Sampele usage

```
usage: lsq-generator.py [-h] [--output-dir OUTPUT_PATH] --config-file CONFIG_FILES
usage: lsq-generator.py [-h] [--output-dir OUTPUT_PATH] --config-file CONFIG_FILES --hdl [vhdl|verilog]
```

### Sample json configuration file (Example: Histogram)
Expand Down Expand Up @@ -89,31 +89,27 @@ Configuration parameters needed for both chisel and Python based LSQ-generator c
- **lsq-generator.py**
Runs the tool.

- **vhdl_gen/**
- **core_gen/**
- **\_\_init__.py**
Re-exports a curated list of public API symbols (e.g. `main`, `generate`, `Logic`, `LSQ`).

- **cli.py**
Parses command-line arguments (with `argparse`), converts them into a `Configs` instance, and calls the core generator.

- **codegen.py**
Implements the `codeGen(config: Configs)` function.

- **configs.py**
Defines the `Configs` class.

- **context.py**
Defines the `VHDLContext` class. It substitutes the previous `global` VHDL context variables.

- **utils.py**
- Defines `VHDLLogicType`, `VHDLLogicVecType`, `VHDLLogicTypeArray`, `VHDLLogicVecTypeArray`, `OpTab`.
- `IntToBits`, `Zero`, `GetValue`, `MaskLess`, `isPow2`, `log2Ceil` helper functions.
- Classes and functions need to be relocated into other files later.
- **ir.py**
Defines the intermediate representation used to generate HDL
Defines `Statement`, `Type`, `Val`, `BinOp`, `Bin`, `UnOp`, `Un`, `Bit`, `CustomStatement`, `WhenElse`.

- **signals.py**
Defines the four signal classes: `Logic`, `LogicVec`, `LogicArray`, `LogicVecArray`.

- **vhdlgen/operators/**
- **utils.py**
- Defines `GetValue`, `isPow2`, `log2Ceil` helper functions.

- **operators/**
Low-level functions that generate VHDL snippets:
- `assign.py`: `Op`
- `arithmetic.py`: `WrapAdd`, `WrapAddConst`, `WrapSub`
Expand All @@ -123,10 +119,17 @@ Configuration parameters needed for both chisel and Python based LSQ-generator c
- `reduction.py`: `ReduceLogicVec`, `ReduceLogicArray`, `ReduceLogicVecArray`, `Reduce`
- `shifts.py`: `RotateLogicVec`, `RotateLogicArray`, `RotateLogicVecArray`, `CyclicLeftShift`

- **vhdlgen/generators/**
- **generators/**
High-level modules that build complete entities/architectures:
- `dispatchers.py` : `PortToQueueDispatcher`, `QueueToPortDispatcher`, `PortToQueueDispatcherInit`, `QueueToPortDispatcherInit`
- `group_allocator.py` : `GroupAllocator`, `GroupAllocatorInit`
- `lsq.py` : `LSQ`

- **emitters/**
Emitters used to emit either VHDL or Verilog code.
- `emmitter.py` : Abstract class `Emitter`
- `verilog_emitter.py` : `VerilogEmitter`
- `vhdl_emitter.py` : `VHDLEmitter`



13 changes: 13 additions & 0 deletions tools/backend/lsq-generator-python/core_gen/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# core_gen/__init__.py
from core_gen.configs import GetConfigs, Configs
from core_gen.codegen import codeGen


# from vhdlgen import *
__all__ = [
# configs
"GetConfigs",
"Configs",
# codegen
"codeGen",
]
86 changes: 86 additions & 0 deletions tools/backend/lsq-generator-python/core_gen/codegen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
from core_gen.emitters import Emitter
import core_gen.generators.group_allocator as group_allocator
import core_gen.generators.dispatchers as dispatchers
import core_gen.generators.lsq as lsq

import core_gen.generators.lsq_submodule_wrapper as lsq_submodule_wrapper


def codeGen(emitter: Emitter, path_rtl, configs):
# Initialize a wrapper object to hold all submodule generator instances.
lsq_submodules = lsq_submodule_wrapper.LSQ_Submodules()

name = configs.name + "_core"
# empty the file
file = open(f"{path_rtl}/{name}.{emitter.get_file_suffix()}", "w").close()

# Group Allocator
ga = group_allocator.GroupAllocator(name=name, suffix="_ga", configs=configs)
ga.generate(emitter.new(), path_rtl)
lsq_submodules.group_allocator = ga

# When the condition "if configs.numLdPorts > 0:" is not true:
# Do not generating dispatching modules when there are zero load ports.
#
# - WARNING: This logic needs more testing
# - TODO: Also remove the load queue when there are zero load ports.
if configs.numLdPorts > 0:
# Load Address Port Dispatcher
ptq_dispatcher_lda = dispatchers.PortToQueueDispatcher(
name,
"_lda",
configs.numLdPorts,
configs.numLdqEntries,
configs.addrW,
configs.ldpAddrW,
)
ptq_dispatcher_lda.generate(emitter.new(), path_rtl)
lsq_submodules.ptq_dispatcher_lda = ptq_dispatcher_lda

# Load Data Port Dispatcher
qtp_dispatcher_ldd = dispatchers.QueueToPortDispatcher(
name,
"_ldd",
configs.numLdPorts,
configs.numLdqEntries,
configs.dataW,
configs.ldpAddrW,
)
qtp_dispatcher_ldd.generate(emitter.new(), path_rtl)
lsq_submodules.qtp_dispatcher_ldd = qtp_dispatcher_ldd

# Store Address Port Dispatcher
ptq_dispatcher_sta = dispatchers.PortToQueueDispatcher(
name,
"_sta",
configs.numStPorts,
configs.numStqEntries,
configs.addrW,
configs.stpAddrW,
)
ptq_dispatcher_sta.generate(emitter.new(), path_rtl)
lsq_submodules.ptq_dispatcher_sta = ptq_dispatcher_sta

# Store Data Port Dispatcher
ptq_dispatcher_std = dispatchers.PortToQueueDispatcher(
name,
"_std",
configs.numStPorts,
configs.numStqEntries,
configs.dataW,
configs.stpAddrW,
)
ptq_dispatcher_std.generate(emitter.new(), path_rtl)
lsq_submodules.ptq_dispatcher_std = ptq_dispatcher_std

# Store Backward Port Dispatcher
if configs.stResp:
qtp_dispatcher_stb = dispatchers.QueueToPortDispatcher(
name, "_stb", configs.numStPorts, configs.numStqEntries, 0, configs.stpAddrW
)
qtp_dispatcher_stb.generate(emitter.new(), path_rtl)
lsq_submodules.qtp_dispatcher_stb = qtp_dispatcher_stb

# Change the name of the following module to lsq_core
lsq_core = lsq.LSQ(name, "", configs)
lsq_core.generate(emitter, lsq_submodules, path_rtl)
134 changes: 134 additions & 0 deletions tools/backend/lsq-generator-python/core_gen/configs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#
# Dynamatic is under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#

import math
import json
import sys

# read and parse the json file
# example json format in README


def GetConfigs(config_json_path: str):
with open(config_json_path, "r") as file:
configString = file.read()
configs = json.loads(configString)
return Configs(configs)


class Configs:
"""
Configuration object for LSQ code generation.

This class is instantiated using 'GetConfigs(path_to_json_file)', which loads a JSON file
and overwrites all the values below using user-defined parameters.

The values shown below are NOT the actual values used during generation;
they are one of possible default configurations.
"""

name: str = "test" # Name prefix used for generated VHDL files
dataW: int = 16 # Data width (Number of bits for load/store data)
addrW: int = 13 # Address width (Number of bits for memory address)
idW: int = 2 # ID width (Number of bits for ID in the memory interface)
numLdqEntries: int = 3 # Load queue size (Number of entries in the load queue)
numStqEntries: int = 10 # Store queue size (Number of entries in the store queue)
numLdPorts: int = 3 # Number of load access ports
numStPorts: int = 3 # Number of store access ports
numGroups: int = 2 # Number of total Basic Blocks (BBs)
numLdMem: int = 1 # Number of load channels at memory interface (Fixed to 1)
numStMem: int = 1 # Number of store channels at memory interface (Fixed to 1)

gaNumLoads: list = [2, 1] # Number of loads in each BB
gaNumStores: list = [2, 1] # Number of stores in each BB
gaLdOrder: list = [
[2, 2], # The order matrix for each group
[0],
] # Outer list (Row): Index for each BB
# Inner list (Column): List of store counts ahead of each load
# In this example -> BB0=[st0,st1,ld0,ld1], BB1=[ld2,st2]
gaLdPortIdx: list = [
[0, 1], # The related access port index for each load in BB
[2],
]
gaStPortIdx: list = [
[0, 1], # The related access port index for each store in BB
[2],
]
ldqAddrW: int = 2 # Load queue address width
stqAddrW: int = 4 # Store queue address width
ldpAddrW: int = 2 # Load port address width
stpAddrW: int = 2 # Store port address width

pipe0: bool = False # Enable pipeline register 0
pipe1: bool = False # Enable pipeline register 1
pipeComp: bool = False # Enable pipeline register pipeComp
headLag: bool = False # Whether the head pointer of the load queue is updated
# one cycle later than the valid bits of entries
stResp: bool = (
False # Whether store response channel in store access port is enabled
)
gaMulti: bool = (
False # Whether multiple groups are allowed to request an allocation at the same cycle
)

def __init__(self, config: dict) -> None:
self.name = config["name"]
self.dataW = config["dataWidth"]
self.addrW = config["addrWidth"]
self.idW = config["indexWidth"]
self.numLdqEntries = config["fifoDepth_L"]
self.numStqEntries = config["fifoDepth_S"]
self.numLdPorts = config["numLoadPorts"]
self.numStPorts = config["numStorePorts"]
self.numGroups = config["numBBs"]
self.numLdMem = config["numLdChannels"]
self.numStMem = config["numStChannels"]
self.master = bool(config["master"])

self.stResp = bool(config["stResp"])
self.gaMulti = bool(config["groupMulti"])

self.gaNumLoads = config["numLoads"]
self.gaNumStores = config["numStores"]
self.gaLdOrder = config["ldOrder"]
self.gaLdPortIdx = config["ldPortIdx"]
self.gaStPortIdx = config["stPortIdx"]

self.ldqAddrW = math.ceil(math.log2(self.numLdqEntries))
self.stqAddrW = math.ceil(math.log2(self.numStqEntries))

# Original empty assignment assumes the size of load or store queue to be always a multiple of 2
if self.numLdqEntries & (self.numLdqEntries % 2 == 0):
self.emptyLdAddrW = math.ceil(math.log2(self.numLdqEntries + 1))
else:
self.emptyLdAddrW = math.ceil(math.log2(self.numLdqEntries)) + 1

if self.numStqEntries & (self.numStqEntries % 2 == 0):
self.emptyStAddrW = math.ceil(math.log2(self.numStqEntries + 1))
else:
self.emptyStAddrW = math.ceil(math.log2(self.numStqEntries)) + 1
# Check the number of ports, if num*Ports == 0, set it to 1
self.ldpAddrW = math.ceil(
math.log2(self.numLdPorts if self.numLdPorts > 0 else 1)
)
self.stpAddrW = math.ceil(
math.log2(self.numStPorts if self.numStPorts > 0 else 1)
)

self.pipe0 = bool(config["pipe0En"])
self.pipe1 = bool(config["pipe1En"])
self.pipeComp = bool(config["pipeCompEn"])
self.headLag = bool(config["headLagEn"])

assert self.idW >= self.ldqAddrW

# list size checking
assert len(self.gaNumLoads) == self.numGroups
assert len(self.gaNumStores) == self.numGroups
assert len(self.gaLdOrder) == self.numGroups
assert len(self.gaLdPortIdx) == self.numGroups
assert len(self.gaStPortIdx) == self.numGroups
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# core_gen/emitters/__init__.py
from core_gen.emitters.emitter import Emitter
from core_gen.emitters.vhdl_emitter import VHDLEmitter
from core_gen.emitters.verilog_emitter import VerilogEmitter

__all__ = ["Emitter", "VHDLEmitter", "VerilogEmitter"]
Loading