Skip to content

Commit

Permalink
add submodule hdl/constraints
Browse files Browse the repository at this point in the history
  • Loading branch information
umarcor committed Jan 28, 2022
1 parent d8a34d1 commit ce65e4b
Show file tree
Hide file tree
Showing 177 changed files with 227 additions and 325 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "collection"]
path = collection
url = https://github.com/FPGAwars/collection-default
[submodule "constraints"]
path = ICETool/constraints
url = https://github.com/hdl/constraints
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/docs/
/fonts/
/collection/
/ICETool/constraints/
/plugins/serial-term/
/cache/
/dist/
Expand Down
193 changes: 193 additions & 0 deletions ICETool/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
#!/usr/bin/env python3

from sys import (
argv as sys_argv,
exit as sys_exit,
stdout as sys_stdout,
stderr as sys_stderr
)
from os import getenv
from shutil import which
from pathlib import Path
from subprocess import check_call
import click
import re
import json

from ICETool.constraints.constraints import getBoardsInfo


def getBoard(board):
"""
Get board info from hdl/constraints.
"""
ConvertBoardNameFromIcestudioToConstraints = {
"icezum": "IceZumAlhambra",
"alhambra-ii": "IceZumAlhambraII",
"icestick": "IceStick",
"upduino": "UPDuino-v1.0",
"upduino2": "UPDuino-v2.0",
"upduino21": "UPDuino-v2.1",
"upduino3": "UPDuino-v3.0"
}
boardInfo = getBoardsInfo(verbose=False)[(
ConvertBoardNameFromIcestudioToConstraints[board]
if board in ConvertBoardNameFromIcestudioToConstraints else
board
)]
print(boardInfo)
return boardInfo


def execCommand(cmd, cwd):
"""
Print a command, execute it, and flush stdout and stderr.
"""
print(cmd)
check_call(cmd, cwd=cwd)
sys_stdout.flush()
sys_stderr.flush()


@click.command("verify")
@click.pass_context
@click.option("-p", "--project-dir", type=str, metavar="path", help="Set the target directory for the project.")
@click.option("-b", "--board", type=str, metavar="board", help="Set the board.")
@click.option("-v", "--verbose", is_flag=True, help="Show the entire output of the command.")
def VerifyCommand(ctx, board, project_dir, verbose):
"""
Verify verilog sources through Icarus Verilog.
"""

YOSYS_SHARE_PATH = Path(which('yosys')).parent.parent / 'share/yosys'

boardInfo = getBoard(board)

device = boardInfo.Device.split('-')[0].lower()

sources = " ".join([item.name for item in Path(project_dir).glob("*.v")])

opts = '-D NO_ICE40_DEFAULT_ASSIGNMENTS' if device == 'ice40' else '-D NO_INCLUDES'

execCommand(
f'iverilog -D VCD_OUTPUT=sim.vcd {opts} {YOSYS_SHARE_PATH!s}/{device}/cells_sim.v {sources}',
project_dir
)

print("verbose:", verbose)

ctx.exit(0)


@click.command("build")
@click.pass_context
@click.option("-b", "--board", type=str, metavar="board", help="Set the board.")
@click.option("--device", type=str, metavar="device", help="Set the FPGA device.")
@click.option("--package", type=str, metavar="package", help="Set the FPGA package.")
@click.option("-p", "--project-dir", type=str, metavar="path", help="Set the target directory for the project.")
@click.option("-v", "--verbose", is_flag=True, help="Show the entire output of the command.")
@click.option("--verbose-yosys", is_flag=True, help="Show the yosys output of the command.")
@click.option("--verbose-pnr", is_flag=True, help="Show the pnr output of the command.")
def BuildCommand(ctx, board, device, package, project_dir, verbose, verbose_yosys, verbose_pnr):
"""
Generate bitstream through Yosys and Nextpnr.
"""

sources = " ".join([item.name for item in Path(project_dir).glob("*.v")])
opts = '' if verbose or verbose_yosys else '-q'

execCommand(
f'yosys {opts} -p "proc; read_verilog {sources}; synth_ice40 -top main -json synth.json"',
project_dir
)

boardInfo = getBoard(board)
device = boardInfo.Device.split('-')[1].lower() if device is None else device
package = boardInfo.Package.lower() if package is None else package
pcf = [item.name for item in Path(project_dir).glob("*.pcf")][0]
opts = '' if verbose or verbose_pnr else '-q'

execCommand(
f'nextpnr-ice40 {opts} --{device} --package {package} --pcf {pcf} --json synth.json --asc pnr.asc',
project_dir
)

execCommand(
'icepack pnr.asc design.bin',
project_dir
)

ctx.exit(0)


@click.command("upload")
@click.pass_context
@click.option("-b", "--board", type=str, metavar="board", help="Set the board.")
@click.option("--serial-port", type=str, metavar="serial-port", help="Set the serial port.")
@click.option("--ftdi-id", type=str, metavar="ftdi-id", help="Set the FTDI id.")
@click.option("-s", "--sram", is_flag=True, help="Perform SRAM programming.")
@click.option("-f", "--flash", is_flag=True, help="Perform FLASH programming.")
@click.option("-p", "--project-dir", type=str, metavar="path", help="Set the target directory for the project.")
@click.option("-v", "--verbose", is_flag=True, help="Show the entire output of the command.")
@click.option("--verbose-yosys", is_flag=True, help="Show the yosys output of the command.")
@click.option("--verbose-pnr", is_flag=True, help="Show the pnr output of the command.")
def UploadCommand(ctx, board, serial_port, ftdi_id, sram, flash, project_dir, verbose, verbose_yosys, verbose_pnr):
"""
Upload bitstream to the board through openFPGALoader.
"""

print("board:", board)
print("serial_port:", serial_port)
print("ftdi_id:", ftdi_id)
print("sram:", sram)
print("flash:", flash)
print("verbose:", verbose)
print("verbose_yosys:", verbose_yosys)
print("verbose_pnr:", verbose_pnr)

ctx.exit(0)


@click.command("regenerate-pinouts")
@click.pass_context
@click.option("-d", "--rdir", type=str, metavar="rdir", help="Resources directory.")
def RegeneratePinoutsCommand(ctx, rdir):
p = Path(rdir)

for item in list(p.glob('*')):
if item.is_dir() and item.name[0] != '_':
path = item
cfile = path / 'pinout.pcf'
if not cfile.exists():
cfile = path / 'pinout.lpf'
if not cfile.exists():
raise Exception('No known constraints file found in %s', str(path))

print('· Processing %s file %s' % (item.name, cfile.name))

pattern = 'set_io\s+(--warn-no-port|-nowarn)?\s*(.*?)\s+(.*?)\s+(#+\s+)?' if cfile.suffix == '.pcf' else r'LOCATE\s*?COMP\s*?"(.*)"\s*?SITE\s*?"(.*)";\s*?#?\s*?'
pinout = re.findall(pattern, cfile.read_text())

if len(pinout) == 0:
print(' !!! Something went wrong; empty pinout list')
continue

info = json.loads((path / 'info.json').read_text())

info['pinout'] = { item[1]: item[2] for item in sorted(pinout, key=lambda pinout: pinout[1],reverse=True) } if cfile.suffix == '.pcf' else { item[0]: item[1] for item in pinout }

(path / 'info.json').write_text(json.dumps(info, indent=2) + "\n")


@click.group()
def cli():
pass

cli.add_command(VerifyCommand)
cli.add_command(BuildCommand)
cli.add_command(UploadCommand)
cli.add_command(RegeneratePinoutsCommand)


if __name__ == '__main__':
cli()
1 change: 1 addition & 0 deletions ICETool/constraints
Submodule constraints added at 148fff
36 changes: 14 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<a title="'icestudio' workflow status" href="https://github.com/juanmard/icestudio/actions?query=workflow%3Aicestudio"><img alt="'icestudio' workflow status" src="https://img.shields.io/github/workflow/status/juanmard/icestudio/icestudio?longCache=true&style=flat-square&label=icestudio&logo=Github%20Actions&logoColor=fff"></a>
</p>

Visual editor for Verilog designs, built on top of [OSS CAD Suite](https://github.com/YosysHQ/oss-cad-suite-build).
Visual editor for Verilog designs.
Find installation guidelines, user guide and further information at
[juanmard.github.io/icestudio](https://juanmard.github.io/icestudio).

Expand All @@ -22,9 +22,9 @@ Find installation guidelines, user guide and further information at
<a title="Code Climate technical debt" href="https://codeclimate.com/github/juanmard/icestudio/trends/technical_debt"><img src="https://img.shields.io/codeclimate/tech-debt/juanmard/icestudio?longCache=true&style=flat-square&logo=codeclimate"></a>
</p>

**IMPORTANT: Since June 2021, several enhancements available in this variant are being applied [upstream](https://github.com/FPGAwars/icestudio). Find further details in the [WIKI](https://github.com/juanmard/icestudio/wiki).**
**IMPORTANT: Since June 2021, several frontend and internal enhancements available in this variant are being applied [upstream](https://github.com/FPGAwars/icestudio). Find further details in the [WIKI](https://github.com/juanmard/icestudio/wiki).**

---
# Installation

Unlike the [upstream](https://github.com/FPGAwars/icestudio), _Icestudio Nightly_ is agnostic to the toolchain
installation solution and it does not require admin/sudo permissions.
Expand All @@ -34,32 +34,24 @@ See [hdl/packages](https://github.com/hdl/packages).
By the same token, the usage of virtual environments is optional, although recommended when using Python based packaging
systems such as Conda or apio.

Furthermore, _Icestudio Nightly_ uses `ICETool` by default, instead of `apio`.
[ICETool](tools/ICETool) is a Python script that allows translating `verify`, `build` and `upload` commands from
Icestudio into the entrypoints provided by [FuseSoC](https://github.com/olofk/FuseSoC)/[Edalize](https://github.com/olofk/edalize/),
apio, or any other EDA workflow provider.
See [Electronic Design Automation Abstraction (EDA²)](https://edaa-org.github.io/).

Furthermore, _Icestudio Nightly_ uses [ICETool](ICETool) by default, a Python script that allows executing
`verify`, `build` and `upload` commands without the SCons infrastructure required by `apio`.
Currently, ICETool is in an early development stage and it is not published through PyPI.
Therefore, the location of the script needs to be made available before starting Icestudio.

On GNU/Linux or MSYS2, add subdir `tools` to the PATH:

```sh
PATH=$(pwd)/tools:$PATH yarn start
```

On the Windows CMD, use PYTHONPATH:
Therefore, the location of the package needs to be added to the PYTHONPATH before starting Icestudio:

```sh
PYTHONPATH=$(pwd)/tools:$PATH yarn start
PYTHONPATH=$(pwd) yarn start
```

Moreover, environment variable `ICETOOL_CMD` allows overriding the backend.

```sh
# Use apio
ICETOOL_CMD=apio PATH=$(pwd)/tools:$PATH yarn start
# Use edalize
ICETOOL_CMD=edalize PATH=$(pwd)/tools:$PATH yarn start
ICETOOL_CMD=apio yarn start

# Use custom tool
ICETOOL_CMD=mytool yarn start
```

Do you want to convert Icestudio commands into [FuseSoC](https://github.com/olofk/FuseSoC)/[Edalize](https://github.com/olofk/edalize/) or any other EDA workflow provider? [Let us know!](https://github.com/juanmard/icestudio/issues)!
See [Electronic Design Automation Abstraction (EDA²)](https://edaa-org.github.io/).
31 changes: 0 additions & 31 deletions constraints/boards/regenerate_pinouts.py

This file was deleted.

2 changes: 1 addition & 1 deletion controllers/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,7 @@ angular
if (common.selectedBoard) {
return nodeFs.existsSync(
nodePath.join(
'constraints',
'resources',
'boards',
common.selectedBoard.name,
'pinout.svg'
Expand Down
4 changes: 2 additions & 2 deletions gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ module.exports = function (grunt) {
'collection/**',
'controllers/**',
'graphics/**',
'constraints/**/*.*',
'resources/**/*.*',
'images/**/*.*',
'locale/**/*.*',
'plugins/**/*.*',
Expand Down Expand Up @@ -166,7 +166,7 @@ module.exports = function (grunt) {
watch: {
scripts: {
files: [
'constraints/**/*.*',
'resources/**/*.*',
'controllers/*.js',
'fonts/**',
'graphics/*.js',
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
11 changes: 7 additions & 4 deletions services/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,10 @@ angular

this.APP_DIR = nodePath.dirname(process.execPath);

this.ICETOOL = 'ICETool';
this.ICETOOL = ['python', '-m', 'ICETool.__init__'];
if (process.env.ICETOOL_CMD != undefined) {
this.ICETOOL = [process.env.ICETOOL_CMD];
}

const nodeTmp = require('tmp');

Expand Down Expand Up @@ -108,21 +111,21 @@ angular

this.isEditingSubmodule = false;

// Read list of subdirs of 'constraints' which do not start with '_';
// Read list of subdirs of 'resources' which do not start with '_';
// for each, read 'info.json' and 'rules'.json'.
// Generate list of boards and list of devices.
try {
var boards = [];
var devices = [];
var dpath = nodePath.join('constraints', 'devices');
var dpath = nodePath.join('resources', 'devices');
nodeFs.readdirSync(dpath).forEach((ditem) => {
const ddata = _readJSONFile(dpath, ditem);
devices.push({
name: ditem.slice(0, -5),
resources: ddata,
});
});
var rpath = nodePath.join('constraints', 'boards');
var rpath = nodePath.join('resources', 'boards');
nodeFs.readdirSync(rpath).forEach((bdir) => {
if (bdir[0] !== '_' && !nodePath.extname(bdir)) {
const bpath = nodePath.join(rpath, bdir);
Expand Down
7 changes: 3 additions & 4 deletions services/tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ angular
.then(function () {
var command = commands[0];
if (command === 'build' || command === 'upload') {
commands = commands.concat('--verbose-pnr');
commands = commands.concat('--verbose');
}
return executeLocal(commands);
})
Expand Down Expand Up @@ -264,8 +264,7 @@ angular

function executeLocal(commands) {
return new Promise(function (resolve) {
var command = [common.ICETOOL]
.concat(commands)
var command = common.ICETOOL.concat(commands)
.concat(['-p', `"${common.BUILD_DIR}"`])
.join(' ');
if (
Expand Down Expand Up @@ -306,7 +305,7 @@ angular
var stderr = result.stderr;

return new Promise(function (resolve, reject) {
if (_error || stderr) {
if (_error) {
// -- Process errors
reject();
if (stdout) {
Expand Down
Loading

0 comments on commit ce65e4b

Please sign in to comment.