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.
- package/.github/workflows/nodejs.yml +2 -2
- package/ChangeLog.md +14 -0
- package/README.md +7 -7
- package/dist/index.d.ts +82 -3
- package/dist/index.js +78 -42
- package/package.json +2 -2
- package/result.json +420 -0
- package/src/index.ts +83 -43
- package/tests/ram.sv +1 -1
- package/.travis.yml +0 -8
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
|
-
[](https://travis-ci.org/tilk/yosys2digitaljs)
|
|
2
1
|
# yosys2digitaljs
|
|
3
|
-
This program converts JSON netlist output generated by [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](
|
|
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
|
-
- `
|
|
29
|
-
- `
|
|
30
|
-
- `
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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:
|
|
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:
|
|
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
|
|
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
|
-
|
|
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