Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 8 additions & 3 deletions .github/workflows/regression.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,17 @@ jobs:

- name: Setup python
run: |
python3 -m venv --system-site-packages .efpga
. .efpga/bin/activate
python3 -m venv --system-site-packages .logik
. .logik/bin/activate
python3 -m pip install --upgrade pip
pip3 install -e .[test]

# Temporary
pip3 uninstall -y siliconcompiler
pip3 install siliconcompiler@git+https://github.com/siliconcompiler/siliconcompiler@main


- name: Run tests
run: |
. .efpga/bin/activate
. .logik/bin/activate
pytest
51 changes: 30 additions & 21 deletions examples/adder/adder.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,48 @@
# Copyright 2024 Zero ASIC Corporation
# Licensed under the MIT License (see LICENSE for details)

from siliconcompiler import Chip
import siliconcompiler

from logik.flows import logik_flow
from logiklib.demo.K4_N8_6x6 import K4_N8_6x6

from logik.demo import z1000


def hello_adder():
# 1. Create a Design object to hold source files and constraints.
design = siliconcompiler.Design('adder')

design.add_file('adder.v', fileset="rtl")
design.set_topmodule('adder', fileset="rtl")

# 2. Create an FPGA object
project = siliconcompiler.FPGA(design)

project.add_fileset('rtl')

# Create compilation object
chip = Chip('adder')
chip.create_cmdline(switchlist=['-remote'])
# 2. Create an FPGA object and associate the design with it.
fpga = z1000.z1000()

# Specify design sources
chip.input('adder.v')
# Enable command-line processing for options like -remote.
# fpga.create_cmdline(switchlist=['-remote']) # TODO

# Specify pin constraints
chip.input('adder.pcf')
# 3. Load the specific FPGA part, which also sets the default flow and libraries.
project.set_fpga(fpga)

# Compiler options
chip.set('option', 'quiet', True)
# 4. Use the specific flow for this build.
# Note: z1000 might already load a flow, but it's good practice to specify it.
project.set_flow(logik_flow.LogikFlow())

# Select target fpga
chip.set('fpga', 'partname', 'K4_N8_6x6')
# # 5. Set any general options.
project.set('option', 'quiet', True)

# Load target settings
chip.set('option', 'flow', 'logik_flow')
chip.use(logik_flow)
chip.use(K4_N8_6x6)
project.set('option', 'continue', True, step="place")

# Run compiler
chip.run()
# 6. Run the compilation.
project.run()

# Display compiler results
chip.summary()
# 7. Display the results summary.
project.summary()


if __name__ == "__main__":
Expand Down
66 changes: 36 additions & 30 deletions examples/eth_mac_1g/eth_mac_1g.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,56 +3,62 @@
# This is the logik run script for demonstrating RTL-to-bitstream
# with Alex Forencich's 1G Ethernet MAC

from siliconcompiler import Chip
import siliconcompiler
from logik.flows import logik_flow
from logiklib.zeroasic.z1000 import z1000
from logik.demo import z1000


def build():
chip = Chip('eth_mac_1g_wrapper')

# Load target settings
chip.use(logik_flow)
chip.use(z1000)
chip.set('option', 'flow', 'logik_flow')

# Set default part name
chip.set('fpga', 'partname', 'z1000')
design = siliconcompiler.Design('eth_mac_1g_wrapper')

# Define source files from verilog-ethernet repo

# First we need to register the verilog-ethernet repo
# as a package
chip.register_source(
name='verilog-ethernet',
path='git+https://github.com/alexforencich/verilog-ethernet.git',
ref='77320a9471d19c7dd383914bc049e02d9f4f1ffb')
design.set_dataroot(
'verilog-ethernet',
'git+https://github.com/alexforencich/verilog-ethernet.git',
'77320a9471d19c7dd383914bc049e02d9f4f1ffb')

# Then we can pull in the specific RTL we need from that
# repository -- Silicon Compiler will download and cache the files
# for us
for source_file in ('eth_mac_1g.v',
'axis_gmii_rx.v',
'axis_gmii_tx.v',
'lfsr.v'):
chip.input(f'rtl/{source_file}', package='verilog-ethernet')
with design.active_dataroot('verilog-ethernet'):
for source_file in ('eth_mac_1g.v',
'axis_gmii_rx.v',
'axis_gmii_tx.v',
'lfsr.v'):
design.add_file(f'rtl/{source_file}', fileset='rtl')

# Add in our top-level wrapper, stored locally
chip.register_source('ethmac_example', __file__)
chip.input('eth_mac_1g_wrapper.v', package='ethmac_example')
design.set_dataroot('ethmac_example', __file__)
with design.active_dataroot('ethmac_example'):
design.add_file('eth_mac_1g_wrapper.v', fileset='rtl')
design.set_topmodule("eth_mac_1g_wrapper", fileset="rtl")

# Add timing constraints
design.add_file('eth_mac_1g.sdc', fileset='sdc')

# Define pin constraints
design.add_file("constraints/z1000/pin_constraints.pcf",
fileset='pcf')

project = siliconcompiler.FPGA(design)

project.add_fileset('rtl')
project.add_fileset('sdc')
project.add_fileset('pcf')

# Add timing constraints
chip.input('eth_mac_1g.sdc', package='ethmac_example')
fpga = z1000.z1000()

# Define pin constraints
chip.input(f"constraints/{chip.get('fpga', 'partname')}/pin_constraints.pcf",
package='ethmac_example')
project.set_fpga(fpga)

project.set_flow(logik_flow.LogikFlow())
# Customize steps for this design
chip.set('option', 'quiet', True)
project.set('option', 'quiet', True)

chip.run()
chip.summary()
project.run()
project.summary()


if __name__ == '__main__':
Expand Down
45 changes: 45 additions & 0 deletions logik/demo/z1000.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Copyright 2024 Zero ASIC Corporation

from logik.devices.logik_fpga import LogikFPGA


# ####################################################
# # Setup for z1000 FPGA
# ####################################################

class z1000(LogikFPGA):
'''
Logik driver for z1000
'''
def __init__(self):
super().__init__()
part_name = "z1000"
self.set_name(part_name)

self.define_tool_parameter('convert_bitstream', 'bitstream_map', 'file',
'map for fasm->bitstream conversion')

self.set_dataroot(
part_name, f"github://siliconcompiler/logiklib/v0.1.0/{part_name}_cad.tar.gz", "0.1.0")

self.package.set_vendor("ZeroASIC")
self.set_lutsize(4)

self.add_yosys_registertype(["dff", "dffr", "dffe", "dffer"])
self.add_yosys_featureset(["async_reset", "enable"])
with self.active_dataroot(part_name):
self.set_yosys_flipfloptechmap("techlib/tech_flops.v")

self.set_vpr_devicecode(part_name)
self.set_vpr_clockmodel("route")
self.set_vpr_channelwidth(50)
self.add_vpr_registertype(["dff", "dffr", "dffe", "dffer"])
with self.active_dataroot(part_name):
self.set_vpr_archfile("cad/z1000.xml")
self.set_vpr_graphfile("cad/z1000_rr_graph.xml")
self.set_vpr_constraintsmap("cad/z1000_constraint_map.json")

with self.active_dataroot(part_name):
self.set_convert_bitstream_bitstream_map('cad/z1000_bitstream_map.json')

self.set_vpr_router_lookahead("classic")
Empty file added logik/devices/__init__.py
Empty file.
15 changes: 15 additions & 0 deletions logik/devices/logik_fpga.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from siliconcompiler.tools.vpr import VPRFPGA
from siliconcompiler.tools.yosys import YosysFPGA
from siliconcompiler.tools.opensta import OpenSTAFPGA


class LogikFPGA(YosysFPGA, VPRFPGA, OpenSTAFPGA):
'''
Class for logik FPGA devices
'''
def __init__(self):
super().__init__()

def set_convert_bitstream_bitstream_map(self, file: str, dataroot: str = None):
with self.active_dataroot(self._get_active_dataroot(dataroot)):
return self.set("tool", "convert_bitstream", "bitstream_map", file)
45 changes: 23 additions & 22 deletions logik/flows/logik_flow.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,39 @@
# Copyright 2024 Zero ASIC Corporation
# Licensed under the MIT License (see LICENSE for details)

from siliconcompiler import Chip
from siliconcompiler.flows import fpgaflow

from logik.tools.fasm_to_bitstream import bitstream_finish


############################################################################
# DOCS
############################################################################
def make_docs(chip):
return setup()
class LogikFlow(fpgaflow.FPGAVPRFlow):
'''An open-source FPGA flow using Yosys, VPR, and GenFasm.

This flow is designed for academic and research FPGAs, utilizing VPR
(Versatile Place and Route) for placement and routing.

############################################################################
# Flowgraph Setup
############################################################################
def setup(flowname='logik_flow'):
'''
'''
The flow consists of the following steps:

flow = fpgaflow.setup(
flowname=flowname,
fpgaflow_type='vpr')
* **elaborate**: Elaborate the RTL design from sources.
* **synthesis**: Synthesize the elaborated design into a netlist using Yosys.
* **place**: Place the netlist components onto the FPGA architecture using VPR.
* **route**: Route the connections between placed components using VPR.
* **bitstream**: Generate the final bitstream using GenFasm.
* **convert_bitstream**: Format bitstream from fasm to bits.
'''
def __init__(self, name: str = "logik_flow"):
"""
Initializes the FPGAVPRFlow.

# Add bitstream generation task
flow.node(flowname, 'convert_bitstream', bitstream_finish)
flow.edge(flowname, 'bitstream', 'convert_bitstream')
Args:
name (str): The name of the flow.
"""
super().__init__(name)

return flow
self.node("convert_bitstream", bitstream_finish.BitstreamFinishTask())
self.edge("bitstream", "convert_bitstream")


##################################################
# ##################################################
if __name__ == "__main__":
flow = make_docs(Chip('<flow>'))
flow.write_flowgraph(f"{flow.top()}.png", flow=flow.top(), landscape=True)
LogikFlow().write_flowgraph(f"{LogikFlow().name}.png")
67 changes: 32 additions & 35 deletions logik/tools/fasm_to_bitstream/bitstream_finish.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,51 @@

from logik.tools.fasm_to_bitstream import \
fasm_to_bitstream as fasm_utils
from siliconcompiler.tools._common import get_tool_task
from siliconcompiler import SiliconCompilerError

from siliconcompiler.tool import Task

def setup(chip):
'''
Perform bitstream finishing
'''

tool = 'fasm_to_bitstream'
step = chip.get('arg', 'step')
index = chip.get('arg', 'index')
_, task = get_tool_task(chip, step, index)
class BitstreamFinishTask(Task):
def __init__(self):
super().__init__()

part_name = chip.get('fpga', 'partname')
def tool(self):
return "fasm_to_bitstream"

# Require that a lut size is set for FPGA scripts.
chip.add('tool', tool, 'task', task, 'require',
",".join(['fpga', part_name, 'file', 'bitstream_map']),
step=step, index=index)
def task(self):
return "bitstream_finish"

chip.add('tool', tool, 'task', task, 'input', f'{chip.top()}.fasm', step=step, index=index)
chip.add('tool', tool, 'task', task, 'output', f'{chip.top()}.json', step=step, index=index)
chip.add('tool', tool, 'task', task, 'output', f'{chip.top()}.bin', step=step, index=index)
def setup(self):
'''
Perform bitstream finishing
'''
super().setup()

fpga = self.project.get('fpga', 'device')
fpga_obj = self.project.get('library', fpga, field='schema')
# dd_required_key(...) you can pass in an object the fpga and then finish the keypath
# but this will need to be "tool", "???", "bitstream_map"
self.add_required_key(fpga_obj, "tool", 'convert_bitstream', 'bitstream_map')

def run(chip):
part_name = chip.get('fpga', 'partname')
self.add_input_file(ext="fasm")
self.add_output_file(ext="json")
self.add_output_file(ext="bin")

topmodule = chip.top()
fasm_file = f"inputs/{topmodule}.fasm"
def run(self):
fpga = self.project.get('fpga', 'device')
fpga_obj = self.project.get('library', fpga, field='schema')

bitstream_maps = chip.find_files('fpga', part_name, 'file', 'bitstream_map')
# topmodule = self.top()
fasm_file = f"inputs/{self.design_topmodule}.fasm"

if len(bitstream_maps) == 1:
json_outfile = f"outputs/{topmodule}.json"
binary_outfile = f"outputs/{topmodule}.bin"
bitstream_map = fpga_obj.find_files("tool", 'convert_bitstream', 'bitstream_map')

json_outfile = f"outputs/{self.design_topmodule}.json"
binary_outfile = f"outputs/{self.design_topmodule}.bin"

# Finishing steps are as follows:
# 1. Convert FASM to IR
config_bitstream = fasm_utils.fasm2bitstream(fasm_file, bitstream_maps[0])
config_bitstream = fasm_utils.fasm2bitstream(fasm_file, bitstream_map)

# 2. Write IR to JSON for inspection purposes
fasm_utils.write_bitstream_json(config_bitstream, json_outfile)
Expand All @@ -57,11 +61,4 @@ def run(chip):
# 5. Write binary to file
fasm_utils.write_bitstream_binary(binary_bitstream, binary_outfile)

elif len(bitstream_maps) == 0:
raise SiliconCompilerError(
"fasm_to_bitstream requires a bitstream map file", chip=chip)
else:
raise SiliconCompilerError(
"Only one bitstream map file can be passed to fasm_to_bitstream", chip=chip)

return 0
return 0
Loading