Merge pull request #637 from antmicro/umarcor/lattice
f4pga/flows: support ice40
This commit is contained in:
commit
ebf85baba5
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"default_part": "ICE40UP5K-UWG30",
|
||||||
|
"values": {
|
||||||
|
"top": "top",
|
||||||
|
"extra_args": ["-D", "PVT=1"]
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"sources": [
|
||||||
|
"blink.v"
|
||||||
|
],
|
||||||
|
"synth_log": "synth.log",
|
||||||
|
"nextpnr_log": "nextpnr.log"
|
||||||
|
},
|
||||||
|
"ICE40UP5K-UWG30": {
|
||||||
|
"default_target": "bitstream",
|
||||||
|
"dependencies": {
|
||||||
|
"build_dir": "build",
|
||||||
|
"pcf": "../../../pcf/fomu-pvt.pcf"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -189,6 +189,47 @@ jobs:
|
||||||
path: f4pga-examples/${{ matrix.fam }}/btn_counter/build/top.bit
|
path: f4pga-examples/${{ matrix.fam }}/btn_counter/build/top.bit
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
|
Lattice:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: '🚦 Lattice | ice40'
|
||||||
|
env:
|
||||||
|
F4PGA_INSTALL_DIR: /usr/local
|
||||||
|
FPGA_FAM: ice40
|
||||||
|
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: 🧰 Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: 🛠️ Clone fomu-workshop
|
||||||
|
run: git clone https://github.com/im-tomu/fomu-workshop
|
||||||
|
|
||||||
|
- name: 🚧 [F4PGA] Test f4pga build
|
||||||
|
run: |
|
||||||
|
cat > ice40-test.sh <<'EOF'
|
||||||
|
set -e
|
||||||
|
apt-get update -qq
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends python3-pip git
|
||||||
|
|
||||||
|
pip install ./f4pga
|
||||||
|
|
||||||
|
cd fomu-workshop/hdl/verilog/blink
|
||||||
|
f4pga -vv build --flow ../../../../.github/ice40_test.json
|
||||||
|
EOF
|
||||||
|
|
||||||
|
docker run --rm -i \
|
||||||
|
-v $(pwd):/wrk -w /wrk \
|
||||||
|
-e FPGA_FAM=ice40 \
|
||||||
|
gcr.io/hdl-containers/impl/icestorm \
|
||||||
|
bash -le /wrk/ice40-test.sh
|
||||||
|
|
||||||
|
- name: '📤 Upload artifact: ice40 bitstream'
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: Lattice-ice40-Bitstream
|
||||||
|
path: fomu-workshop/hdl/verilog/blink/build/top.bit
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
|
||||||
Python-Tests:
|
Python-Tests:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
|
@ -22,7 +22,7 @@ from os import environ
|
||||||
|
|
||||||
|
|
||||||
FPGA_FAM = environ.get("FPGA_FAM", "xc7")
|
FPGA_FAM = environ.get("FPGA_FAM", "xc7")
|
||||||
if FPGA_FAM not in ["xc7", "eos-s3", "qlf_k4n8"]:
|
if FPGA_FAM not in ["xc7", "eos-s3", "qlf_k4n8", "ice40"]:
|
||||||
raise (Exception(f"Unsupported FPGA_FAM <{FPGA_FAM}>!"))
|
raise (Exception(f"Unsupported FPGA_FAM <{FPGA_FAM}>!"))
|
||||||
|
|
||||||
F4PGA_DEBUG = environ.get("F4PGA_DEBUG")
|
F4PGA_DEBUG = environ.get("F4PGA_DEBUG")
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
from sys import exit as sys_exit
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from os import environ
|
from os import environ
|
||||||
|
@ -115,7 +116,7 @@ def f4pga_fail():
|
||||||
|
|
||||||
def f4pga_done():
|
def f4pga_done():
|
||||||
sfprint(1, f"f4pga: {f4pga_done_str}" f"{Style.RESET_ALL + Fore.RESET}")
|
sfprint(1, f"f4pga: {f4pga_done_str}" f"{Style.RESET_ALL + Fore.RESET}")
|
||||||
exit(0)
|
sys_exit(0 if "FAILED" not in f4pga_done_str else 1)
|
||||||
|
|
||||||
|
|
||||||
def setup_resolution_env():
|
def setup_resolution_env():
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (C) 2022 F4PGA Authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
from f4pga.flows.common import ResolutionEnv, get_verbosity_level, sub as common_sub
|
||||||
|
from f4pga.flows.module import Module, ModuleContext
|
||||||
|
|
||||||
|
|
||||||
|
class NextPnrBaseModule(Module):
|
||||||
|
nextpnr_variant: str
|
||||||
|
extra_nextpnr_opts: "list[str]"
|
||||||
|
nextpnr_log_name: "str | None"
|
||||||
|
use_interchange: bool
|
||||||
|
|
||||||
|
def map_io(self, ctx: ModuleContext) -> "dict[str, ]":
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def execute(self, ctx: ModuleContext):
|
||||||
|
nextpnr_cmd = f"nextpnr-{self.nextpnr_variant}"
|
||||||
|
|
||||||
|
nextpnr_opts = [
|
||||||
|
"--top",
|
||||||
|
ctx.values.top,
|
||||||
|
"--placer",
|
||||||
|
ctx.values.placer,
|
||||||
|
"--router",
|
||||||
|
ctx.values.router,
|
||||||
|
]
|
||||||
|
|
||||||
|
if self.use_interchange:
|
||||||
|
nextpnr_opts += ["--netlist", ctx.takes.ic_logical_netlist]
|
||||||
|
else:
|
||||||
|
nextpnr_opts += ["--json", ctx.takes.json]
|
||||||
|
|
||||||
|
if ctx.values.prepack_script is not None:
|
||||||
|
nextpnr_opts += ["--pre-pack", ctx.values.prepack_script]
|
||||||
|
if ctx.values.preplace_script is not None:
|
||||||
|
nextpnr_opts += ["--pre-place", ctx.values.preplace_script]
|
||||||
|
if ctx.values.preroute_script is not None:
|
||||||
|
nextpnr_opts += ["--pre-route", ctx.values.preroute_script]
|
||||||
|
if ctx.values.postroute_script is not None:
|
||||||
|
nextpnr_opts += ["--post-poute", ctx.values.postroute_script]
|
||||||
|
if ctx.values.fail_script is not None:
|
||||||
|
nextpnr_opts += ["--on-fail", ctx.values.fail_script]
|
||||||
|
|
||||||
|
if ctx.values.thread_count:
|
||||||
|
nextpnr_opts += ["--threads", ctx.values.thread_count]
|
||||||
|
if ctx.values.parallel:
|
||||||
|
nextpnr_opts += ["--parallel-refine"]
|
||||||
|
|
||||||
|
nextpnr_opts += self.extra_nextpnr_opts
|
||||||
|
|
||||||
|
if get_verbosity_level() >= 2:
|
||||||
|
yield "Place-and-routing with nextpnr...\n " f'{nextpnr_cmd} {" ".join(nextpnr_opts)}'
|
||||||
|
else:
|
||||||
|
yield "Place-and-routing with nextpnr..."
|
||||||
|
|
||||||
|
res = common_sub(nextpnr_cmd, *nextpnr_opts)
|
||||||
|
|
||||||
|
yield "Saving log..."
|
||||||
|
log_path = getattr(ctx.outputs, self.nextpnr_log_name)
|
||||||
|
if log_path is not None:
|
||||||
|
with open(log_path, "w") as f:
|
||||||
|
f.write(res.decode())
|
||||||
|
|
||||||
|
def __init__(self, params: "dict[str, ]", interchange=False):
|
||||||
|
super().__init__(params)
|
||||||
|
self.name = "nextpnr"
|
||||||
|
self.nextpnr_variant = "unknown"
|
||||||
|
self.extra_nextpnr_opts = []
|
||||||
|
|
||||||
|
self.no_of_phases = 2
|
||||||
|
self.use_interchange = interchange
|
||||||
|
|
||||||
|
self.takes = ["ic_logical_netlist"] if self.use_interchange else ["json"]
|
||||||
|
|
||||||
|
self.values = [
|
||||||
|
"top",
|
||||||
|
"placer",
|
||||||
|
"router",
|
||||||
|
"prepack_script?",
|
||||||
|
"preplace_script?",
|
||||||
|
"preroute_script?",
|
||||||
|
"postroute_script?",
|
||||||
|
"fail_script?",
|
||||||
|
"thread_count?",
|
||||||
|
"parallel?",
|
||||||
|
]
|
||||||
|
|
||||||
|
self.nextpnr_log_name = f"nextpnr_log"
|
||||||
|
|
||||||
|
self.produces = [f"{self.nextpnr_log_name}!"]
|
|
@ -0,0 +1,74 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (C) 2022 F4PGA Authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
import pathlib
|
||||||
|
from f4pga.flows.common import ResolutionEnv
|
||||||
|
from f4pga.flows.module import ModuleContext
|
||||||
|
from f4pga.flows.common_modules.nextpnr import NextPnrBaseModule
|
||||||
|
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
class Ice40ChipInfo:
|
||||||
|
subfamily: str
|
||||||
|
size: str
|
||||||
|
package_code: str
|
||||||
|
|
||||||
|
def __init__(self, part_name: str):
|
||||||
|
m = re.match("ICE40([A-Z]*)([0-9]+[A-Z]?)-([A-Z0-9]*)$", part_name.upper())
|
||||||
|
assert m is not None
|
||||||
|
|
||||||
|
self.subfamily = m.group(1)
|
||||||
|
self.size = m.group(2)
|
||||||
|
self.package_code = m.group(3)
|
||||||
|
|
||||||
|
|
||||||
|
class NextPnrModule(NextPnrBaseModule):
|
||||||
|
def map_io(self, ctx: ModuleContext) -> "dict[str, ]":
|
||||||
|
return {"ice_asm": str(Path(ctx.takes.json).with_suffix(".ice"))}
|
||||||
|
|
||||||
|
def execute(self, ctx: ModuleContext):
|
||||||
|
chip_info = Ice40ChipInfo(ctx.values.part_name)
|
||||||
|
|
||||||
|
self.extra_nextpnr_opts = [
|
||||||
|
f"--{(chip_info.subfamily + chip_info.size).lower()}",
|
||||||
|
f"--package",
|
||||||
|
chip_info.package_code.lower(),
|
||||||
|
f"--asc",
|
||||||
|
ctx.outputs.ice_asm,
|
||||||
|
]
|
||||||
|
|
||||||
|
if ctx.takes.pcf is not None:
|
||||||
|
self.extra_nextpnr_opts += ["--pcf", ctx.takes.pcf]
|
||||||
|
else:
|
||||||
|
self.extra_nextpnr_opts += ["--pcf-allow-unconstrained"]
|
||||||
|
|
||||||
|
return super().execute(ctx)
|
||||||
|
|
||||||
|
def __init__(self, params: "dict[str, ]"):
|
||||||
|
super().__init__(params, interchange=False)
|
||||||
|
self.name = "nextpnr-ice40"
|
||||||
|
self.nextpnr_variant = "ice40"
|
||||||
|
self.takes += ["pcf?"]
|
||||||
|
self.values += ["part_name"]
|
||||||
|
self.produces += ["ice_asm"]
|
||||||
|
|
||||||
|
|
||||||
|
ModuleClass = NextPnrModule
|
|
@ -20,12 +20,13 @@
|
||||||
from os import environ
|
from os import environ
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from f4pga.context import FPGA_FAM
|
||||||
from f4pga.flows.common import decompose_depname, get_verbosity_level, sub as common_sub
|
from f4pga.flows.common import decompose_depname, get_verbosity_level, sub as common_sub
|
||||||
from f4pga.flows.module import Module, ModuleContext
|
from f4pga.flows.module import Module, ModuleContext
|
||||||
from f4pga.wrappers.tcl import get_script_path as get_tcl_wrapper_path
|
from f4pga.wrappers.tcl import get_script_path as get_tcl_wrapper_path
|
||||||
|
|
||||||
|
|
||||||
class SynthModule(Module):
|
class YosysModule(Module):
|
||||||
extra_products: "list[str]"
|
extra_products: "list[str]"
|
||||||
|
|
||||||
def map_io(self, ctx: ModuleContext):
|
def map_io(self, ctx: ModuleContext):
|
||||||
|
@ -69,35 +70,52 @@ class SynthModule(Module):
|
||||||
|
|
||||||
# Execute YOSYS command
|
# Execute YOSYS command
|
||||||
args_str = "" if ctx.values.read_verilog_args is None else " ".join(ctx.values.read_verilog_args)
|
args_str = "" if ctx.values.read_verilog_args is None else " ".join(ctx.values.read_verilog_args)
|
||||||
|
|
||||||
|
extra_args = ["-l", ctx.outputs.synth_log] if ctx.outputs.synth_log else []
|
||||||
|
if ctx.values.extra_args is not None:
|
||||||
|
extra_args.extend(ctx.values.extra_args)
|
||||||
|
|
||||||
common_sub(
|
common_sub(
|
||||||
*(
|
*(
|
||||||
[
|
["yosys"]
|
||||||
"yosys",
|
+ extra_args
|
||||||
|
+ [
|
||||||
"-p",
|
"-p",
|
||||||
(
|
(
|
||||||
" ".join([f"read_verilog {args_str} {vfile};" for vfile in ctx.takes.sources])
|
" ".join([f"read_verilog {args_str} {vfile};" for vfile in ctx.takes.sources])
|
||||||
+ f" tcl {str(get_tcl_wrapper_path())}"
|
+ f" tcl {str(get_tcl_wrapper_path(pnrtool=self.pnrtool))}"
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
+ (["-l", ctx.outputs.synth_log] if ctx.outputs.synth_log else [])
|
|
||||||
),
|
),
|
||||||
env=env,
|
env=env,
|
||||||
)
|
)
|
||||||
|
|
||||||
if not Path(ctx.produces.fasm_extra).is_file():
|
if self.pnrtool == "vpr":
|
||||||
with Path(ctx.produces.fasm_extra).open("w") as wfptr:
|
if not Path(ctx.produces.fasm_extra).is_file():
|
||||||
wfptr.write("")
|
with Path(ctx.produces.fasm_extra).open("w") as wfptr:
|
||||||
|
wfptr.write("")
|
||||||
|
|
||||||
def __init__(self, params):
|
def __init__(self, params):
|
||||||
self.name = "synthesize"
|
self.name = "yosys"
|
||||||
self.no_of_phases = 3
|
self.no_of_phases = 3
|
||||||
|
|
||||||
|
self.pnrtool = "nextpnr" if FPGA_FAM == "ice40" else "vpr"
|
||||||
|
|
||||||
self.takes = ["sources", "build_dir?"]
|
self.takes = ["sources", "build_dir?"]
|
||||||
# Extra takes for use with TCL scripts
|
# Extra takes for use with TCL scripts
|
||||||
extra_takes = params.get("takes")
|
extra_takes = params.get("takes")
|
||||||
if extra_takes:
|
if extra_takes:
|
||||||
self.takes += extra_takes
|
self.takes += extra_takes
|
||||||
|
|
||||||
self.produces = ["eblif", "fasm_extra", "json", "synth_json", "synth_log!"]
|
self.produces = ["json", "synth_log!"]
|
||||||
|
if self.pnrtool == "vpr":
|
||||||
|
self.produces.extend(
|
||||||
|
[
|
||||||
|
"eblif",
|
||||||
|
"fasm_extra",
|
||||||
|
"synth_json",
|
||||||
|
]
|
||||||
|
)
|
||||||
# Extra products for use with TCL scripts
|
# Extra products for use with TCL scripts
|
||||||
extra_products = params.get("produces")
|
extra_products = params.get("produces")
|
||||||
if extra_products:
|
if extra_products:
|
||||||
|
@ -106,7 +124,14 @@ class SynthModule(Module):
|
||||||
else:
|
else:
|
||||||
self.extra_products = []
|
self.extra_products = []
|
||||||
|
|
||||||
self.values = ["top", "device", "tcl_scripts", "yosys_tcl_env?", "read_verilog_args?"]
|
self.values = [
|
||||||
|
"top",
|
||||||
|
"device",
|
||||||
|
"tcl_scripts?",
|
||||||
|
"extra_args?",
|
||||||
|
"yosys_tcl_env?",
|
||||||
|
"read_verilog_args?",
|
||||||
|
]
|
||||||
self.prod_meta = {
|
self.prod_meta = {
|
||||||
"eblif": "Extended BLIF hierarchical sequential designs file\n" "generated by YOSYS",
|
"eblif": "Extended BLIF hierarchical sequential designs file\n" "generated by YOSYS",
|
||||||
"json": "JSON file containing a design generated by YOSYS",
|
"json": "JSON file containing a design generated by YOSYS",
|
||||||
|
@ -120,4 +145,4 @@ class SynthModule(Module):
|
||||||
self.prod_meta.update(extra_meta)
|
self.prod_meta.update(extra_meta)
|
||||||
|
|
||||||
|
|
||||||
ModuleClass = SynthModule
|
ModuleClass = YosysModule
|
|
@ -45,3 +45,52 @@ ql-k4n8_slow:
|
||||||
|
|
||||||
ql-k4n8_fast:
|
ql-k4n8_fast:
|
||||||
- K4N8_FAST
|
- K4N8_FAST
|
||||||
|
|
||||||
|
ice40:
|
||||||
|
- ICE40LP1K-CB121
|
||||||
|
- ICE40LP1K-CB81
|
||||||
|
- ICE40LP4K-CM225
|
||||||
|
- ICE40LP8K-CM225
|
||||||
|
- ICE40LP1K-CM121
|
||||||
|
- ICE40LP4K-CM121
|
||||||
|
- ICE40LP8K-CM121
|
||||||
|
- ICE40LP384-CM36
|
||||||
|
- ICE40LP1K-CM36
|
||||||
|
- ICE40LP384-CM49
|
||||||
|
- ICE40LP1K-CM49
|
||||||
|
- ICE40LP1K-CM81
|
||||||
|
- ICE40LP4K-CM81
|
||||||
|
- ICE40LP8K-CM81
|
||||||
|
- ICE40LP1K-QN84
|
||||||
|
- ICE40LP384-SG32
|
||||||
|
- ICE40LP640-SWG16
|
||||||
|
- ICE40LP1K-SWG16
|
||||||
|
- ICE40LP384-VQ100
|
||||||
|
- ICE40LP640-VQ100
|
||||||
|
- ICE40LP1K-VQ100
|
||||||
|
- ICE40LP4K-VQ100
|
||||||
|
- ICE40LP8K-VQ100
|
||||||
|
- ICE40HX1K-CB132
|
||||||
|
- ICE40HX4K-CB132
|
||||||
|
- ICE40HX8K-CB132
|
||||||
|
- ICE40HX1K-VQ100
|
||||||
|
- ICE40HX1K-TQ144
|
||||||
|
- ICE40HX4K-TQ144
|
||||||
|
- ICE40HX8K-CM225
|
||||||
|
- ICE40HX8K-CT256
|
||||||
|
- ICE40UP3K-UWG30
|
||||||
|
- ICE40UP3K-SG48
|
||||||
|
- ICE40UP5K-UWG30
|
||||||
|
- ICE40UP5K-SG48
|
||||||
|
- ICE40UL640-SWG16
|
||||||
|
- ICE40UL640-CM36
|
||||||
|
- ICE40UL1K-CM36
|
||||||
|
- ICE5LP1K-SWG36
|
||||||
|
- ICE5LP2K-SWG36
|
||||||
|
- ICE5LP4K-SWG36
|
||||||
|
- ICE5LP1K-CM36
|
||||||
|
- ICE5LP2K-CM36
|
||||||
|
- ICE5LP4K-CM36
|
||||||
|
- ICE5LP1K-SG48
|
||||||
|
- ICE5LP2K-SG48
|
||||||
|
- ICE5LP4K-SG4
|
||||||
|
|
|
@ -59,7 +59,7 @@ xc7a50t: &xc7
|
||||||
params:
|
params:
|
||||||
build_dir: 'build/${device}'
|
build_dir: 'build/${device}'
|
||||||
synth:
|
synth:
|
||||||
module: 'common:synth'
|
module: 'common:yosys'
|
||||||
params:
|
params:
|
||||||
takes:
|
takes:
|
||||||
- xdc?
|
- xdc?
|
||||||
|
@ -180,6 +180,47 @@ xc7a200t:
|
||||||
vpr_options: *xc7-vpr_options
|
vpr_options: *xc7-vpr_options
|
||||||
|
|
||||||
|
|
||||||
|
ice40:
|
||||||
|
|
||||||
|
values:
|
||||||
|
device: ICE40UP5K
|
||||||
|
nextpnr_options:
|
||||||
|
hx1k: true
|
||||||
|
|
||||||
|
stages:
|
||||||
|
mk_build_dir:
|
||||||
|
module: 'common:mkdirs'
|
||||||
|
params:
|
||||||
|
build_dir: build/${device}
|
||||||
|
synth:
|
||||||
|
module: 'common:yosys'
|
||||||
|
params:
|
||||||
|
takes:
|
||||||
|
produces:
|
||||||
|
prod_meta:
|
||||||
|
values:
|
||||||
|
yosys_tcl_env:
|
||||||
|
OUT_JSON: '${:json}'
|
||||||
|
pnr:
|
||||||
|
module: 'common:nextpnr_ice40'
|
||||||
|
values:
|
||||||
|
placer: heap
|
||||||
|
router: router1
|
||||||
|
bitstream:
|
||||||
|
module: 'common:generic_script_wrapper'
|
||||||
|
params:
|
||||||
|
stage_name: bitstream
|
||||||
|
script: icepack
|
||||||
|
outputs:
|
||||||
|
bitstream:
|
||||||
|
mode: file
|
||||||
|
file: "${:ice_asm[noext]}.bit"
|
||||||
|
target: "${:ice_asm[noext]}.bit"
|
||||||
|
inputs:
|
||||||
|
"#1": "${:ice_asm}"
|
||||||
|
"#2": "${:ice_asm[noext]}.bit"
|
||||||
|
|
||||||
|
|
||||||
ql-eos-s3:
|
ql-eos-s3:
|
||||||
|
|
||||||
values:
|
values:
|
||||||
|
@ -220,7 +261,7 @@ ql-eos-s3:
|
||||||
params:
|
params:
|
||||||
build_dir: 'build/${device}'
|
build_dir: 'build/${device}'
|
||||||
synth:
|
synth:
|
||||||
module: 'common:synth'
|
module: 'common:yosys'
|
||||||
params:
|
params:
|
||||||
takes:
|
takes:
|
||||||
- pcf?
|
- pcf?
|
||||||
|
@ -609,7 +650,7 @@ ql-k4n8_fast: &ql-k4n8
|
||||||
params:
|
params:
|
||||||
build_dir: 'build/${device}'
|
build_dir: 'build/${device}'
|
||||||
synth:
|
synth:
|
||||||
module: 'common:synth'
|
module: 'common:yosys'
|
||||||
params:
|
params:
|
||||||
produces:
|
produces:
|
||||||
- synth_v
|
- synth_v
|
||||||
|
|
|
@ -52,10 +52,12 @@ def get_requirements(file: Path) -> List[str]:
|
||||||
semver = "0.0.0"
|
semver = "0.0.0"
|
||||||
version = None
|
version = None
|
||||||
|
|
||||||
with (packagePath.parent / ".gitcommit").open("r") as rptr:
|
gitcommit = packagePath.parent / ".gitcommit"
|
||||||
sha = rptr.read().strip()
|
if gitcommit.exists():
|
||||||
if sha != "$Format:%h$":
|
with gitcommit.open("r") as rptr:
|
||||||
version = f"{semver}+{sha}"
|
sha = rptr.read().strip()
|
||||||
|
if sha != "$Format:%h$":
|
||||||
|
version = f"{semver}+{sha}"
|
||||||
|
|
||||||
git = which("git")
|
git = which("git")
|
||||||
if git is not None:
|
if git is not None:
|
||||||
|
|
|
@ -28,7 +28,7 @@ ROOT = Path(__file__).resolve().parent
|
||||||
ARCHS = {"xc7": ["artix7", "artix7_100t", "artix7_200t", "zynq7", "zynq7_z020", "spartan7"], "eos-s3": ["ql-s3", "pp3"]}
|
ARCHS = {"xc7": ["artix7", "artix7_100t", "artix7_200t", "zynq7", "zynq7_z020", "spartan7"], "eos-s3": ["ql-s3", "pp3"]}
|
||||||
|
|
||||||
|
|
||||||
def get_script_path(arch=None):
|
def get_script_path(arch=None, pnrtool="vpr"):
|
||||||
if arch is None:
|
if arch is None:
|
||||||
arch = FPGA_FAM
|
arch = FPGA_FAM
|
||||||
for key, val in ARCHS.items():
|
for key, val in ARCHS.items():
|
||||||
|
@ -37,4 +37,5 @@ def get_script_path(arch=None):
|
||||||
break
|
break
|
||||||
if arch not in ["xc7", "eos-s3", "qlf_k4n8", "ice40"]:
|
if arch not in ["xc7", "eos-s3", "qlf_k4n8", "ice40"]:
|
||||||
raise (Exception(f"Unsupported arch <{arch}>!"))
|
raise (Exception(f"Unsupported arch <{arch}>!"))
|
||||||
return ROOT / f"{arch}.f4pga.tcl"
|
suffix = f".{pnrtool}" if arch == "ice40" else ""
|
||||||
|
return ROOT / f"{arch}{suffix}.f4pga.tcl"
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
yosys -import
|
||||||
|
|
||||||
|
synth_ice40 -nocarry
|
||||||
|
|
||||||
|
opt_expr -undriven
|
||||||
|
opt_clean
|
||||||
|
|
||||||
|
attrmap -remove hdlname
|
||||||
|
setundef -zero -params
|
||||||
|
|
||||||
|
write_json $::env(OUT_JSON)
|
||||||
|
#write_verilog $::env(OUT_SYNTH_V)
|
Loading…
Reference in New Issue