Skip to content

Commit

Permalink
f4pga/utils: all python scripts moved from quicklogic arch-defs tarballs
Browse files Browse the repository at this point in the history
Signed-off-by: Pawel Czarnecki <pczarnecki@antmicro.com>
  • Loading branch information
umarcor committed Sep 6, 2022
1 parent cf35028 commit 8232259
Show file tree
Hide file tree
Showing 56 changed files with 18,606 additions and 26 deletions.
23 changes: 11 additions & 12 deletions f4pga/flows/platforms.yml
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ ql-eos-s3:
params:
stage_name: prepare_sdc
interpreter: '${python3}'
script: '${shareDir}/scripts/process_sdc_constraints.py'
script: ['-m', 'f4pga.utils.quicklogic.process_sdc_constraints']
outputs:
sdc:
mode: file
Expand Down Expand Up @@ -300,7 +300,7 @@ ql-eos-s3:
params:
stage_name: ioplace
interpreter: '${python3}'
script: '${shareDir}/scripts/pp3_create_ioplace.py'
script: ['-m', 'f4pga.utils.quicklogic.pp3.create_ioplace']
outputs:
io_place:
mode: stdout
Expand All @@ -316,7 +316,7 @@ ql-eos-s3:
params:
stage_name: place_constraints
interpreter: '${python3}'
script: '${shareDir}/scripts/pp3_create_place_constraints.py'
script: ['-m', 'f4pga.utils.quicklogic.pp3.create_place_constraints']
outputs:
place_constraints:
mode: stdout
Expand All @@ -333,7 +333,7 @@ ql-eos-s3:
params:
stage_name: iomux_jlink
interpreter: '${python3}'
script: '${shareDir}/scripts/pp3_eos_s3_iomux_config.py'
script: ['-m', 'f4pga.utils.quicklogic.pp3.eos-s3.iomux_config']
outputs:
iomux_jlink:
mode: stdout
Expand All @@ -349,7 +349,7 @@ ql-eos-s3:
params:
stage_name: iomux_openocd
interpreter: '${python3}'
script: '${shareDir}/scripts/pp3_eos_s3_iomux_config.py'
script: ['-m', 'f4pga.utils.quicklogic.pp3.eos-s3.iomux_config']
outputs:
iomux_openocd:
mode: stdout
Expand All @@ -365,7 +365,7 @@ ql-eos-s3:
params:
stage_name: iomux_binary
interpreter: '${python3}'
script: '${shareDir}/scripts/pp3_eos_s3_iomux_config.py'
script: ['-m', 'f4pga.utils.quicklogic.pp3.eos-s3.iomux_config']
outputs:
iomux_binary:
mode: stdout
Expand Down Expand Up @@ -570,10 +570,9 @@ ql-eos-s3:
out-verilog: '${:bitstream}.v'
out-pcf: '${:bitstream}.pcf'
out-qcf: '${:bitstream}.qcf'
$F4PGA_INSTALL_DIR: '${shareDir}/../../../../'
$F4PGA_INSTALL_DIR: '${shareDir}/../../../'
$FPGA_FAM: eos-s3
$PATH: >-
${shareDir}/../../../conda/envs/eos-s3/bin/:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
$PATH: '${shareDir}/../../conda/envs/eos-s3/bin/:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
$BIN_DIR_PATH: '${binDir}'


Expand Down Expand Up @@ -630,7 +629,7 @@ ql-k4n8_fast: &ql-k4n8
params:
stage_name: ioplace
interpreter: '${python3}'
script: '${binDir}/python/ql_qlf_create_ioplace.py'
script: ['-m', 'f4pga.utils.quicklogic.qlf_k4n8.create_ioplace']
outputs:
io_place:
mode: stdout
Expand All @@ -649,7 +648,7 @@ ql-k4n8_fast: &ql-k4n8
params:
stage_name: repack
interpreter: '${python3}'
script: '${binDir}/python/repacker/repack.py'
script: ['-m', 'f4pga.utils.quicklogic.repacker.repack']
outputs:
eblif_repacked:
mode: file
Expand Down Expand Up @@ -742,7 +741,7 @@ ql-k4n8_slow:
params:
stage_name: ioplace
interpreter: '${python3}'
script: '${binDir}/python/ql_qlf_create_ioplace.py'
script: ['-m', 'f4pga.utils.quicklogic.qlf_k4n8.create_ioplace']
outputs:
io_place:
mode: stdout
Expand Down
221 changes: 221 additions & 0 deletions f4pga/utils/quicklogic/convert_compile_opts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
#!/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
#
# http://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

"""
This script reads Verilog compile options string from stdin and outputs a
series of Yosys commands that implement them to stdout.
"""

import os
import sys
import shlex


def eprint(*args, **kwargs):
"""
Like print() but to stderr
"""
print(*args, file=sys.stderr, **kwargs)


def parse_options(lines, opts=None):
"""
Parses compile options
"""

# Remove "#" comments and C/C++ style "//" comments, remove blank lines,
# join all remaining ones into a single string
opt_string = ""
for line in lines:

# Remove comments
pos = line.find("#")
if pos != -1:
line = line[:pos]

pos = line.find("//")
if pos != -1:
line = line[:pos]

# Append
line = line.strip()
if line:
opt_string += line + " "

# Remove all C/C++ style "/* ... */" comments
while True:

# Find beginning of a block comment. Finish if none is found
p0 = opt_string.find("/*")
if p0 == -1:
break

# Find ending of a block comments. Throw an error if none is found
p1 = opt_string.find("*/", p0 + 2)
if p1 == -1:
eprint("ERROR: Unbalanced block comment!")
exit(-1)

# Remove the comment
opt_string = opt_string[:p0] + opt_string[p1 + 2 :]

# Initialize options if not given
if opts is None:
opts = {"incdir": set(), "libdir": set(), "libext": set(), "defines": {}}

# Scan and process options
parts = iter(shlex.split(opt_string))
while True:

# Get the option
try:
opt = next(parts)
except StopIteration:
break

# A file containing options
if opt == "-f":
try:
arg = next(parts)
except StopIteration:
eprint("ERROR: Missing file name for '-f'")
exit(-1)

# Open and read the file, recurse
if not os.path.isfile(arg):
eprint("ERROR: File '{}' does not exist".format(arg))
exit(-1)

with open(arg, "r") as fp:
lines = fp.readlines()

parse_options(lines, opts)

# Verilog library directory
elif opt == "-y":
try:
arg = next(parts)
except StopIteration:
eprint("ERROR: Missing directory name for '-y'")
exit(-1)

if not os.path.isdir(arg):
eprint("ERROR: Directory '{}' does not exist".format(arg))
exit(-1)

opts["libdir"].add(arg)

# Library file extensions
elif opt.startswith("+libext+"):
args = opt.strip().split("+")
if len(args) < 2:
eprint("ERROR: Missing file extensions(s) for '+libext+'")
exit(-1)

opts["libext"] |= set(args[2:])

# Verilog include directory
elif opt.startswith("+incdir+"):
args = opt.strip().split("+")
if len(args) < 2:
eprint("ERROR: Missing file name(s) for '+incdir+'")
exit(-1)

opts["incdir"] |= set(args[2:])

# Verilog defines
elif opt.startswith("+define+"):
args = opt.strip().split("+")
if len(args) < 2:
eprint("ERROR: Malformed '+define+' directive")
exit(-1)

# Parse defines. They may or may not have values
for arg in args[2:]:
if "=" in arg:
key, value = arg.split("=")
else:
key, value = arg, None

if key in opts["defines"]:
eprint("ERROR: Macro '{}' defined twice!".format(key))
opts["defines"][key] = value

return opts


def quote(s):
"""
Quotes a string if it needs it
"""
if " " in s:
return '"' + s + '"'
else:
return s


def translate_options(opts):
"""
Translates the given options into Yosys commands
"""

commands = []

# Include directories
for incdir in opts["incdir"]:
cmd = "verilog_defaults -add -I{}".format(quote(incdir))
commands.append(cmd)

# Macro defines
for key, val in opts["defines"].items():
if val is not None:
cmd = "verilog_defaults -add -D{}={}".format(key, val)
else:
cmd = "verilog_defaults -add -D{}".format(key)
commands.append(cmd)

# Since Yosys does not automatically search for an unknown module in
# verilog files make it read all library files upfront. Do this by
# searching for files with extensions provided with "+libext+" in
# paths privided by "-y".
libext = opts["libext"] | {"v"}

for libdir in opts["libdir"]:
for f in os.listdir(libdir):
_, ext = os.path.splitext(f)
if ext.replace(".", "") in libext:
fname = os.path.join(libdir, f)
cmd = "read_verilog {}".format(quote(fname))
commands.append(cmd)

return commands


# =============================================================================

if __name__ == "__main__":

# Read lines from stdin, parse options
lines = sys.stdin.readlines()
opts = parse_options(lines)

# Translate parsed options to Yosys commands and output them
cmds = translate_options(opts)
for cmd in cmds:
print(cmd)
Loading

0 comments on commit 8232259

Please sign in to comment.