From d8a34d1d9c3e3f8fbeeab2b8fc5ae8eadeabaaa4 Mon Sep 17 00:00:00 2001
From: umarcor
Date: Wed, 5 Jan 2022 12:58:02 +0100
Subject: [PATCH] rm toolchain and drivers; replace apio with ICETool
---
README.md | 45 +++-
app.js | 1 -
controllers/preferences.js | 4 -
docs/index.rst | 1 -
docs/quickstart/drivers.rst | 18 +-
docs/quickstart/toolchain.rst | 21 --
index.html | 1 -
package.json | 2 +-
services/common.js | 17 +-
services/compiler.js | 12 +-
services/drivers.js | 472 ----------------------------------
services/tools.js | 426 +++---------------------------
tools/ICETool | 259 +++++++++++++++++++
views/preferences.html | 131 ----------
14 files changed, 352 insertions(+), 1058 deletions(-)
delete mode 100644 docs/quickstart/toolchain.rst
delete mode 100644 services/drivers.js
create mode 100755 tools/ICETool
diff --git a/README.md b/README.md
index 207f8f21d..8dfc36702 100644
--- a/README.md
+++ b/README.md
@@ -8,8 +8,7 @@
-Visual editor for Verilog designs, built on top of [Icestorm](http://www.clifford.at/icestorm/) and
-[Apio](https://github.com/FPGAwars/apio).
+Visual editor for Verilog designs, built on top of [OSS CAD Suite](https://github.com/YosysHQ/oss-cad-suite-build).
Find installation guidelines, user guide and further information at
[juanmard.github.io/icestudio](https://juanmard.github.io/icestudio).
@@ -23,4 +22,44 @@ Find installation guidelines, user guide and further information at
-**IMPORTANT: Since June 2021, several enhancements available in this variant are being applied [upstream](https://github.com/FPGAwars/icestudio). Therefore, the development of this fork is on hold until the dependencies are stabilized. Find further details in the [WIKI](https://github.com/juanmard/icestudio/wiki).**
+**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).**
+
+---
+
+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.
+Users are free to choose between [OSS CAD Suite](https://github.com/YosysHQ/oss-cad-suite-build), system packages, Conda environments, [apio](https://github.com/FPGAwars/apio), [containers](https://hdl.github.io/containers/), etc. as their
+preferred solution for getting the required tools and making them available in the PATH.
+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/).
+
+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:
+
+```sh
+PYTHONPATH=$(pwd)/tools:$PATH 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
+```
diff --git a/app.js b/app.js
index 397020d3c..83815e867 100644
--- a/app.js
+++ b/app.js
@@ -139,7 +139,6 @@ angular
utils.selectBoard(_board);
}
- tools.checkToolchain();
setTimeout(utils.endWait, 1500);
});
diff --git a/controllers/preferences.js b/controllers/preferences.js
index 49f776dc8..14247caab 100644
--- a/controllers/preferences.js
+++ b/controllers/preferences.js
@@ -39,10 +39,6 @@ angular
icon: 'snowflake-o',
title: 'UI Theme',
},
- toolchain: {
- icon: 'gear',
- title: 'Toolchain',
- },
};
$scope.done = () => {
diff --git a/docs/index.rst b/docs/index.rst
index 9bb6f5336..fa6ff6e0a 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -19,7 +19,6 @@ Icestudio v1 (nightly)
quickstart/installation
quickstart/selectboard
- quickstart/toolchain
quickstart/drivers
quickstart/test
quickstart/project
diff --git a/docs/quickstart/drivers.rst b/docs/quickstart/drivers.rst
index 89ee9a7b2..6c106e930 100644
--- a/docs/quickstart/drivers.rst
+++ b/docs/quickstart/drivers.rst
@@ -3,17 +3,11 @@
Install/configure the drivers
-----------------------------
-Then, for configuring drivers, connect your board and select **Enable** in *toolchain* section. This operation requires **administrator privileges**.
+On Windows, an external application (`Zadig `_) is used for boards with FTDI devices.
+It replaces the existing FTDI driver of the **Interface 0** with **libusbK**.
-.. attention::
+.. image:: ../_static/img/zadig.png
+ :width: 500 px
+ :align: center
- On Windows, an external application (`Zadig `_) is used for boards with FTDI devices.
- It replaces the existing FTDI driver of the **Interface 0** with **libusbK**.
-
- .. image:: ../_static/img/zadig.png
- :width: 500 px
- :align: center
-
- |
-
- On macOS, this operation requires internet connection to allow *Homebrew* to install ``libffi`` and ``libftdi`` packages.
+On macOS, this operation requires internet connection to allow *Homebrew* to install ``libffi`` and ``libftdi`` packages.
diff --git a/docs/quickstart/toolchain.rst b/docs/quickstart/toolchain.rst
deleted file mode 100644
index 0802e50e1..000000000
--- a/docs/quickstart/toolchain.rst
+++ /dev/null
@@ -1,21 +0,0 @@
-.. _quickstart:toolchain:
-
-Install/configure the toolchain
--------------------------------
-
-For configuring the built-in toolchain of custom statically built binaries, go to **Edit > Preferences** and select *install*:
-
-.. image:: ../_static/img/start_toolchain.png
- :width: 500 px
- :align: center
-
-The latest stable release of `Apio `_ and all its built-in packages will be installed.
-
-.. IMPORTANT:: Some boards are not supported in the stable releases of Apio, but are available in the development branch.
- You might need to install/update Apio from the git repository.
-
- NOTE: on GNU/Linux, first ``source ~/.icestudio/venv/bin/activate``.
-
- .. code-block:: shell
-
- pip install -U git+https://github.com/FPGAwars/apio.git@develop#egg=apio
diff --git a/index.html b/index.html
index e87a51760..16af5a388 100644
--- a/index.html
+++ b/index.html
@@ -96,7 +96,6 @@
-
diff --git a/package.json b/package.json
index a33aa49f4..de2d05048 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "icestudio",
- "version": "0.9.0dev",
+ "version": "0.12.0dev",
"sha": "00000000",
"description": "Visual editor for Verilog designs",
"repository": "https://github.com/juanmard/icestudio",
diff --git a/services/common.js b/services/common.js
index 00e318fb9..e5834c2ca 100644
--- a/services/common.js
+++ b/services/common.js
@@ -73,25 +73,12 @@ angular
this.ICESTUDIO_DIR,
'collections'
);
- this.APIO_HOME_DIR = nodePath.join(this.ICESTUDIO_DIR, 'apio');
const _PROFILE_PATH = nodePath.join(this.ICESTUDIO_DIR, 'profile.json');
this.PROFILE_PATH = _PROFILE_PATH;
this.APP_DIR = nodePath.dirname(process.execPath);
- //-- Folder name for the virtual environment
- this.ENV_DIR = nodePath.join(this.ICESTUDIO_DIR, 'venv');
- this.ENV_BIN_DIR = nodePath.join(
- this.ENV_DIR,
- this.WIN32 && !this.MSYSTEM ? 'Scripts' : 'bin'
- );
- this.ENV_APIO = nodePath.join(
- this.ENV_BIN_DIR,
- this.WIN32 ? 'apio.exe' : 'apio'
- );
- this.APIO_CMD = this.WIN32
- ? `set APIO_HOME_DIR="${this.APIO_HOME_DIR}"& "${this.ENV_APIO}"`
- : `export APIO_HOME_DIR="${this.APIO_HOME_DIR}"; "${this.ENV_APIO}"`;
+ this.ICETOOL = 'ICETool';
const nodeTmp = require('tmp');
@@ -198,8 +185,6 @@ angular
// Profile
const _data = {
- apioRepo: 'juanmard/icestudio',
- apioRef: 'apio-dev',
board: null,
prog: null,
boardRules: true,
diff --git a/services/compiler.js b/services/compiler.js
index 3a5db9d7e..ca7ffd445 100644
--- a/services/compiler.js
+++ b/services/compiler.js
@@ -698,13 +698,15 @@ angular
code += module(data);
}
+ code += '\n';
+
// Dependencies modules
if (typeof project.package !== 'undefined') {
- code += '\n/*-------------------------------------------------*/\n';
- code += '/*-- ' + project.package.name + ' */\n';
- code += '/*-- - - - - - - - - - - - - - - - - - - - - - - --*/\n';
- code += '/*-- ' + project.package.description + '\n';
- code += '/*-------------------------------------------------*/\n';
+ code += '//---------------------------------------------------\n';
+ code += '//-- ' + project.package.name + '\n';
+ code += '//-- - - - - - - - - - - - - - - - - - - - - - - - --\n';
+ code += '//-- ' + project.package.description + '\n';
+ code += '//---------------------------------------------------\n';
}
for (var d in dependencies) {
code += verilogCompiler(utils.digestId(d), dependencies[d]);
diff --git a/services/drivers.js b/services/drivers.js
deleted file mode 100644
index bb6a34ad2..000000000
--- a/services/drivers.js
+++ /dev/null
@@ -1,472 +0,0 @@
-angular
- .module('icestudio')
- .service(
- 'drivers',
- function (
- $rootScope,
- alerts,
- common,
- gettextCatalog,
- gui,
- nodeChildProcess,
- utils
- ) {
- 'use strict';
-
- function _tcStr(str, args) {
- return gettextCatalog.getString(str, args);
- }
-
- this.enable = function () {
- switch (common.selectedProgrammer) {
- case 'FTDI':
- enableDriversFTDI();
- break;
- case 'Serial':
- enableDriversSerial();
- break;
- default:
- console.warn('No valid selected board programmer');
- }
- };
-
- this.disable = function () {
- switch (common.selectedProgrammer) {
- case 'FTDI':
- disableDriversFTDI();
- break;
- case 'Serial':
- disableDriversSerial();
- break;
- default:
- console.warn('No valid selected board programmer');
- }
- };
-
- function enableDriversFTDI() {
- if (common.WIN32) {
- enableWindowsDriversFTDI();
- } else if (common.DARWIN) {
- enableDarwinDriversFTDI();
- } else {
- enableLinuxDriversFTDI();
- }
- }
-
- function disableDriversFTDI() {
- if (common.WIN32) {
- disableWindowsDriversFTDI();
- } else if (common.DARWIN) {
- disableDarwinDriversFTDI();
- } else {
- disableLinuxDriversFTDI();
- }
- }
-
- function enableDriversSerial() {
- if (common.WIN32) {
- enableWindowsDriversSerial();
- } else if (common.DARWIN) {
- enableDarwinDriversSerial();
- } else {
- enableLinuxDriversSerial();
- }
- }
-
- function disableDriversSerial() {
- if (common.WIN32) {
- disableWindowsDriversSerial();
- } else if (common.DARWIN) {
- disableDarwinDriversSerial();
- } else {
- disableLinuxDriversSerial();
- }
- }
-
- this.preUpload = function (callback) {
- if (common.DARWIN) {
- preUploadDarwin(callback);
- } else if (callback) {
- callback();
- }
- };
-
- this.postUpload = function () {
- if (common.DARWIN) {
- postUploadDarwin();
- }
- };
-
- /*
- * Linux drivers
- */
-
- function enableLinuxDriversFTDI() {
- var rules = '';
- rules += 'ATTRS{idVendor}==\\"0403\\", ATTRS{idProduct}==\\"6010\\", ';
- rules += 'MODE=\\"0660\\", GROUP=\\"plugdev\\", TAG+=\\"uaccess\\"\n';
-
- rules += 'ATTRS{idVendor}==\\"0403\\", ATTRS{idProduct}==\\"6014\\", ';
- rules += 'MODE=\\"0660\\", GROUP=\\"plugdev\\", TAG+=\\"uaccess\\"\n';
-
- rules += 'ATTRS{idVendor}==\\"0403\\", ATTRS{idProduct}==\\"6015\\", ';
- rules += 'MODE=\\"0660\\", GROUP=\\"plugdev\\", TAG+=\\"uaccess\\"\n';
-
- rules += 'ATTRS{idVendor}==\\"1209\\", ATTRS{idProduct}==\\"5af0\\", ';
- rules += 'MODE=\\"0660\\", GROUP=\\"plugdev\\", TAG+=\\"uaccess\\"\n';
-
- rules += 'ATTRS{idVendor}==\\"1209\\", ATTRS{idProduct}==\\"5bf0\\", ';
- rules += 'MODE=\\"0660\\", GROUP=\\"plugdev\\", TAG+=\\"uaccess\\"\n';
-
- //-- ulx3s board
- rules += 'ATTRS{idVendor}==\\"0403\\", ATTRS{idProduct}==\\"6015\\", ';
- rules += 'MODE=\\"666\\", GROUP=\\"dialout\\"\n';
-
- rules += 'ATTRS{idVendor}==\\"0403\\", ATTRS{idProduct}==\\"6015\\", ';
- rules += 'MODE=\\"664\\", GROUP=\\"dialout\\", SUBSYSTEM=="tty"\n';
-
- //-- Icesugar board
- rules += 'ATTRS{idVendor}==\\"1d50\\", ATTRS{idProduct}==\\"602b\\", ';
- rules += 'MODE=\\"0660\\", GROUP=\\"plugdev\\", TAG+=\\"uaccess\\"\n';
-
- configureLinuxDrivers(
- [
- "echo '" + rules + "' > /etc/udev/rules.d/80-fpga-ftdi.rules",
- ].concat(reloadRules()),
- true
- );
- }
-
- function disableLinuxDriversFTDI() {
- configureLinuxDrivers(
- [
- 'rm -f /etc/udev/rules.d/80-icestick.rules',
- 'rm -f /etc/udev/rules.d/80-fpga-ftdi.rules',
- ].concat(reloadRules()),
- false
- );
- }
-
- function enableLinuxDriversSerial() {
- var rules = '';
- rules += '# Disable ModemManager for BlackIce\n';
- rules +=
- 'ATTRS{idVendor}==\\"0483\\", ATTRS{idProduct}==\\"5740\\", ENV{ID_MM_DEVICE_IGNORE}=\\"1\\"\n';
- rules += '# Disable ModemManager for TinyFPGA B2\n';
- rules +=
- 'ATTRS{idVendor}==\\"1209\\", ATTRS{idProduct}==\\"2100\\", ENV{ID_MM_DEVICE_IGNORE}=\\"1\\"';
- rules += '# Disable ModemManager for TinyFPGA BX\n';
- rules +=
- 'ATTRS{idVendor}==\\"1d50\\", ATTRS{idProduct}==\\"6130\\", ENV{ID_MM_DEVICE_IGNORE}=\\"1\\"';
- rules += '# Disable ModemManager for iceFUN\n';
- rules +=
- 'ATTRS{idVendor}==\\"04d8\\", ATTRS{idProduct}==\\"ffee\\", ENV{ID_MM_DEVICE_IGNORE}=\\"1\\"';
- configureLinuxDrivers(
- [
- "echo '" + rules + "' > /etc/udev/rules.d/80-fpga-serial.rules",
- ].concat(reloadRules()),
- true
- );
- }
-
- function disableLinuxDriversSerial() {
- configureLinuxDrivers(
- ['rm -f /etc/udev/rules.d/80-fpga-serial.rules'].concat(
- reloadRules()
- ),
- false
- );
- }
-
- function reloadRules() {
- return [
- 'udevadm control --reload-rules',
- 'udevadm trigger',
- 'service udev restart',
- ];
- }
-
- const nodeSudo = require('sudo-prompt');
-
- function configureLinuxDrivers(commands, enable) {
- utils.startWait();
- nodeSudo.exec(
- `sh -c "${commands.join('; ')}"`,
- {name: 'Icestudio'},
- function (err) {
- utils.endWait();
- if (err) {
- alertify.error(_tcStr('Command failed!'));
- return;
- }
- if (enable) {
- alertify.success(_tcStr('Drivers enabled'));
- alertify.message(
- _tcStr('Unplug and reconnect the board'),
- 5
- );
- } else {
- alertify.warning(_tcStr('Drivers disabled'));
- }
- }
- );
- }
-
- /*
- * Darwin drivers
- */
-
- function enableDarwinDriversFTDI() {
- enableDarwinDrivers(['libftdi', 'libffi'], 'macosFTDIDrivers');
- }
-
- function disableDarwinDriversFTDI() {
- disableDarwinDrivers('macosFTDIDrivers');
- }
-
- function enableDarwinDriversSerial() {
- enableDarwinDrivers(['libusb', 'libffi']);
- }
-
- function disableDarwinDriversSerial() {
- disableDarwinDrivers();
- }
-
- const fs = require('fs');
-
- function enableDarwinDrivers(brewPackages, profileSetting) {
- var brewCommands = ['/usr/local/bin/brew update'];
- for (var i in brewPackages) {
- brewCommands = brewCommands.concat(brewInstall(brewPackages[i]));
- }
- utils.startWait();
- if (typeof common.DEBUGMODE !== 'undefined' && common.DEBUGMODE === 1) {
- fs.appendFileSync(
- common.LOGFILE,
- 'drivers.enableDarwinDrivers' + '\n'
- );
- }
- nodeChildProcess.exec(
- brewCommands.join('; '),
- function (error, stdout, stderr) {
- if (
- typeof common.DEBUGMODE !== 'undefined' &&
- common.DEBUGMODE === 1
- ) {
- fs.appendFileSync(common.LOGFILE, 'STDERR ' + stderr + '\n');
- fs.appendFileSync(common.LOGFILE, 'STDOUT ' + stdout + '\n');
- }
- if (error) {
- if (
- stderr.indexOf('brew: command not found') !== -1 ||
- stderr.indexOf('brew: No such file or directory') !== -1
- ) {
- alertify.warning(
- _tcStr('{{app}} is required.', {
- app: 'Homebrew',
- }) +
- '
' +
- '' +
- _tcStr('Click here to install it') +
- '',
- 30
- ).callback = function (isClicked) {
- if (isClicked) {
- gui.Shell.openExternal('https://brew.sh');
- }
- };
- } else if (stderr.indexOf('Error: Failed to download') !== -1) {
- alertify.error(_tcStr('Internet connection required'), 30);
- } else {
- alertify.error(stderr, 30);
- }
- } else {
- if (profileSetting) {
- common.set(profileSetting, true);
- }
- alertify.success(_tcStr('Drivers enabled'));
- }
- utils.endWait();
- }
- );
- if (typeof common.DEBUGMODE !== 'undefined' && common.DEBUGMODE === 1) {
- fs.appendFileSync(
- common.LOGFILE,
- '/drivers.enableDarwinDrivers' + '\n'
- );
- }
- }
-
- function disableDarwinDrivers(profileSetting) {
- if (profileSetting) {
- common.set(profileSetting, false);
- }
- alertify.warning(_tcStr('Drivers disabled'));
- }
-
- function brewInstall(brewPackage) {
- return [
- '/usr/local/bin/brew install --force ' + brewPackage,
- '/usr/local/bin/brew unlink ' + brewPackage,
- '/usr/local/bin/brew link --force ' + brewPackage,
- ];
- }
-
- var driverC = '';
-
- function preUploadDarwin(callback) {
- if (common.get('macosFTDIDrivers')) {
- // Check and unload the Drivers
- var driverA = 'com.FTDI.driver.FTDIUSBSerialDriver';
- var driverB = 'com.apple.driver.AppleUSBFTDI';
- if (checkDriverDarwin(driverA)) {
- driverC = driverA;
- processDriverDarwin(driverA, false, callback);
- } else if (checkDriverDarwin(driverB)) {
- driverC = driverB;
- processDriverDarwin(driverB, false, callback);
- } else {
- driverC = '';
- if (callback) {
- callback();
- }
- }
- } else if (callback) {
- callback();
- }
- }
-
- function postUploadDarwin() {
- if (common.get('macosFTDIDrivers')) {
- processDriverDarwin(driverC, true);
- }
- }
-
- function checkDriverDarwin(driver) {
- var output = nodeChildProcess.execSync('kextstat').toString();
- return output.indexOf(driver) > -1;
- }
-
- function processDriverDarwin(driver, load, callback) {
- if (driver) {
- var command = (load ? 'kextload' : 'kextunload') + ' -b ' + driver;
- nodeSudo.exec(
- command,
- {name: 'Icestudio'},
- function (/*error, stdout, stderr*/) {
- if (callback) {
- callback();
- }
- }
- );
- } else if (callback) {
- callback();
- }
- }
-
- /*
- * Windows drivers
- */
-
- function enableWindowsDriversFTDI() {
- alerts.confirm({
- title: _tcStr('FTDI driver installation instructions'),
- body:
- _tcStr(
- '- Connect the FPGA board to the USB and wait until Windows finishes the default installation of the driver
- When the OK button is clicked, the FTDI driver installer will be launched in a new window
- In the installer, replace the (Interface 0) driver of the board by libusbK
- Unplug and reconnect the board
'
- ) + _tcStr('It is recommended to use USB 2.0 ports'),
- onok: () => {
- enableWindowsDrivers('ftdi');
- },
- });
- }
-
- function disableWindowsDriversFTDI() {
- alerts.confirm({
- title: _tcStr('FTDI driver uninstallation instructions'),
- body: _tcStr(
- '- Find the FPGA USB Device
- Select the board programmer and uninstall the driver
'
- ),
- onok: () => {
- disableWindowsDrivers('ftdi');
- },
- });
- }
-
- function enableWindowsDriversSerial() {
- alerts.confirm({
- title: _tcStr('Serial driver installation instructions'),
- body: _tcStr(
- '- Connect the FPGA board to the USB and wait until Windows finishes the default installation of the driver
- When the OK button is clicked, the Serial driver installer will be launched in a new window
- In the installer, follow the steps to install the driver
- Unplug and reconnect the board
'
- ),
- onok: () => {
- enableWindowsDrivers('serial');
- },
- });
- }
-
- function disableWindowsDriversSerial() {
- alerts.confirm({
- title: _tcStr('Serial driver uninstallation instructions'),
- body: _tcStr(
- '- Find the FPGA USB Device
- Select the board programmer and uninstall the driver
'
- ),
- onok: () => {
- disableWindowsDrivers('serial');
- },
- });
- }
-
- function enableWindowsDrivers(type) {
- var option = '--' + type + '-enable';
- utils.startWait();
- nodeSudo.exec(
- [common.APIO_CMD, 'drivers', option].join(' '),
- {name: 'Icestudio'},
- function (error, stdout, stderr) {
- utils.endWait();
- if (stderr) {
- alertify.error(
- _tcStr('Toolchain not installed') +
- '.
' +
- _tcStr('Click here to install it'),
- 30
- ).callback = function (isClicked) {
- if (isClicked) {
- $rootScope.$broadcast('installToolchain');
- }
- };
- } else if (!error) {
- alertify.message(
- _tcStr('Unplug and reconnect the board'),
- 5
- );
- }
- }
- );
- }
-
- function disableWindowsDrivers(type) {
- var option = '--' + type + '-disable';
- utils.startWait();
- nodeChildProcess.exec(
- [common.APIO_CMD, 'drivers', option].join(' '),
- function (error, stdout, stderr) {
- utils.endWait();
- if (stderr) {
- alertify.error(
- _tcStr('Toolchain not installed') +
- '.
' +
- _tcStr('Click here to install it'),
- 30
- ).callback = function (isClicked) {
- if (isClicked) {
- $rootScope.$broadcast('installToolchain');
- }
- };
- }
- }
- );
- }
- }
- );
diff --git a/services/tools.js b/services/tools.js
index aeb0727bc..3e0828a31 100644
--- a/services/tools.js
+++ b/services/tools.js
@@ -7,7 +7,6 @@ angular
project,
compiler,
collections,
- drivers,
graph,
utils,
common,
@@ -16,8 +15,7 @@ angular
nodeFse,
nodePath,
nodeChildProcess,
- _package,
- $rootScope
+ _package
) {
'use strict';
@@ -30,16 +28,9 @@ angular
var startAlert = null;
var infoAlert = null;
var resultAlert = null;
- var toolchain = {
- apio: '-',
- installed: false,
- disabled: false,
- };
-
- this.toolchain = toolchain;
this.verifyCode = function (startMessage, endMessage) {
- return apioRun(
+ return ICEToolRun(
['verify', '--board', common.selectedBoard.name],
startMessage,
endMessage
@@ -47,7 +38,7 @@ angular
};
this.buildCode = function (startMessage, endMessage) {
- return apioRun(
+ return ICEToolRun(
['build', '--board', common.selectedBoard.name],
startMessage,
endMessage
@@ -55,14 +46,14 @@ angular
};
this.uploadCode = function (startMessage, endMessage) {
- return apioRun(
+ return ICEToolRun(
['upload', '--board', common.selectedBoard.name],
startMessage,
endMessage
);
};
- function apioRun(commands, startMessage, endMessage) {
+ function ICEToolRun(commands, startMessage, endMessage) {
return new Promise(function (resolve) {
var sourceCode = '';
@@ -80,12 +71,7 @@ angular
.resetCodeErrors()
.then(function () {
return new Promise(function (resolve, reject) {
- if (toolchain.apio != '-') {
- resolve();
- } else {
- _toolchainAlert(true);
- reject();
- }
+ resolve();
});
})
.then(function () {
@@ -106,7 +92,6 @@ angular
if (command === 'build' || command === 'upload') {
commands = commands.concat('--verbose-pnr');
}
- console.log('APIO', commands);
return executeLocal(commands);
})
.then(function (result) {
@@ -279,55 +264,38 @@ angular
function executeLocal(commands) {
return new Promise(function (resolve) {
- if (commands[0] === 'upload') {
- // Upload command requires drivers setup (Mac OS)
- drivers.preUpload(function () {
- _executeLocal();
- });
- } else {
- // Other !upload commands
- _executeLocal();
- }
-
- function _executeLocal() {
- var apio = getApioExecutable();
- var command = [apio]
- .concat(commands)
- .concat(['-p', `"${common.BUILD_DIR}"`])
- .join(' ');
- console.log('APIO COMMAND', command);
- if (
- typeof common.DEBUGMODE !== 'undefined' &&
- common.DEBUGMODE === 1
- ) {
- const fs = require('fs');
- fs.appendFileSync(
- common.LOGFILE,
- 'tools._executeLocal>' + command + '\n'
- );
- }
- nodeChildProcess.exec(
- command,
- {
- maxBuffer: 5000 * 1024,
- }, // To avoid buffer overflow
- function (error, stdout, stderr) {
- if (commands[0] === 'upload') {
- // Upload command requires to restore the drivers (Mac OS)
- drivers.postUpload();
- }
- common.commandOutput = command + '\n\n' + stdout + stderr;
- $(document).trigger('commandOutputChanged', [
- common.commandOutput,
- ]);
- resolve({
- error: error,
- stdout: stdout,
- stderr: stderr,
- });
- }
+ var command = [common.ICETOOL]
+ .concat(commands)
+ .concat(['-p', `"${common.BUILD_DIR}"`])
+ .join(' ');
+ if (
+ typeof common.DEBUGMODE !== 'undefined' &&
+ common.DEBUGMODE === 1
+ ) {
+ const fs = require('fs');
+ fs.appendFileSync(
+ common.LOGFILE,
+ 'tools._executeLocal>' + command + '\n'
);
}
+ nodeChildProcess.exec(
+ command,
+ {
+ shell: 'bash',
+ maxBuffer: 5000 * 1024,
+ }, // To avoid buffer overflow
+ function (error, stdout, stderr) {
+ common.commandOutput = command + '\n\n' + stdout + stderr;
+ $(document).trigger('commandOutputChanged', [
+ common.commandOutput,
+ ]);
+ resolve({
+ error: error,
+ stdout: stdout,
+ stderr: stderr,
+ });
+ }
+ );
});
}
@@ -344,7 +312,6 @@ angular
if (stdout) {
var boardName = common.selectedBoard.name;
var boardLabel = common.selectedBoard.info.label;
- // - Apio errors
if (
stdout.indexOf(
'Error: board ' + boardName + ' not connected'
@@ -879,327 +846,6 @@ angular
}
}
- this.checkToolchain = _checkToolchain;
-
- function getApioExecutable() {
- const apio = process.env.ICESTUDIO_APIO;
- if (nodeFs.existsSync(apio)) {
- alertify.message('Using external apio: ' + apio, 5);
- return `"${apio}"`;
- }
- return common.APIO_CMD;
- }
-
- function _checkToolchain(callback) {
- var apio = getApioExecutable();
- console.log('[srv.tools.checkToolchain] apio:', apio);
- nodeChildProcess.exec(`${apio} --version`, function (error, stdout) {
- console.log('[srv.tools.checkToolchain] version:', stdout);
- if (error) {
- console.log('[srv.tools.checkToolchain] version error:', error);
- toolchain.apio = '-';
- _toolchainAlert(true);
- if (callback) {
- callback();
- }
- return;
- }
- toolchain.apio = stdout.match(/apio,\sversion\s(.+)/i)[1];
- console.log(
- '[srv.tools.checkToolchain] toolchain.apio:',
- toolchain.apio
- );
- if (toolchain.apio && toolchain.apio != '') {
- _toolchainAlert(
- false,
- `${_tcStr('Apio version')} v${toolchain.apio}`
- );
- // TODO: We should run some minimal test for ensuring that apio was correctly installed.
- // nodeChildProcess.exec(
- // `${apio} clean -p`,
- // (error, stdout, stderr) => {
- // console.log('[srv.tools.checkToolchain] clean sample:', error, stdout, stderr);
- // if (error) {
- // toolchain.apio = '-';
- // _toolchainAlert(false, _tcStr('Toolchain failed executing sample project!'));
- // }
- // if (callback) {
- // callback();
- // }
- // }
- // );
- if (callback) {
- callback();
- }
- return;
- }
- _toolchainAlert(false, _tcStr('Could not retrieve apio version!'));
- if (callback) {
- callback();
- }
- });
- }
-
- function executeCommand(command, callback) {
- var cmd = command.join(' ');
- nodeChildProcess.exec(cmd, (error, stdout, stderr) => {
- console.log(
- `[srv.tools.executeCommand] cmd: ${cmd}\nstdout: ${stdout}\nstderr: ${stderr}\nerror: ${error}`
- );
- common.commandOutput = `${cmd}\n\n${stdout}${stderr}`;
- $(document).trigger('commandOutputChanged', [common.commandOutput]);
- if (error) {
- alertify.error(error.message, 30);
- callback(true);
- } else {
- callback(false);
- }
- });
- }
-
- function _removeToolchain() {
- deleteFolderRecursive(common.ENV_DIR);
- deleteFolderRecursive(common.APIO_HOME_DIR);
- }
-
- $rootScope.$on('installToolchain', () => {
- _installToolchain();
- });
-
- this.installToolchain = _installToolchain;
-
- const nodeOnline = require('is-online');
-
- function _installToolchain() {
- if (resultAlert) {
- resultAlert.dismiss(false);
- }
- alerts.confirm({
- title: _tcStr('Toolchain installation'),
- body: _tcStr(
- 'The toolchain will be downloaded. This operation requires Internet connection.'
- ),
- onok: () => {
- _removeToolchain();
- alerts.alert({
- title: _tcStr('Installing toolchain'),
- body: ``,
- });
- toolchain.apio = '-';
-
- const _py = getPythonExecutable();
- var _epip = null;
-
- async.series(
- [
- // checkInternetConnection
- (callback) => {
- updateProgress(_tcStr('Check Internet connection...'), 0);
- nodeOnline({timeout: 5000}, function (err, online) {
- if (online) {
- callback(false);
- return;
- }
- resultAlert = alertify.error(
- _tcStr('Internet connection required'),
- 30
- );
- callback(true);
- });
- },
- // ensurePythonIsAvailable
- (callback) => {
- updateProgress(_tcStr('Check Python...'), 10);
- if (_py) {
- callback(false);
- return;
- }
- resultAlert = alertify.error(
- _tcStr('At least Python 3.5 is required'),
- 30
- );
- callback(true);
- },
- // createVirtualenv
- (callback) => {
- updateProgress(_tcStr('Create virtualenv...'), 20);
- if (nodeFs.existsSync(common.ENV_DIR)) {
- callback(false);
- return;
- }
- if (!nodeFs.existsSync(common.ICESTUDIO_DIR)) {
- nodeFs.mkdirSync(common.ICESTUDIO_DIR);
- }
- executeCommand(
- [_py, '-m', 'venv', `"${common.ENV_DIR}"`],
- callback
- );
- },
- // setupVirtualenv
- // see: https://bugs.python.org/issue30628 and https://stackoverflow.com/a/61553959
- (callback) => {
- updateProgress(_tcStr('Setup virtualenv...'), 25);
- if (!nodeFs.existsSync(common.ENV_DIR)) {
- callback(true);
- return;
- }
- if (!nodeFs.existsSync(common.ENV_BIN_DIR)) {
- callback(true);
- return;
- }
- _epip = [
- getPythonExecutable(common.ENV_BIN_DIR),
- '-m',
- 'pip',
- ];
-
- if (common.MSYSTEM) {
- callback(false);
- return;
- }
- executeCommand(
- _epip.concat([
- 'install',
- '-U',
- 'pip',
- 'setuptools',
- 'wheel',
- ]),
- callback
- );
- },
- // installOnlineApio
- (callback) => {
- updateProgress('Install apio', 50);
- const pkgs = '[blackiceprog,tinyfpgab,tinyprog,icefunprog]'; //icesprog,fujprog
- executeCommand(
- _epip.concat([
- 'install',
- '-U',
- `apio${pkgs}@https://github.com/${common.get(
- 'apioRepo'
- )}/archive/${common.get('apioRef')}.zip`,
- ]),
- callback
- );
- },
- // apioinstallPackages
- (callback) => {
- const pkgs =
- 'oss-cad-suite yosys ice40 ecp5 fujprog icesprog dfu iverilog drivers scons';
- updateProgress(`apio install ${pkgs}`, 75);
- apioInstall(pkgs, callback);
- },
- ],
- // installationCompleted
- (err, results) => {
- console.log(
- `[srv.tools.installationCompleted] err: ${err}\nresults: ${results}`
- );
- _checkToolchain(() => {
- if (toolchain.apio != '-') {
- updateProgress(_tcStr('Installation completed'), 100);
- alertify.success(_tcStr('Toolchain installed'));
- } else {
- alertify.failure(_tcStr('Toolchain installation failed'));
- }
- });
- }
- );
- },
- });
- }
-
- function _toolchainAlert(install, message) {
- if (resultAlert) {
- resultAlert.dismiss(false);
- }
- resultAlert = alertify.warning(
- !message
- ? `${_tcStr('Toolchain not found')}.
${_tcStr(
- 'Click here to install it'
- )}`
- : message,
- 10,
- function (isClicked) {
- if (install && isClicked) {
- _installToolchain();
- }
- }
- );
- }
-
- this.removeToolchain = function () {
- if (resultAlert) {
- resultAlert.dismiss(false);
- }
- alerts.confirm({
- title: _tcStr('The toolchain will be removed'),
- body: _tcStr('Do you want to continue?'),
- onok: () => {
- _removeToolchain();
- toolchain.apio = '-';
- alertify.success(_tcStr('Toolchain removed'));
- },
- });
- };
-
- this.enableDrivers = () => {
- _checkToolchain(() => {
- if (toolchain.apio != '-') {
- drivers.enable();
- }
- });
- };
-
- this.disableDrivers = () => {
- _checkToolchain(() => {
- if (toolchain.apio != '-') {
- drivers.disable();
- }
- });
- };
-
- function apioInstall(pkg, callback) {
- executeCommand([common.APIO_CMD, 'install', pkg], callback);
- }
-
- function setupDriversAlert() {
- if (!infoAlert) {
- infoAlert = alertify.message(
- _tcStr('Click here to setup the drivers'),
- 30
- );
- infoAlert.callback = function (isClicked) {
- infoAlert = null;
- if (isClicked) {
- if (resultAlert) {
- resultAlert.dismiss(false);
- }
- $rootScope.$broadcast('enableDrivers');
- }
- };
- }
- }
-
- function updateProgress(message, value) {
- var bar = $('#progress-bar');
- if (value === 100) {
- bar.removeClass('progress-bar-striped active');
- }
- bar.text(value + '%');
- bar.attr('aria-valuenow', value);
- bar.css('width', value + '%');
- $('#progress-message').text(message);
- }
-
// Collections management
this.saveCollections = () => {
diff --git a/tools/ICETool b/tools/ICETool
new file mode 100755
index 000000000..252395a56
--- /dev/null
+++ b/tools/ICETool
@@ -0,0 +1,259 @@
+#!/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 pathlib import Path
+from subprocess import check_call
+import click
+
+
+@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.
+ """
+
+ device = 'ice40' if board in ['TinyFPGA-B2'] else 'ecp5'
+
+ IVER_PATH = 'apath'
+ TARGET_SIM = 'atarget'
+ YOSYS_PATH = 'path'
+
+ 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'
+
+ #cmd = f'iverilog {IVER_PATH} -o $TARGET -D VCD_OUTPUT={TARGET_SIM} {opts} {YOSYS_PATH}/{device}/cells_sim.v {sources}'
+ cmd = f'iverilog {opts} {sources}'
+
+ print(cmd)
+ check_call(cmd, cwd=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'
+ cmd = f'yosys -p "proc; synth_ice40 -top main -json synth.json" {opts} {sources}'
+
+ print(cmd)
+ check_call(cmd, cwd=project_dir)
+ sys_stdout.flush()
+ sys_stderr.flush()
+
+ boards = {
+ 'icezum': {
+ 'device': 'ICE40-HX1K',
+ 'package': 'TQ144'
+ }
+ }
+
+ device = boards[board]['device'].split('-')[1].lower() if device is None else device
+ package = boards[board]['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'
+ cmd = f'nextpnr-ice40 --{device} --package {package} --pcf {pcf} --json synth.json --asc pnr.asc {opts}'
+
+ print(cmd)
+ check_call(cmd, cwd=project_dir)
+ sys_stdout.flush()
+ sys_stderr.flush()
+
+ cmd = 'icepack pnr.asc design.bin'
+
+ print(cmd)
+ check_call(cmd, cwd=project_dir)
+ sys_stdout.flush()
+ sys_stderr.flush()
+
+ print('board:', board)
+
+ 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.group()
+def cli():
+ pass
+
+cli.add_command(VerifyCommand)
+cli.add_command(BuildCommand)
+cli.add_command(UploadCommand)
+
+
+if __name__ == '__main__':
+ toolenv = getenv('ICETOOL_CMD', 'ICETool')
+ if toolenv != 'ICETool':
+ check_call([toolenv] + sys_argv[1:])
+ sys_exit()
+ cli()
diff --git a/views/preferences.html b/views/preferences.html
index c4429ca23..a4c8364c5 100644
--- a/views/preferences.html
+++ b/views/preferences.html
@@ -228,134 +228,3 @@
-->
-
-
-
-