yosys2digitaljs 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  name: Node.js CI
2
2
 
3
- on: [push]
3
+ on: [push, pull_request]
4
4
 
5
5
  jobs:
6
6
  build:
@@ -9,7 +9,7 @@ jobs:
9
9
 
10
10
  strategy:
11
11
  matrix:
12
- node-version: [8.x, 10.x, 12.x]
12
+ node-version: [12.x, 14.x, 16.x]
13
13
 
14
14
  steps:
15
15
  - uses: actions/checkout@v2
package/ChangeLog.md CHANGED
@@ -1,6 +1,20 @@
1
1
  # Changelog
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
+ ## [0.7.0] -- 2023-03-2023
5
+
6
+ ### Added
7
+
8
+ - Support for `$lut` cells
9
+ - Support for generating 7-segment display outputs
10
+
11
+ ## [0.6.0] -- 2022-02-02
12
+
13
+ ### Added
14
+
15
+ - Support for Yosys 0.11 cells `$aldff`, `$aldffe`
16
+ - Added a function `yosys2digitaljs` for converting a Yosys JSON output obtained elsewhere, without running Yosys locally
17
+
4
18
  ## [0.5.0] -- 2021-10-06
5
19
 
6
20
  ### Added
package/README.md CHANGED
@@ -1,11 +1,10 @@
1
- [![Build Status](https://travis-ci.org/tilk/yosys2digitaljs.svg?branch=master)](https://travis-ci.org/tilk/yosys2digitaljs)
2
1
  # yosys2digitaljs
3
- This program converts JSON netlist output generated by [Yosys](http://www.clifford.at/yosys/)
4
- circuit synthesis software for use with the
2
+ This program converts JSON netlist output generated by [Yosys](https://yosyshq.net/yosys/)
3
+ circuit synthesis software (Github repo [here](https://github.com/YosysHQ/yosys/)) for use with the
5
4
  [DigitalJS](http://github.com/tilk/digitaljs) graphical circuit simulator.
6
5
 
7
6
  # Usage
8
- You need to have [Yosys](http://www.clifford.at/yosys/) installed to run
7
+ You need to have [Yosys](https://yosyshq.net/yosys/) installed to run
9
8
  yosys2digitaljs. For example, in Debian/Ubuntu, run:
10
9
  ```bash
11
10
  apt install yosys
@@ -25,9 +24,10 @@ The generated JSON is printed on standard output.
25
24
  # API
26
25
  Yosys2digitaljs can be used as a library. The API is promise (or async/await) based. Available functions are:
27
26
 
28
- - `process_sv(sv_text)` - converts a single SystemVerilog source passed as a string.
29
- - `process_files(texts)` - converts multiple Verilog/SystemVerilog sources. The `texts` parameter is an object, with keys being file names, and corresponding values containing the file contents as strings. Example: `{ 'test.sv': 'module test; ...' }`.
30
- - `process(filenames, dirname)` - converts Verilog/SystemVerilog sources saved on the filesystem under names `filenames` in the directory `dirname`.
27
+ - `yosys2digitaljs(json, options)` - converts the Yosys JSON output `json` (passed as an JS object) to a DigitalJS representation of the same circuit.
28
+ - `process_sv(sv_text, options)` - converts a single SystemVerilog source passed as a string.
29
+ - `process_files(texts, options)` - converts multiple Verilog/SystemVerilog sources. The `texts` parameter is an object, with keys being file names, and corresponding values containing the file contents as strings. Example: `{ 'test.sv': 'module test; ...' }`.
30
+ - `process(filenames, dirname, options)` - converts Verilog/SystemVerilog sources saved on the filesystem under names `filenames` in the directory `dirname`.
31
31
 
32
32
  The functions return a promise, which fulfills with an object value with following keys:
33
33
 
package/dist/index.d.ts CHANGED
@@ -53,8 +53,86 @@ declare namespace Digitaljs {
53
53
  };
54
54
  };
55
55
  }
56
- declare type Options = {
56
+ declare namespace Yosys {
57
+ type BitChar = '0' | '1' | 'x';
58
+ type Bit = number | '0' | '1' | 'x';
59
+ type BitVector = Bit[];
60
+ type Port = {
61
+ direction: 'input' | 'output' | 'inout';
62
+ bits: any;
63
+ };
64
+ type Parameters = {
65
+ WIDTH?: JsonConstant;
66
+ A_WIDTH?: JsonConstant;
67
+ B_WIDTH?: JsonConstant;
68
+ S_WIDTH?: JsonConstant;
69
+ Y_WIDTH?: JsonConstant;
70
+ A_SIGNED?: JsonConstant;
71
+ B_SIGNED?: JsonConstant;
72
+ CLK_POLARITY?: JsonConstant;
73
+ EN_POLARITY?: JsonConstant;
74
+ ARST_POLARITY?: JsonConstant;
75
+ ARST_VALUE: JsonConstant;
76
+ CTRL_IN_WIDTH?: JsonConstant;
77
+ CTRL_OUT_WIDTH?: JsonConstant;
78
+ TRANS_NUM?: JsonConstant;
79
+ STATE_NUM?: JsonConstant;
80
+ STATE_NUM_LOG2?: JsonConstant;
81
+ STATE_RST?: JsonConstant;
82
+ RD_PORTS?: JsonConstant;
83
+ WR_PORTS?: JsonConstant;
84
+ RD_CLK_POLARITY?: JsonConstant;
85
+ RD_CLK_ENABLE?: JsonConstant;
86
+ RD_CLK_TRANSPARENT?: JsonConstant;
87
+ WR_CLK_POLARITY?: JsonConstant;
88
+ WR_CLK_ENABLE?: JsonConstant;
89
+ [key: string]: any;
90
+ };
91
+ type JsonConstant = number | string;
92
+ type Attributes = {
93
+ init: JsonConstant;
94
+ [key: string]: any;
95
+ };
96
+ type Cell = {
97
+ hide_name: 0 | 1;
98
+ type: string;
99
+ parameters: Parameters;
100
+ attributes: Attributes;
101
+ port_directions: {
102
+ [key: string]: 'input' | 'output';
103
+ };
104
+ connections: {
105
+ [key: string]: BitVector;
106
+ };
107
+ };
108
+ type Net = {
109
+ hide_name: 0 | 1;
110
+ bits: BitVector;
111
+ attributes: {
112
+ [key: string]: string;
113
+ };
114
+ };
115
+ type Module = {
116
+ ports: {
117
+ [key: string]: Port;
118
+ };
119
+ cells: {
120
+ [key: string]: Cell;
121
+ };
122
+ netnames: {
123
+ [key: string]: Net;
124
+ };
125
+ };
126
+ type Output = {
127
+ modules: {
128
+ [key: string]: Module;
129
+ };
130
+ };
131
+ }
132
+ declare type ConvertOptions = {
57
133
  propagation?: number;
134
+ };
135
+ declare type Options = ConvertOptions & {
58
136
  optimize?: boolean;
59
137
  fsmexpand?: boolean;
60
138
  fsm?: boolean | "nomap";
@@ -76,10 +154,11 @@ declare type LintMessage = {
76
154
  message: string;
77
155
  };
78
156
  export declare function verilator_lint(filenames: string[], dirname?: string, options?: Options): Promise<LintMessage[]>;
157
+ export declare function yosys2digitaljs(obj: Yosys.Output, options?: ConvertOptions): Digitaljs.TopModule;
79
158
  export declare function process(filenames: string[], dirname?: string, options?: Options): Promise<Output>;
80
159
  export declare function io_ui(output: Digitaljs.Module): void;
81
160
  export declare function process_files(data: {
82
161
  [key: string]: string;
83
- }, options: Options): Promise<Output>;
84
- export declare function process_sv(text: string): Promise<Output>;
162
+ }, options?: Options): Promise<Output>;
163
+ export declare function process_sv(text: string, options?: Options): Promise<Output>;
85
164
  export {};
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.process_sv = exports.process_files = exports.io_ui = exports.process = exports.verilator_lint = void 0;
4
+ exports.process_sv = exports.process_files = exports.io_ui = exports.process = exports.yosys2digitaljs = exports.verilator_lint = void 0;
5
5
  const tmp = require("tmp-promise");
6
6
  const child_process = require("child_process");
7
7
  const assert = require("assert");
@@ -62,6 +62,7 @@ const gate_subst = new Map([
62
62
  ['$pmux', 'Mux1Hot'],
63
63
  ['$mem', 'Memory'],
64
64
  ['$mem_v2', 'Memory'],
65
+ ['$lut', 'Memory'],
65
66
  ['$fsm', 'FSM'],
66
67
  ['$clock', 'Clock'],
67
68
  ['$button', 'Button'],
@@ -95,7 +96,9 @@ const gate_subst = new Map([
95
96
  ['$adlatch', 'Dff'],
96
97
  ['$sr', 'Dff'],
97
98
  ['$dffsr', 'Dff'],
98
- ['$dffsre', 'Dff']
99
+ ['$dffsre', 'Dff'],
100
+ ['$aldff', 'Dff'],
101
+ ['$aldffe', 'Dff']
99
102
  ]);
100
103
  const gate_negations = new Map([
101
104
  ['And', 'Nand'],
@@ -149,6 +152,8 @@ function order_ports(data) {
149
152
  '$adlatch': { EN: 'en', ARST: 'arst', D: 'in', Q: 'out' },
150
153
  '$dffsr': { CLK: 'clk', SET: 'set', CLR: 'clr', D: 'in', Q: 'out' },
151
154
  '$dffsre': { CLK: 'clk', EN: 'en', SET: 'set', CLR: 'clr', D: 'in', Q: 'out' },
155
+ '$aldff': { CLK: 'clk', ALOAD: 'aload', AD: 'ain', D: 'in', Q: 'out' },
156
+ '$aldffe': { CLK: 'clk', EN: 'en', ALOAD: 'aload', AD: 'ain', D: 'in', Q: 'out' },
152
157
  '$sr': { SET: 'set', CLR: 'clr', Q: 'out' },
153
158
  '$fsm': { ARST: 'arst', CLK: 'clk', CTRL_IN: 'in', CTRL_OUT: 'out' }
154
159
  };
@@ -436,7 +441,7 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
436
441
  assert(cell.port_directions.B == 'input');
437
442
  assert(cell.port_directions.Y == 'output');
438
443
  }
439
- if (['$dff', '$dffe', '$adff', '$adffe', '$sdff', '$sdffe', '$sdffce', '$dlatch', '$adlatch', '$dffsr', '$dffsre'].includes(cell.type)) {
444
+ if (['$dff', '$dffe', '$adff', '$adffe', '$sdff', '$sdffe', '$sdffce', '$dlatch', '$adlatch', '$dffsr', '$dffsre', '$aldff', '$aldffe'].includes(cell.type)) {
440
445
  assert(cell.connections.D.length == decode_json_number(cell.parameters.WIDTH));
441
446
  assert(cell.connections.Q.length == decode_json_number(cell.parameters.WIDTH));
442
447
  assert(cell.port_directions.D == 'input');
@@ -446,6 +451,18 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
446
451
  assert(cell.port_directions.CLK == 'input');
447
452
  }
448
453
  }
454
+ if (['$dffe', '$adffe', '$sdffe', '$sdffce', '$dffsre', '$aldffe', '$dlatch', '$adlatch'].includes(cell.type)) {
455
+ assert(cell.connections.EN.length == 1);
456
+ assert(cell.port_directions.EN == 'input');
457
+ }
458
+ if (['$adff', '$adffe', '$adlatch'].includes(cell.type)) {
459
+ assert(cell.connections.ARST.length == 1);
460
+ assert(cell.port_directions.ARST == 'input');
461
+ }
462
+ if (['$sdff', '$sdffe', '$sdffce'].includes(cell.type)) {
463
+ assert(cell.connections.SRST.length == 1);
464
+ assert(cell.port_directions.SRST == 'input');
465
+ }
449
466
  if (['$dffsr', '$dffsre'].includes(cell.type)) {
450
467
  assert(cell.connections.SET.length == decode_json_number(cell.parameters.WIDTH));
451
468
  assert(cell.connections.CLR.length == decode_json_number(cell.parameters.WIDTH));
@@ -592,17 +609,28 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
592
609
  };
593
610
  break;
594
611
  case '$dffe':
595
- assert(cell.connections.EN.length == 1);
596
- assert(cell.port_directions.EN == 'input');
597
612
  dev.bits = decode_json_number(cell.parameters.WIDTH);
598
613
  dev.polarity = {
599
614
  clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
600
615
  enable: Boolean(decode_json_number(cell.parameters.EN_POLARITY))
601
616
  };
602
617
  break;
618
+ case '$aldff':
619
+ dev.bits = decode_json_number(cell.parameters.WIDTH);
620
+ dev.polarity = {
621
+ clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
622
+ aload: Boolean(decode_json_number(cell.parameters.ALOAD_POLARITY))
623
+ };
624
+ break;
625
+ case '$aldffe':
626
+ dev.bits = decode_json_number(cell.parameters.WIDTH);
627
+ dev.polarity = {
628
+ clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
629
+ enable: Boolean(decode_json_number(cell.parameters.EN_POLARITY)),
630
+ aload: Boolean(decode_json_number(cell.parameters.ALOAD_POLARITY))
631
+ };
632
+ break;
603
633
  case '$adff':
604
- assert(cell.connections.ARST.length == 1);
605
- assert(cell.port_directions.ARST == 'input');
606
634
  dev.bits = decode_json_number(cell.parameters.WIDTH);
607
635
  dev.polarity = {
608
636
  clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
@@ -611,8 +639,6 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
611
639
  dev.arst_value = decode_json_constant(cell.parameters.ARST_VALUE, dev.bits);
612
640
  break;
613
641
  case '$sdff':
614
- assert(cell.connections.SRST.length == 1);
615
- assert(cell.port_directions.SRST == 'input');
616
642
  dev.bits = decode_json_number(cell.parameters.WIDTH);
617
643
  dev.polarity = {
618
644
  clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
@@ -621,10 +647,6 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
621
647
  dev.srst_value = decode_json_constant(cell.parameters.SRST_VALUE, dev.bits);
622
648
  break;
623
649
  case '$adffe':
624
- assert(cell.connections.ARST.length == 1);
625
- assert(cell.port_directions.ARST == 'input');
626
- assert(cell.connections.EN.length == 1);
627
- assert(cell.port_directions.EN == 'input');
628
650
  dev.bits = decode_json_number(cell.parameters.WIDTH);
629
651
  dev.polarity = {
630
652
  clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
@@ -634,10 +656,6 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
634
656
  dev.arst_value = decode_json_constant(cell.parameters.ARST_VALUE, dev.bits);
635
657
  break;
636
658
  case '$sdffe':
637
- assert(cell.connections.SRST.length == 1);
638
- assert(cell.port_directions.SRST == 'input');
639
- assert(cell.connections.EN.length == 1);
640
- assert(cell.port_directions.EN == 'input');
641
659
  dev.bits = decode_json_number(cell.parameters.WIDTH);
642
660
  dev.polarity = {
643
661
  clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
@@ -647,10 +665,6 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
647
665
  dev.srst_value = decode_json_constant(cell.parameters.SRST_VALUE, dev.bits);
648
666
  break;
649
667
  case '$sdffce':
650
- assert(cell.connections.SRST.length == 1);
651
- assert(cell.port_directions.SRST == 'input');
652
- assert(cell.connections.EN.length == 1);
653
- assert(cell.port_directions.EN == 'input');
654
668
  dev.bits = decode_json_number(cell.parameters.WIDTH);
655
669
  dev.polarity = {
656
670
  clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
@@ -661,18 +675,12 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
661
675
  dev.srst_value = decode_json_constant(cell.parameters.SRST_VALUE, dev.bits);
662
676
  break;
663
677
  case '$dlatch':
664
- assert(cell.connections.EN.length == 1);
665
- assert(cell.port_directions.EN == 'input');
666
678
  dev.bits = decode_json_number(cell.parameters.WIDTH);
667
679
  dev.polarity = {
668
680
  enable: Boolean(decode_json_number(cell.parameters.EN_POLARITY))
669
681
  };
670
682
  break;
671
683
  case '$adlatch':
672
- assert(cell.connections.EN.length == 1);
673
- assert(cell.port_directions.EN == 'input');
674
- assert(cell.connections.ARST.length == 1);
675
- assert(cell.port_directions.ARST == 'input');
676
684
  dev.bits = decode_json_number(cell.parameters.WIDTH);
677
685
  dev.polarity = {
678
686
  enable: Boolean(decode_json_number(cell.parameters.EN_POLARITY)),
@@ -689,8 +697,6 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
689
697
  };
690
698
  break;
691
699
  case '$dffsre':
692
- assert(cell.connections.EN.length == 1);
693
- assert(cell.port_directions.EN == 'input');
694
700
  dev.bits = decode_json_number(cell.parameters.WIDTH);
695
701
  dev.polarity = {
696
702
  clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
@@ -860,6 +866,23 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
860
866
  }
861
867
  break;
862
868
  }
869
+ case '$lut':
870
+ assert(cell.connections.A.length == decode_json_number(cell.parameters.WIDTH));
871
+ assert(cell.connections.Y.length == 1);
872
+ assert(cell.port_directions.A == 'input');
873
+ assert(cell.port_directions.Y == 'output');
874
+ dev.abits = cell.connections.A.length;
875
+ dev.bits = cell.connections.Y.length;
876
+ dev.rdports = [{}];
877
+ dev.wrports = [];
878
+ dev.memdata = cell.parameters.LUT.split('').reverse();
879
+ assert(dev.memdata.length == Math.pow(2, dev.abits));
880
+ // Rewrite cell connections to be $mem compatible for port mapping
881
+ cell.connections.RD_ADDR = cell.connections.A;
882
+ cell.connections.RD_DATA = cell.connections.Y;
883
+ delete cell.connections.A;
884
+ delete cell.connections.Y;
885
+ break;
863
886
  default:
864
887
  }
865
888
  if (dev.type == 'Dff') {
@@ -882,6 +905,8 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
882
905
  connect_mem(dname, cell, dev);
883
906
  else if (cell.type == '$mem_v2')
884
907
  connect_mem(dname, cell, dev);
908
+ else if (cell.type == '$lut')
909
+ connect_mem(dname, cell, dev);
885
910
  else
886
911
  throw Error('Invalid cell type: ' + cell.type);
887
912
  }
@@ -1020,6 +1045,18 @@ async function verilator_lint(filenames, dirname, options = {}) {
1020
1045
  }
1021
1046
  }
1022
1047
  exports.verilator_lint = verilator_lint;
1048
+ function yosys2digitaljs(obj, options = {}) {
1049
+ const portmaps = order_ports(obj);
1050
+ const out = yosys_to_digitaljs(obj, portmaps, options);
1051
+ const toporder = topsort(module_deps(obj));
1052
+ toporder.pop();
1053
+ const toplevel = toporder.pop();
1054
+ const output = Object.assign({ subcircuits: {} }, out[toplevel]);
1055
+ for (const x of toporder)
1056
+ output.subcircuits[x] = out[x];
1057
+ return output;
1058
+ }
1059
+ exports.yosys2digitaljs = yosys2digitaljs;
1023
1060
  async function process(filenames, dirname, options = {}) {
1024
1061
  const optimize_simp = options.optimize ? "; opt" : "; opt_clean";
1025
1062
  const optimize = options.optimize ? "; opt -full" : "; opt_clean";
@@ -1044,14 +1081,7 @@ async function process(filenames, dirname, options = {}) {
1044
1081
  }
1045
1082
  obj = JSON.parse(fs.readFileSync(tmpjson, 'utf8'));
1046
1083
  await (0, util_1.promisify)(fs.unlink)(tmpjson);
1047
- const portmaps = order_ports(obj);
1048
- const out = yosys_to_digitaljs(obj, portmaps, options);
1049
- const toporder = topsort(module_deps(obj));
1050
- toporder.pop();
1051
- const toplevel = toporder.pop();
1052
- const output = Object.assign({ subcircuits: {} }, out[toplevel]);
1053
- for (const x of toporder)
1054
- output.subcircuits[x] = out[x];
1084
+ const output = yosys2digitaljs(obj, options);
1055
1085
  const ret = {
1056
1086
  output: output,
1057
1087
  yosys_output: obj,
@@ -1083,12 +1113,18 @@ function io_ui(output) {
1083
1113
  }
1084
1114
  if (dev.type == 'Input')
1085
1115
  dev.type = dev.bits == 1 ? 'Button' : 'NumEntry';
1086
- if (dev.type == 'Output')
1087
- dev.type = dev.bits == 1 ? 'Lamp' : 'NumDisplay';
1116
+ if (dev.type == 'Output') {
1117
+ if (dev.bits == 1)
1118
+ dev.type = 'Lamp';
1119
+ else if (dev.bits == 8 && (dev.label == 'display7' || dev.label.startsWith('display7_')))
1120
+ dev.type = 'Display7';
1121
+ else
1122
+ dev.type = 'NumDisplay';
1123
+ }
1088
1124
  }
1089
1125
  }
1090
1126
  exports.io_ui = io_ui;
1091
- async function process_files(data, options) {
1127
+ async function process_files(data, options = {}) {
1092
1128
  const dir = await tmp.dir();
1093
1129
  const names = [];
1094
1130
  try {
@@ -1108,12 +1144,12 @@ async function process_files(data, options) {
1108
1144
  }
1109
1145
  }
1110
1146
  exports.process_files = process_files;
1111
- async function process_sv(text) {
1147
+ async function process_sv(text, options = {}) {
1112
1148
  const tmpsv = await tmp.file({ postfix: '.sv' });
1113
1149
  try {
1114
1150
  await (0, util_1.promisify)(fs.write)(tmpsv.fd, text);
1115
1151
  await (0, util_1.promisify)(fs.close)(tmpsv.fd);
1116
- return await process([tmpsv.path]);
1152
+ return await process([tmpsv.path], undefined, options);
1117
1153
  }
1118
1154
  finally {
1119
1155
  tmpsv.cleanup();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yosys2digitaljs",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "Export Yosys netlists to a logic simulator",
5
5
  "main": "dist/index",
6
6
  "types": "dist/index.d.ts",
@@ -13,7 +13,7 @@
13
13
  "author": "Marek Materzok",
14
14
  "license": "BSD-2-Clause",
15
15
  "dependencies": {
16
- "3vl": "^0.3.5",
16
+ "3vl": "^1.0.1",
17
17
  "big-integer": "^1.6.49",
18
18
  "hashmap": "^2.4.0",
19
19
  "minimist": "^1.2.5",
package/result.json ADDED
@@ -0,0 +1,420 @@
1
+ {
2
+ "creator": "Yosys 0.8 (git sha1 5706e90)",
3
+ "modules": {
4
+ "fsm": {
5
+ "attributes": {
6
+ "src": "tests/fsm.sv:1"
7
+ },
8
+ "ports": {
9
+ "clk": {
10
+ "direction": "input",
11
+ "bits": [ 2 ]
12
+ },
13
+ "rst": {
14
+ "direction": "input",
15
+ "bits": [ 3 ]
16
+ },
17
+ "a": {
18
+ "direction": "input",
19
+ "bits": [ 4 ]
20
+ },
21
+ "b": {
22
+ "direction": "output",
23
+ "bits": [ 5 ]
24
+ }
25
+ },
26
+ "cells": {
27
+ "$auto$simplemap.cc:136:simplemap_reduce$41": {
28
+ "hide_name": 1,
29
+ "type": "$_OR_",
30
+ "parameters": {
31
+ },
32
+ "attributes": {
33
+ },
34
+ "port_directions": {
35
+ "A": "input",
36
+ "B": "input",
37
+ "Y": "output"
38
+ },
39
+ "connections": {
40
+ "A": [ 6 ],
41
+ "B": [ 7 ],
42
+ "Y": [ 8 ]
43
+ }
44
+ },
45
+ "$auto$simplemap.cc:136:simplemap_reduce$61": {
46
+ "hide_name": 1,
47
+ "type": "$_OR_",
48
+ "parameters": {
49
+ },
50
+ "attributes": {
51
+ "src": "tests/fsm.sv:16"
52
+ },
53
+ "port_directions": {
54
+ "A": "input",
55
+ "B": "input",
56
+ "Y": "output"
57
+ },
58
+ "connections": {
59
+ "A": [ 7 ],
60
+ "B": [ 9 ],
61
+ "Y": [ 10 ]
62
+ }
63
+ },
64
+ "$auto$simplemap.cc:136:simplemap_reduce$63": {
65
+ "hide_name": 1,
66
+ "type": "$_OR_",
67
+ "parameters": {
68
+ },
69
+ "attributes": {
70
+ "src": "tests/fsm.sv:16"
71
+ },
72
+ "port_directions": {
73
+ "A": "input",
74
+ "B": "input",
75
+ "Y": "output"
76
+ },
77
+ "connections": {
78
+ "A": [ 6 ],
79
+ "B": [ 11 ],
80
+ "Y": [ 12 ]
81
+ }
82
+ },
83
+ "$auto$simplemap.cc:206:simplemap_lognot$52": {
84
+ "hide_name": 1,
85
+ "type": "$_NOT_",
86
+ "parameters": {
87
+ },
88
+ "attributes": {
89
+ },
90
+ "port_directions": {
91
+ "A": "input",
92
+ "Y": "output"
93
+ },
94
+ "connections": {
95
+ "A": [ 13 ],
96
+ "Y": [ 14 ]
97
+ }
98
+ },
99
+ "$auto$simplemap.cc:206:simplemap_lognot$59": {
100
+ "hide_name": 1,
101
+ "type": "$_NOT_",
102
+ "parameters": {
103
+ },
104
+ "attributes": {
105
+ },
106
+ "port_directions": {
107
+ "A": "input",
108
+ "Y": "output"
109
+ },
110
+ "connections": {
111
+ "A": [ 15 ],
112
+ "Y": [ 16 ]
113
+ }
114
+ },
115
+ "$auto$simplemap.cc:496:simplemap_adff$42": {
116
+ "hide_name": 1,
117
+ "type": "$_DFF_PP1_",
118
+ "parameters": {
119
+ },
120
+ "attributes": {
121
+ },
122
+ "port_directions": {
123
+ "C": "input",
124
+ "D": "input",
125
+ "Q": "output",
126
+ "R": "input"
127
+ },
128
+ "connections": {
129
+ "C": [ 2 ],
130
+ "D": [ 11 ],
131
+ "Q": [ 6 ],
132
+ "R": [ 3 ]
133
+ }
134
+ },
135
+ "$auto$simplemap.cc:496:simplemap_adff$43": {
136
+ "hide_name": 1,
137
+ "type": "$_DFF_PP0_",
138
+ "parameters": {
139
+ },
140
+ "attributes": {
141
+ },
142
+ "port_directions": {
143
+ "C": "input",
144
+ "D": "input",
145
+ "Q": "output",
146
+ "R": "input"
147
+ },
148
+ "connections": {
149
+ "C": [ 2 ],
150
+ "D": [ 8 ],
151
+ "Q": [ 9 ],
152
+ "R": [ 3 ]
153
+ }
154
+ },
155
+ "$auto$simplemap.cc:496:simplemap_adff$44": {
156
+ "hide_name": 1,
157
+ "type": "$_DFF_PP0_",
158
+ "parameters": {
159
+ },
160
+ "attributes": {
161
+ },
162
+ "port_directions": {
163
+ "C": "input",
164
+ "D": "input",
165
+ "Q": "output",
166
+ "R": "input"
167
+ },
168
+ "connections": {
169
+ "C": [ 2 ],
170
+ "D": [ 17 ],
171
+ "Q": [ 7 ],
172
+ "R": [ 3 ]
173
+ }
174
+ },
175
+ "$auto$simplemap.cc:496:simplemap_adff$45": {
176
+ "hide_name": 1,
177
+ "type": "$_DFF_PP0_",
178
+ "parameters": {
179
+ },
180
+ "attributes": {
181
+ },
182
+ "port_directions": {
183
+ "C": "input",
184
+ "D": "input",
185
+ "Q": "output",
186
+ "R": "input"
187
+ },
188
+ "connections": {
189
+ "C": [ 2 ],
190
+ "D": [ 18 ],
191
+ "Q": [ 11 ],
192
+ "R": [ 3 ]
193
+ }
194
+ },
195
+ "$auto$simplemap.cc:85:simplemap_bitop$38": {
196
+ "hide_name": 1,
197
+ "type": "$_AND_",
198
+ "parameters": {
199
+ },
200
+ "attributes": {
201
+ },
202
+ "port_directions": {
203
+ "A": "input",
204
+ "B": "input",
205
+ "Y": "output"
206
+ },
207
+ "connections": {
208
+ "A": [ 14 ],
209
+ "B": [ 9 ],
210
+ "Y": [ 17 ]
211
+ }
212
+ },
213
+ "$auto$simplemap.cc:85:simplemap_bitop$39": {
214
+ "hide_name": 1,
215
+ "type": "$_AND_",
216
+ "parameters": {
217
+ },
218
+ "attributes": {
219
+ },
220
+ "port_directions": {
221
+ "A": "input",
222
+ "B": "input",
223
+ "Y": "output"
224
+ },
225
+ "connections": {
226
+ "A": [ 16 ],
227
+ "B": [ 9 ],
228
+ "Y": [ 18 ]
229
+ }
230
+ },
231
+ "$auto$simplemap.cc:85:simplemap_bitop$48": {
232
+ "hide_name": 1,
233
+ "type": "$_XOR_",
234
+ "parameters": {
235
+ },
236
+ "attributes": {
237
+ },
238
+ "port_directions": {
239
+ "A": "input",
240
+ "B": "input",
241
+ "Y": "output"
242
+ },
243
+ "connections": {
244
+ "A": [ 4 ],
245
+ "B": [ "0" ],
246
+ "Y": [ 13 ]
247
+ }
248
+ },
249
+ "$auto$simplemap.cc:85:simplemap_bitop$55": {
250
+ "hide_name": 1,
251
+ "type": "$_XOR_",
252
+ "parameters": {
253
+ },
254
+ "attributes": {
255
+ },
256
+ "port_directions": {
257
+ "A": "input",
258
+ "B": "input",
259
+ "Y": "output"
260
+ },
261
+ "connections": {
262
+ "A": [ 4 ],
263
+ "B": [ "1" ],
264
+ "Y": [ 15 ]
265
+ }
266
+ },
267
+ "$procmux$3": {
268
+ "hide_name": 1,
269
+ "type": "$pmux",
270
+ "parameters": {
271
+ "S_WIDTH": 2,
272
+ "WIDTH": 1
273
+ },
274
+ "attributes": {
275
+ "src": "tests/fsm.sv:16"
276
+ },
277
+ "port_directions": {
278
+ "A": "input",
279
+ "B": "input",
280
+ "S": "input",
281
+ "Y": "output"
282
+ },
283
+ "connections": {
284
+ "A": [ "x" ],
285
+ "B": [ "1", "0" ],
286
+ "S": [ 10, 12 ],
287
+ "Y": [ 5 ]
288
+ }
289
+ }
290
+ },
291
+ "netnames": {
292
+ "$auto$fsm_map.cc:118:implement_pattern_cache$31": {
293
+ "hide_name": 1,
294
+ "bits": [ 17 ],
295
+ "attributes": {
296
+ }
297
+ },
298
+ "$auto$fsm_map.cc:118:implement_pattern_cache$35": {
299
+ "hide_name": 1,
300
+ "bits": [ 18 ],
301
+ "attributes": {
302
+ }
303
+ },
304
+ "$auto$fsm_map.cc:170:map_fsm$24": {
305
+ "hide_name": 1,
306
+ "bits": [ 19, 8 ],
307
+ "attributes": {
308
+ }
309
+ },
310
+ "$auto$fsm_map.cc:74:implement_pattern_cache$29": {
311
+ "hide_name": 1,
312
+ "bits": [ 14 ],
313
+ "attributes": {
314
+ }
315
+ },
316
+ "$auto$fsm_map.cc:74:implement_pattern_cache$33": {
317
+ "hide_name": 1,
318
+ "bits": [ 16 ],
319
+ "attributes": {
320
+ }
321
+ },
322
+ "$auto$simplemap.cc:127:simplemap_reduce$40": {
323
+ "hide_name": 1,
324
+ "bits": [ 20 ],
325
+ "attributes": {
326
+ }
327
+ },
328
+ "$auto$simplemap.cc:127:simplemap_reduce$60": {
329
+ "hide_name": 1,
330
+ "bits": [ 21 ],
331
+ "attributes": {
332
+ }
333
+ },
334
+ "$auto$simplemap.cc:127:simplemap_reduce$62": {
335
+ "hide_name": 1,
336
+ "bits": [ 22 ],
337
+ "attributes": {
338
+ }
339
+ },
340
+ "$auto$simplemap.cc:250:simplemap_eqne$46": {
341
+ "hide_name": 1,
342
+ "bits": [ 13 ],
343
+ "attributes": {
344
+ }
345
+ },
346
+ "$auto$simplemap.cc:250:simplemap_eqne$53": {
347
+ "hide_name": 1,
348
+ "bits": [ 15 ],
349
+ "attributes": {
350
+ }
351
+ },
352
+ "$auto$simplemap.cc:256:simplemap_eqne$49": {
353
+ "hide_name": 1,
354
+ "bits": [ 13 ],
355
+ "attributes": {
356
+ }
357
+ },
358
+ "$auto$simplemap.cc:256:simplemap_eqne$56": {
359
+ "hide_name": 1,
360
+ "bits": [ 15 ],
361
+ "attributes": {
362
+ }
363
+ },
364
+ "$auto$wreduce.cc:347:run$37": {
365
+ "hide_name": 1,
366
+ "bits": [ 19, 8, 23, 24 ],
367
+ "attributes": {
368
+ }
369
+ },
370
+ "$procmux$4_CTRL": {
371
+ "hide_name": 1,
372
+ "bits": [ 10 ],
373
+ "attributes": {
374
+ }
375
+ },
376
+ "$procmux$5_CTRL": {
377
+ "hide_name": 1,
378
+ "bits": [ 12 ],
379
+ "attributes": {
380
+ }
381
+ },
382
+ "a": {
383
+ "hide_name": 0,
384
+ "bits": [ 4 ],
385
+ "attributes": {
386
+ "src": "tests/fsm.sv:1"
387
+ }
388
+ },
389
+ "b": {
390
+ "hide_name": 0,
391
+ "bits": [ 5 ],
392
+ "attributes": {
393
+ "src": "tests/fsm.sv:1"
394
+ }
395
+ },
396
+ "clk": {
397
+ "hide_name": 0,
398
+ "bits": [ 2 ],
399
+ "attributes": {
400
+ "src": "tests/fsm.sv:1"
401
+ }
402
+ },
403
+ "rst": {
404
+ "hide_name": 0,
405
+ "bits": [ 3 ],
406
+ "attributes": {
407
+ "src": "tests/fsm.sv:1"
408
+ }
409
+ },
410
+ "state": {
411
+ "hide_name": 0,
412
+ "bits": [ 6, 9, 7, 11 ],
413
+ "attributes": {
414
+ "onehot": 1
415
+ }
416
+ }
417
+ }
418
+ }
419
+ }
420
+ }
package/src/index.ts CHANGED
@@ -61,6 +61,7 @@ const gate_subst = new Map([
61
61
  ['$pmux', 'Mux1Hot'],
62
62
  ['$mem', 'Memory'],
63
63
  ['$mem_v2', 'Memory'],
64
+ ['$lut', 'Memory'],
64
65
  ['$fsm', 'FSM'],
65
66
  ['$clock', 'Clock'],
66
67
  ['$button', 'Button'],
@@ -94,7 +95,9 @@ const gate_subst = new Map([
94
95
  ['$adlatch', 'Dff'],
95
96
  ['$sr', 'Dff'],
96
97
  ['$dffsr', 'Dff'],
97
- ['$dffsre', 'Dff']]);
98
+ ['$dffsre', 'Dff'],
99
+ ['$aldff', 'Dff'],
100
+ ['$aldffe', 'Dff']]);
98
101
  const gate_negations = new Map([
99
102
  ['And', 'Nand'],
100
103
  ['Nand', 'And'],
@@ -245,8 +248,11 @@ namespace Yosys {
245
248
 
246
249
  };
247
250
 
248
- type Options = {
251
+ type ConvertOptions = {
249
252
  propagation?: number,
253
+ };
254
+
255
+ type Options = ConvertOptions & {
250
256
  optimize?: boolean,
251
257
  fsmexpand?: boolean,
252
258
  fsm?: boolean | "nomap",
@@ -330,6 +336,8 @@ function order_ports(data: Yosys.Output): Portmaps {
330
336
  '$adlatch': {EN: 'en', ARST: 'arst', D: 'in', Q: 'out'},
331
337
  '$dffsr': {CLK: 'clk', SET: 'set', CLR: 'clr', D: 'in', Q: 'out'},
332
338
  '$dffsre': {CLK: 'clk', EN: 'en', SET: 'set', CLR: 'clr', D: 'in', Q: 'out'},
339
+ '$aldff': {CLK: 'clk', ALOAD: 'aload', AD: 'ain', D: 'in', Q: 'out'},
340
+ '$aldffe': {CLK: 'clk', EN: 'en', ALOAD: 'aload', AD: 'ain', D: 'in', Q: 'out'},
333
341
  '$sr': {SET: 'set', CLR: 'clr', Q: 'out'},
334
342
  '$fsm': {ARST: 'arst', CLK: 'clk', CTRL_IN: 'in', CTRL_OUT: 'out'}
335
343
  };
@@ -386,7 +394,7 @@ function parse_source_positions(str: string): Digitaljs.SourcePosition[] {
386
394
  return ret;
387
395
  }
388
396
 
389
- function yosys_to_digitaljs(data: Yosys.Output, portmaps: Portmaps, options: Options = {}): {[key: string]: Digitaljs.Module} {
397
+ function yosys_to_digitaljs(data: Yosys.Output, portmaps: Portmaps, options: ConvertOptions = {}): {[key: string]: Digitaljs.Module} {
390
398
  const out = {};
391
399
  for (const [name, mod] of Object.entries(data.modules)) {
392
400
  out[name] = yosys_to_digitaljs_mod(name, mod, portmaps, options);
@@ -394,7 +402,7 @@ function yosys_to_digitaljs(data: Yosys.Output, portmaps: Portmaps, options: Opt
394
402
  return out
395
403
  }
396
404
 
397
- function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portmaps, options: Options = {}): Digitaljs.Module {
405
+ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portmaps, options: ConvertOptions = {}): Digitaljs.Module {
398
406
  function constbit(bit: Bit) {
399
407
  return bit == '0' || bit == '1' || bit == 'x';
400
408
  }
@@ -624,7 +632,7 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
624
632
  assert(cell.port_directions.B == 'input');
625
633
  assert(cell.port_directions.Y == 'output');
626
634
  }
627
- if (['$dff', '$dffe', '$adff', '$adffe', '$sdff', '$sdffe', '$sdffce', '$dlatch', '$adlatch', '$dffsr', '$dffsre'].includes(cell.type)) {
635
+ if (['$dff', '$dffe', '$adff', '$adffe', '$sdff', '$sdffe', '$sdffce', '$dlatch', '$adlatch', '$dffsr', '$dffsre', '$aldff', '$aldffe'].includes(cell.type)) {
628
636
  assert(cell.connections.D.length == decode_json_number(cell.parameters.WIDTH));
629
637
  assert(cell.connections.Q.length == decode_json_number(cell.parameters.WIDTH));
630
638
  assert(cell.port_directions.D == 'input');
@@ -634,6 +642,18 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
634
642
  assert(cell.port_directions.CLK == 'input');
635
643
  }
636
644
  }
645
+ if (['$dffe', '$adffe', '$sdffe', '$sdffce', '$dffsre', '$aldffe', '$dlatch', '$adlatch'].includes(cell.type)) {
646
+ assert(cell.connections.EN.length == 1);
647
+ assert(cell.port_directions.EN == 'input');
648
+ }
649
+ if (['$adff', '$adffe', '$adlatch'].includes(cell.type)) {
650
+ assert(cell.connections.ARST.length == 1);
651
+ assert(cell.port_directions.ARST == 'input');
652
+ }
653
+ if (['$sdff', '$sdffe', '$sdffce'].includes(cell.type)) {
654
+ assert(cell.connections.SRST.length == 1);
655
+ assert(cell.port_directions.SRST == 'input');
656
+ }
637
657
  if (['$dffsr', '$dffsre'].includes(cell.type)) {
638
658
  assert(cell.connections.SET.length == decode_json_number(cell.parameters.WIDTH));
639
659
  assert(cell.connections.CLR.length == decode_json_number(cell.parameters.WIDTH));
@@ -756,17 +776,28 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
756
776
  };
757
777
  break;
758
778
  case '$dffe':
759
- assert(cell.connections.EN.length == 1);
760
- assert(cell.port_directions.EN == 'input');
761
779
  dev.bits = decode_json_number(cell.parameters.WIDTH);
762
780
  dev.polarity = {
763
781
  clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
764
782
  enable: Boolean(decode_json_number(cell.parameters.EN_POLARITY))
765
783
  };
766
784
  break;
785
+ case '$aldff':
786
+ dev.bits = decode_json_number(cell.parameters.WIDTH);
787
+ dev.polarity = {
788
+ clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
789
+ aload: Boolean(decode_json_number(cell.parameters.ALOAD_POLARITY))
790
+ };
791
+ break;
792
+ case '$aldffe':
793
+ dev.bits = decode_json_number(cell.parameters.WIDTH);
794
+ dev.polarity = {
795
+ clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
796
+ enable: Boolean(decode_json_number(cell.parameters.EN_POLARITY)),
797
+ aload: Boolean(decode_json_number(cell.parameters.ALOAD_POLARITY))
798
+ };
799
+ break;
767
800
  case '$adff':
768
- assert(cell.connections.ARST.length == 1);
769
- assert(cell.port_directions.ARST == 'input');
770
801
  dev.bits = decode_json_number(cell.parameters.WIDTH);
771
802
  dev.polarity = {
772
803
  clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
@@ -775,8 +806,6 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
775
806
  dev.arst_value = decode_json_constant(cell.parameters.ARST_VALUE, dev.bits);
776
807
  break;
777
808
  case '$sdff':
778
- assert(cell.connections.SRST.length == 1);
779
- assert(cell.port_directions.SRST == 'input');
780
809
  dev.bits = decode_json_number(cell.parameters.WIDTH);
781
810
  dev.polarity = {
782
811
  clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
@@ -785,10 +814,6 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
785
814
  dev.srst_value = decode_json_constant(cell.parameters.SRST_VALUE, dev.bits);
786
815
  break;
787
816
  case '$adffe':
788
- assert(cell.connections.ARST.length == 1);
789
- assert(cell.port_directions.ARST == 'input');
790
- assert(cell.connections.EN.length == 1);
791
- assert(cell.port_directions.EN == 'input');
792
817
  dev.bits = decode_json_number(cell.parameters.WIDTH);
793
818
  dev.polarity = {
794
819
  clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
@@ -798,10 +823,6 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
798
823
  dev.arst_value = decode_json_constant(cell.parameters.ARST_VALUE, dev.bits);
799
824
  break;
800
825
  case '$sdffe':
801
- assert(cell.connections.SRST.length == 1);
802
- assert(cell.port_directions.SRST == 'input');
803
- assert(cell.connections.EN.length == 1);
804
- assert(cell.port_directions.EN == 'input');
805
826
  dev.bits = decode_json_number(cell.parameters.WIDTH);
806
827
  dev.polarity = {
807
828
  clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
@@ -811,10 +832,6 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
811
832
  dev.srst_value = decode_json_constant(cell.parameters.SRST_VALUE, dev.bits);
812
833
  break;
813
834
  case '$sdffce':
814
- assert(cell.connections.SRST.length == 1);
815
- assert(cell.port_directions.SRST == 'input');
816
- assert(cell.connections.EN.length == 1);
817
- assert(cell.port_directions.EN == 'input');
818
835
  dev.bits = decode_json_number(cell.parameters.WIDTH);
819
836
  dev.polarity = {
820
837
  clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
@@ -825,18 +842,12 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
825
842
  dev.srst_value = decode_json_constant(cell.parameters.SRST_VALUE, dev.bits);
826
843
  break;
827
844
  case '$dlatch':
828
- assert(cell.connections.EN.length == 1);
829
- assert(cell.port_directions.EN == 'input');
830
845
  dev.bits = decode_json_number(cell.parameters.WIDTH);
831
846
  dev.polarity = {
832
847
  enable: Boolean(decode_json_number(cell.parameters.EN_POLARITY))
833
848
  };
834
849
  break;
835
850
  case '$adlatch':
836
- assert(cell.connections.EN.length == 1);
837
- assert(cell.port_directions.EN == 'input');
838
- assert(cell.connections.ARST.length == 1);
839
- assert(cell.port_directions.ARST == 'input');
840
851
  dev.bits = decode_json_number(cell.parameters.WIDTH);
841
852
  dev.polarity = {
842
853
  enable: Boolean(decode_json_number(cell.parameters.EN_POLARITY)),
@@ -853,8 +864,6 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
853
864
  };
854
865
  break;
855
866
  case '$dffsre':
856
- assert(cell.connections.EN.length == 1);
857
- assert(cell.port_directions.EN == 'input');
858
867
  dev.bits = decode_json_number(cell.parameters.WIDTH);
859
868
  dev.polarity = {
860
869
  clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
@@ -1022,6 +1031,24 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
1022
1031
  }
1023
1032
  break;
1024
1033
  }
1034
+ case '$lut':
1035
+ assert(cell.connections.A.length == decode_json_number(cell.parameters.WIDTH));
1036
+ assert(cell.connections.Y.length == 1);
1037
+ assert(cell.port_directions.A == 'input');
1038
+ assert(cell.port_directions.Y == 'output');
1039
+ dev.abits = cell.connections.A.length;
1040
+ dev.bits = cell.connections.Y.length;
1041
+ dev.rdports = [{}];
1042
+ dev.wrports = [];
1043
+ dev.memdata = cell.parameters.LUT.split('').reverse();
1044
+ assert(dev.memdata.length == Math.pow(2, dev.abits));
1045
+
1046
+ // Rewrite cell connections to be $mem compatible for port mapping
1047
+ cell.connections.RD_ADDR = cell.connections.A;
1048
+ cell.connections.RD_DATA = cell.connections.Y;
1049
+ delete cell.connections.A;
1050
+ delete cell.connections.Y;
1051
+ break;
1025
1052
  default:
1026
1053
  }
1027
1054
  if (dev.type == 'Dff') {
@@ -1040,6 +1067,7 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
1040
1067
  else if (cell.type == '$pmux') connect_pmux(dname, cell);
1041
1068
  else if (cell.type == '$mem') connect_mem(dname, cell, dev);
1042
1069
  else if (cell.type == '$mem_v2') connect_mem(dname, cell, dev);
1070
+ else if (cell.type == '$lut') connect_mem(dname, cell, dev);
1043
1071
  else throw Error('Invalid cell type: ' + cell.type);
1044
1072
  }
1045
1073
  // Group bits into nets for complex sources
@@ -1172,6 +1200,18 @@ export async function verilator_lint(filenames: string[], dirname?: string, opti
1172
1200
  }
1173
1201
  }
1174
1202
 
1203
+ export function yosys2digitaljs(obj: Yosys.Output, options: ConvertOptions = {}): Digitaljs.TopModule {
1204
+ const portmaps = order_ports(obj);
1205
+ const out = yosys_to_digitaljs(obj, portmaps, options);
1206
+ const toporder = topsort(module_deps(obj));
1207
+ toporder.pop();
1208
+ const toplevel = toporder.pop();
1209
+ const output: Digitaljs.TopModule = { subcircuits: {}, ... out[toplevel] };
1210
+ for (const x of toporder)
1211
+ output.subcircuits[x] = out[x];
1212
+ return output;
1213
+ }
1214
+
1175
1215
  export async function process(filenames: string[], dirname?: string, options: Options = {}): Promise<Output> {
1176
1216
  const optimize_simp = options.optimize ? "; opt" : "; opt_clean";
1177
1217
  const optimize = options.optimize ? "; opt -full" : "; opt_clean";
@@ -1198,13 +1238,7 @@ export async function process(filenames: string[], dirname?: string, options: Op
1198
1238
  }
1199
1239
  obj = JSON.parse(fs.readFileSync(tmpjson, 'utf8'));
1200
1240
  await promisify(fs.unlink)(tmpjson);
1201
- const portmaps = order_ports(obj);
1202
- const out = yosys_to_digitaljs(obj, portmaps, options);
1203
- const toporder = topsort(module_deps(obj));
1204
- toporder.pop();
1205
- const toplevel = toporder.pop();
1206
- const output: Digitaljs.TopModule = { subcircuits: {}, ... out[toplevel] };
1207
- for (const x of toporder) output.subcircuits[x] = out[x];
1241
+ const output = yosys2digitaljs(obj, options);
1208
1242
  const ret: Output = {
1209
1243
  output: output,
1210
1244
  yosys_output: obj,
@@ -1234,12 +1268,18 @@ export function io_ui(output: Digitaljs.Module) {
1234
1268
  }
1235
1269
  if (dev.type == 'Input')
1236
1270
  dev.type = dev.bits == 1 ? 'Button' : 'NumEntry';
1237
- if (dev.type == 'Output')
1238
- dev.type = dev.bits == 1 ? 'Lamp' : 'NumDisplay';
1271
+ if (dev.type == 'Output') {
1272
+ if (dev.bits == 1)
1273
+ dev.type = 'Lamp';
1274
+ else if (dev.bits == 8 && (dev.label == 'display7' || dev.label.startsWith('display7_')))
1275
+ dev.type = 'Display7';
1276
+ else
1277
+ dev.type = 'NumDisplay';
1278
+ }
1239
1279
  }
1240
1280
  }
1241
1281
 
1242
- export async function process_files(data: {[key: string]: string}, options: Options): Promise<Output> {
1282
+ export async function process_files(data: {[key: string]: string}, options: Options = {}): Promise<Output> {
1243
1283
  const dir = await tmp.dir();
1244
1284
  const names = [];
1245
1285
  try {
@@ -1257,12 +1297,12 @@ export async function process_files(data: {[key: string]: string}, options: Opti
1257
1297
  }
1258
1298
  }
1259
1299
 
1260
- export async function process_sv(text: string): Promise<Output> {
1300
+ export async function process_sv(text: string, options: Options = {}): Promise<Output> {
1261
1301
  const tmpsv = await tmp.file({ postfix: '.sv' });
1262
1302
  try {
1263
1303
  await promisify(fs.write)(tmpsv.fd, text);
1264
1304
  await promisify(fs.close)(tmpsv.fd);
1265
- return await process([tmpsv.path]);
1305
+ return await process([tmpsv.path], undefined, options);
1266
1306
  } finally {
1267
1307
  tmpsv.cleanup();
1268
1308
  }
package/tests/ram.sv CHANGED
@@ -1,5 +1,5 @@
1
1
  // Simple RAM
2
- module rom
2
+ module ram
3
3
  #(parameter AWIDTH = 4, DWIDTH = 4)(
4
4
  input clk,
5
5
  input [AWIDTH-1:0] addr,
package/.travis.yml DELETED
@@ -1,8 +0,0 @@
1
- before_install:
2
- - sudo add-apt-repository ppa:saltmakrell/ppa -y
3
- - sudo apt-get update
4
- - sudo apt-get install -y yosys
5
-
6
- language: node_js
7
- node_js:
8
- - "8"