yosys2digitaljs 0.5.0 → 0.6.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/ChangeLog.md +7 -0
- package/README.md +4 -4
- package/dist/index.d.ts +82 -3
- package/dist/index.js +50 -40
- package/package.json +1 -1
- package/src/index.ts +55 -41
- package/.travis.yml +0 -8
package/ChangeLog.md
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
All notable changes to this project will be documented in this file.
|
|
3
3
|
|
|
4
|
+
## [0.6.0] -- 2022-02-02
|
|
5
|
+
|
|
6
|
+
### Added
|
|
7
|
+
|
|
8
|
+
- Support for Yosys 0.11 cells `$aldff`, `$aldffe`
|
|
9
|
+
- Added a function `yosys2digitaljs` for converting a Yosys JSON output obtained elsewhere, without running Yosys locally
|
|
10
|
+
|
|
4
11
|
## [0.5.0] -- 2021-10-06
|
|
5
12
|
|
|
6
13
|
### Added
|
package/README.md
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
[](https://travis-ci.org/tilk/yosys2digitaljs)
|
|
2
1
|
# yosys2digitaljs
|
|
3
2
|
This program converts JSON netlist output generated by [Yosys](http://www.clifford.at/yosys/)
|
|
4
3
|
circuit synthesis software for use with the
|
|
@@ -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");
|
|
@@ -95,7 +95,9 @@ const gate_subst = new Map([
|
|
|
95
95
|
['$adlatch', 'Dff'],
|
|
96
96
|
['$sr', 'Dff'],
|
|
97
97
|
['$dffsr', 'Dff'],
|
|
98
|
-
['$dffsre', 'Dff']
|
|
98
|
+
['$dffsre', 'Dff'],
|
|
99
|
+
['$aldff', 'Dff'],
|
|
100
|
+
['$aldffe', 'Dff']
|
|
99
101
|
]);
|
|
100
102
|
const gate_negations = new Map([
|
|
101
103
|
['And', 'Nand'],
|
|
@@ -149,6 +151,8 @@ function order_ports(data) {
|
|
|
149
151
|
'$adlatch': { EN: 'en', ARST: 'arst', D: 'in', Q: 'out' },
|
|
150
152
|
'$dffsr': { CLK: 'clk', SET: 'set', CLR: 'clr', D: 'in', Q: 'out' },
|
|
151
153
|
'$dffsre': { CLK: 'clk', EN: 'en', SET: 'set', CLR: 'clr', D: 'in', Q: 'out' },
|
|
154
|
+
'$aldff': { CLK: 'clk', ALOAD: 'aload', AD: 'ain', D: 'in', Q: 'out' },
|
|
155
|
+
'$aldffe': { CLK: 'clk', EN: 'en', ALOAD: 'aload', AD: 'ain', D: 'in', Q: 'out' },
|
|
152
156
|
'$sr': { SET: 'set', CLR: 'clr', Q: 'out' },
|
|
153
157
|
'$fsm': { ARST: 'arst', CLK: 'clk', CTRL_IN: 'in', CTRL_OUT: 'out' }
|
|
154
158
|
};
|
|
@@ -436,7 +440,7 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
|
|
|
436
440
|
assert(cell.port_directions.B == 'input');
|
|
437
441
|
assert(cell.port_directions.Y == 'output');
|
|
438
442
|
}
|
|
439
|
-
if (['$dff', '$dffe', '$adff', '$adffe', '$sdff', '$sdffe', '$sdffce', '$dlatch', '$adlatch', '$dffsr', '$dffsre'].includes(cell.type)) {
|
|
443
|
+
if (['$dff', '$dffe', '$adff', '$adffe', '$sdff', '$sdffe', '$sdffce', '$dlatch', '$adlatch', '$dffsr', '$dffsre', '$aldff', '$aldffe'].includes(cell.type)) {
|
|
440
444
|
assert(cell.connections.D.length == decode_json_number(cell.parameters.WIDTH));
|
|
441
445
|
assert(cell.connections.Q.length == decode_json_number(cell.parameters.WIDTH));
|
|
442
446
|
assert(cell.port_directions.D == 'input');
|
|
@@ -446,6 +450,18 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
|
|
|
446
450
|
assert(cell.port_directions.CLK == 'input');
|
|
447
451
|
}
|
|
448
452
|
}
|
|
453
|
+
if (['$dffe', '$adffe', '$sdffe', '$sdffce', '$dffsre', '$aldffe', '$dlatch', '$adlatch'].includes(cell.type)) {
|
|
454
|
+
assert(cell.connections.EN.length == 1);
|
|
455
|
+
assert(cell.port_directions.EN == 'input');
|
|
456
|
+
}
|
|
457
|
+
if (['$adff', '$adffe', '$adlatch'].includes(cell.type)) {
|
|
458
|
+
assert(cell.connections.ARST.length == 1);
|
|
459
|
+
assert(cell.port_directions.ARST == 'input');
|
|
460
|
+
}
|
|
461
|
+
if (['$sdff', '$sdffe', '$sdffce'].includes(cell.type)) {
|
|
462
|
+
assert(cell.connections.SRST.length == 1);
|
|
463
|
+
assert(cell.port_directions.SRST == 'input');
|
|
464
|
+
}
|
|
449
465
|
if (['$dffsr', '$dffsre'].includes(cell.type)) {
|
|
450
466
|
assert(cell.connections.SET.length == decode_json_number(cell.parameters.WIDTH));
|
|
451
467
|
assert(cell.connections.CLR.length == decode_json_number(cell.parameters.WIDTH));
|
|
@@ -592,17 +608,28 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
|
|
|
592
608
|
};
|
|
593
609
|
break;
|
|
594
610
|
case '$dffe':
|
|
595
|
-
assert(cell.connections.EN.length == 1);
|
|
596
|
-
assert(cell.port_directions.EN == 'input');
|
|
597
611
|
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
598
612
|
dev.polarity = {
|
|
599
613
|
clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
|
|
600
614
|
enable: Boolean(decode_json_number(cell.parameters.EN_POLARITY))
|
|
601
615
|
};
|
|
602
616
|
break;
|
|
617
|
+
case '$aldff':
|
|
618
|
+
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
619
|
+
dev.polarity = {
|
|
620
|
+
clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
|
|
621
|
+
aload: Boolean(decode_json_number(cell.parameters.ALOAD_POLARITY))
|
|
622
|
+
};
|
|
623
|
+
break;
|
|
624
|
+
case '$aldffe':
|
|
625
|
+
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
626
|
+
dev.polarity = {
|
|
627
|
+
clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
|
|
628
|
+
enable: Boolean(decode_json_number(cell.parameters.EN_POLARITY)),
|
|
629
|
+
aload: Boolean(decode_json_number(cell.parameters.ALOAD_POLARITY))
|
|
630
|
+
};
|
|
631
|
+
break;
|
|
603
632
|
case '$adff':
|
|
604
|
-
assert(cell.connections.ARST.length == 1);
|
|
605
|
-
assert(cell.port_directions.ARST == 'input');
|
|
606
633
|
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
607
634
|
dev.polarity = {
|
|
608
635
|
clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
|
|
@@ -611,8 +638,6 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
|
|
|
611
638
|
dev.arst_value = decode_json_constant(cell.parameters.ARST_VALUE, dev.bits);
|
|
612
639
|
break;
|
|
613
640
|
case '$sdff':
|
|
614
|
-
assert(cell.connections.SRST.length == 1);
|
|
615
|
-
assert(cell.port_directions.SRST == 'input');
|
|
616
641
|
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
617
642
|
dev.polarity = {
|
|
618
643
|
clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
|
|
@@ -621,10 +646,6 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
|
|
|
621
646
|
dev.srst_value = decode_json_constant(cell.parameters.SRST_VALUE, dev.bits);
|
|
622
647
|
break;
|
|
623
648
|
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
649
|
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
629
650
|
dev.polarity = {
|
|
630
651
|
clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
|
|
@@ -634,10 +655,6 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
|
|
|
634
655
|
dev.arst_value = decode_json_constant(cell.parameters.ARST_VALUE, dev.bits);
|
|
635
656
|
break;
|
|
636
657
|
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
658
|
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
642
659
|
dev.polarity = {
|
|
643
660
|
clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
|
|
@@ -647,10 +664,6 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
|
|
|
647
664
|
dev.srst_value = decode_json_constant(cell.parameters.SRST_VALUE, dev.bits);
|
|
648
665
|
break;
|
|
649
666
|
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
667
|
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
655
668
|
dev.polarity = {
|
|
656
669
|
clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
|
|
@@ -661,18 +674,12 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
|
|
|
661
674
|
dev.srst_value = decode_json_constant(cell.parameters.SRST_VALUE, dev.bits);
|
|
662
675
|
break;
|
|
663
676
|
case '$dlatch':
|
|
664
|
-
assert(cell.connections.EN.length == 1);
|
|
665
|
-
assert(cell.port_directions.EN == 'input');
|
|
666
677
|
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
667
678
|
dev.polarity = {
|
|
668
679
|
enable: Boolean(decode_json_number(cell.parameters.EN_POLARITY))
|
|
669
680
|
};
|
|
670
681
|
break;
|
|
671
682
|
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
683
|
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
677
684
|
dev.polarity = {
|
|
678
685
|
enable: Boolean(decode_json_number(cell.parameters.EN_POLARITY)),
|
|
@@ -689,8 +696,6 @@ function yosys_to_digitaljs_mod(name, mod, portmaps, options = {}) {
|
|
|
689
696
|
};
|
|
690
697
|
break;
|
|
691
698
|
case '$dffsre':
|
|
692
|
-
assert(cell.connections.EN.length == 1);
|
|
693
|
-
assert(cell.port_directions.EN == 'input');
|
|
694
699
|
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
695
700
|
dev.polarity = {
|
|
696
701
|
clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
|
|
@@ -1020,6 +1025,18 @@ async function verilator_lint(filenames, dirname, options = {}) {
|
|
|
1020
1025
|
}
|
|
1021
1026
|
}
|
|
1022
1027
|
exports.verilator_lint = verilator_lint;
|
|
1028
|
+
function yosys2digitaljs(obj, options = {}) {
|
|
1029
|
+
const portmaps = order_ports(obj);
|
|
1030
|
+
const out = yosys_to_digitaljs(obj, portmaps, options);
|
|
1031
|
+
const toporder = topsort(module_deps(obj));
|
|
1032
|
+
toporder.pop();
|
|
1033
|
+
const toplevel = toporder.pop();
|
|
1034
|
+
const output = Object.assign({ subcircuits: {} }, out[toplevel]);
|
|
1035
|
+
for (const x of toporder)
|
|
1036
|
+
output.subcircuits[x] = out[x];
|
|
1037
|
+
return output;
|
|
1038
|
+
}
|
|
1039
|
+
exports.yosys2digitaljs = yosys2digitaljs;
|
|
1023
1040
|
async function process(filenames, dirname, options = {}) {
|
|
1024
1041
|
const optimize_simp = options.optimize ? "; opt" : "; opt_clean";
|
|
1025
1042
|
const optimize = options.optimize ? "; opt -full" : "; opt_clean";
|
|
@@ -1044,14 +1061,7 @@ async function process(filenames, dirname, options = {}) {
|
|
|
1044
1061
|
}
|
|
1045
1062
|
obj = JSON.parse(fs.readFileSync(tmpjson, 'utf8'));
|
|
1046
1063
|
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];
|
|
1064
|
+
const output = yosys2digitaljs(obj, options);
|
|
1055
1065
|
const ret = {
|
|
1056
1066
|
output: output,
|
|
1057
1067
|
yosys_output: obj,
|
|
@@ -1088,7 +1098,7 @@ function io_ui(output) {
|
|
|
1088
1098
|
}
|
|
1089
1099
|
}
|
|
1090
1100
|
exports.io_ui = io_ui;
|
|
1091
|
-
async function process_files(data, options) {
|
|
1101
|
+
async function process_files(data, options = {}) {
|
|
1092
1102
|
const dir = await tmp.dir();
|
|
1093
1103
|
const names = [];
|
|
1094
1104
|
try {
|
|
@@ -1108,12 +1118,12 @@ async function process_files(data, options) {
|
|
|
1108
1118
|
}
|
|
1109
1119
|
}
|
|
1110
1120
|
exports.process_files = process_files;
|
|
1111
|
-
async function process_sv(text) {
|
|
1121
|
+
async function process_sv(text, options = {}) {
|
|
1112
1122
|
const tmpsv = await tmp.file({ postfix: '.sv' });
|
|
1113
1123
|
try {
|
|
1114
1124
|
await (0, util_1.promisify)(fs.write)(tmpsv.fd, text);
|
|
1115
1125
|
await (0, util_1.promisify)(fs.close)(tmpsv.fd);
|
|
1116
|
-
return await process([tmpsv.path]);
|
|
1126
|
+
return await process([tmpsv.path], undefined, options);
|
|
1117
1127
|
}
|
|
1118
1128
|
finally {
|
|
1119
1129
|
tmpsv.cleanup();
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -94,7 +94,9 @@ const gate_subst = new Map([
|
|
|
94
94
|
['$adlatch', 'Dff'],
|
|
95
95
|
['$sr', 'Dff'],
|
|
96
96
|
['$dffsr', 'Dff'],
|
|
97
|
-
['$dffsre', 'Dff']
|
|
97
|
+
['$dffsre', 'Dff'],
|
|
98
|
+
['$aldff', 'Dff'],
|
|
99
|
+
['$aldffe', 'Dff']]);
|
|
98
100
|
const gate_negations = new Map([
|
|
99
101
|
['And', 'Nand'],
|
|
100
102
|
['Nand', 'And'],
|
|
@@ -245,8 +247,11 @@ namespace Yosys {
|
|
|
245
247
|
|
|
246
248
|
};
|
|
247
249
|
|
|
248
|
-
type
|
|
250
|
+
type ConvertOptions = {
|
|
249
251
|
propagation?: number,
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
type Options = ConvertOptions & {
|
|
250
255
|
optimize?: boolean,
|
|
251
256
|
fsmexpand?: boolean,
|
|
252
257
|
fsm?: boolean | "nomap",
|
|
@@ -330,6 +335,8 @@ function order_ports(data: Yosys.Output): Portmaps {
|
|
|
330
335
|
'$adlatch': {EN: 'en', ARST: 'arst', D: 'in', Q: 'out'},
|
|
331
336
|
'$dffsr': {CLK: 'clk', SET: 'set', CLR: 'clr', D: 'in', Q: 'out'},
|
|
332
337
|
'$dffsre': {CLK: 'clk', EN: 'en', SET: 'set', CLR: 'clr', D: 'in', Q: 'out'},
|
|
338
|
+
'$aldff': {CLK: 'clk', ALOAD: 'aload', AD: 'ain', D: 'in', Q: 'out'},
|
|
339
|
+
'$aldffe': {CLK: 'clk', EN: 'en', ALOAD: 'aload', AD: 'ain', D: 'in', Q: 'out'},
|
|
333
340
|
'$sr': {SET: 'set', CLR: 'clr', Q: 'out'},
|
|
334
341
|
'$fsm': {ARST: 'arst', CLK: 'clk', CTRL_IN: 'in', CTRL_OUT: 'out'}
|
|
335
342
|
};
|
|
@@ -386,7 +393,7 @@ function parse_source_positions(str: string): Digitaljs.SourcePosition[] {
|
|
|
386
393
|
return ret;
|
|
387
394
|
}
|
|
388
395
|
|
|
389
|
-
function yosys_to_digitaljs(data: Yosys.Output, portmaps: Portmaps, options:
|
|
396
|
+
function yosys_to_digitaljs(data: Yosys.Output, portmaps: Portmaps, options: ConvertOptions = {}): {[key: string]: Digitaljs.Module} {
|
|
390
397
|
const out = {};
|
|
391
398
|
for (const [name, mod] of Object.entries(data.modules)) {
|
|
392
399
|
out[name] = yosys_to_digitaljs_mod(name, mod, portmaps, options);
|
|
@@ -394,7 +401,7 @@ function yosys_to_digitaljs(data: Yosys.Output, portmaps: Portmaps, options: Opt
|
|
|
394
401
|
return out
|
|
395
402
|
}
|
|
396
403
|
|
|
397
|
-
function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portmaps, options:
|
|
404
|
+
function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portmaps, options: ConvertOptions = {}): Digitaljs.Module {
|
|
398
405
|
function constbit(bit: Bit) {
|
|
399
406
|
return bit == '0' || bit == '1' || bit == 'x';
|
|
400
407
|
}
|
|
@@ -624,7 +631,7 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
|
|
|
624
631
|
assert(cell.port_directions.B == 'input');
|
|
625
632
|
assert(cell.port_directions.Y == 'output');
|
|
626
633
|
}
|
|
627
|
-
if (['$dff', '$dffe', '$adff', '$adffe', '$sdff', '$sdffe', '$sdffce', '$dlatch', '$adlatch', '$dffsr', '$dffsre'].includes(cell.type)) {
|
|
634
|
+
if (['$dff', '$dffe', '$adff', '$adffe', '$sdff', '$sdffe', '$sdffce', '$dlatch', '$adlatch', '$dffsr', '$dffsre', '$aldff', '$aldffe'].includes(cell.type)) {
|
|
628
635
|
assert(cell.connections.D.length == decode_json_number(cell.parameters.WIDTH));
|
|
629
636
|
assert(cell.connections.Q.length == decode_json_number(cell.parameters.WIDTH));
|
|
630
637
|
assert(cell.port_directions.D == 'input');
|
|
@@ -634,6 +641,18 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
|
|
|
634
641
|
assert(cell.port_directions.CLK == 'input');
|
|
635
642
|
}
|
|
636
643
|
}
|
|
644
|
+
if (['$dffe', '$adffe', '$sdffe', '$sdffce', '$dffsre', '$aldffe', '$dlatch', '$adlatch'].includes(cell.type)) {
|
|
645
|
+
assert(cell.connections.EN.length == 1);
|
|
646
|
+
assert(cell.port_directions.EN == 'input');
|
|
647
|
+
}
|
|
648
|
+
if (['$adff', '$adffe', '$adlatch'].includes(cell.type)) {
|
|
649
|
+
assert(cell.connections.ARST.length == 1);
|
|
650
|
+
assert(cell.port_directions.ARST == 'input');
|
|
651
|
+
}
|
|
652
|
+
if (['$sdff', '$sdffe', '$sdffce'].includes(cell.type)) {
|
|
653
|
+
assert(cell.connections.SRST.length == 1);
|
|
654
|
+
assert(cell.port_directions.SRST == 'input');
|
|
655
|
+
}
|
|
637
656
|
if (['$dffsr', '$dffsre'].includes(cell.type)) {
|
|
638
657
|
assert(cell.connections.SET.length == decode_json_number(cell.parameters.WIDTH));
|
|
639
658
|
assert(cell.connections.CLR.length == decode_json_number(cell.parameters.WIDTH));
|
|
@@ -756,17 +775,28 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
|
|
|
756
775
|
};
|
|
757
776
|
break;
|
|
758
777
|
case '$dffe':
|
|
759
|
-
assert(cell.connections.EN.length == 1);
|
|
760
|
-
assert(cell.port_directions.EN == 'input');
|
|
761
778
|
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
762
779
|
dev.polarity = {
|
|
763
780
|
clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
|
|
764
781
|
enable: Boolean(decode_json_number(cell.parameters.EN_POLARITY))
|
|
765
782
|
};
|
|
766
783
|
break;
|
|
784
|
+
case '$aldff':
|
|
785
|
+
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
786
|
+
dev.polarity = {
|
|
787
|
+
clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
|
|
788
|
+
aload: Boolean(decode_json_number(cell.parameters.ALOAD_POLARITY))
|
|
789
|
+
};
|
|
790
|
+
break;
|
|
791
|
+
case '$aldffe':
|
|
792
|
+
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
793
|
+
dev.polarity = {
|
|
794
|
+
clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
|
|
795
|
+
enable: Boolean(decode_json_number(cell.parameters.EN_POLARITY)),
|
|
796
|
+
aload: Boolean(decode_json_number(cell.parameters.ALOAD_POLARITY))
|
|
797
|
+
};
|
|
798
|
+
break;
|
|
767
799
|
case '$adff':
|
|
768
|
-
assert(cell.connections.ARST.length == 1);
|
|
769
|
-
assert(cell.port_directions.ARST == 'input');
|
|
770
800
|
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
771
801
|
dev.polarity = {
|
|
772
802
|
clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
|
|
@@ -775,8 +805,6 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
|
|
|
775
805
|
dev.arst_value = decode_json_constant(cell.parameters.ARST_VALUE, dev.bits);
|
|
776
806
|
break;
|
|
777
807
|
case '$sdff':
|
|
778
|
-
assert(cell.connections.SRST.length == 1);
|
|
779
|
-
assert(cell.port_directions.SRST == 'input');
|
|
780
808
|
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
781
809
|
dev.polarity = {
|
|
782
810
|
clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
|
|
@@ -785,10 +813,6 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
|
|
|
785
813
|
dev.srst_value = decode_json_constant(cell.parameters.SRST_VALUE, dev.bits);
|
|
786
814
|
break;
|
|
787
815
|
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
816
|
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
793
817
|
dev.polarity = {
|
|
794
818
|
clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
|
|
@@ -798,10 +822,6 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
|
|
|
798
822
|
dev.arst_value = decode_json_constant(cell.parameters.ARST_VALUE, dev.bits);
|
|
799
823
|
break;
|
|
800
824
|
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
825
|
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
806
826
|
dev.polarity = {
|
|
807
827
|
clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
|
|
@@ -811,10 +831,6 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
|
|
|
811
831
|
dev.srst_value = decode_json_constant(cell.parameters.SRST_VALUE, dev.bits);
|
|
812
832
|
break;
|
|
813
833
|
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
834
|
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
819
835
|
dev.polarity = {
|
|
820
836
|
clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
|
|
@@ -825,18 +841,12 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
|
|
|
825
841
|
dev.srst_value = decode_json_constant(cell.parameters.SRST_VALUE, dev.bits);
|
|
826
842
|
break;
|
|
827
843
|
case '$dlatch':
|
|
828
|
-
assert(cell.connections.EN.length == 1);
|
|
829
|
-
assert(cell.port_directions.EN == 'input');
|
|
830
844
|
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
831
845
|
dev.polarity = {
|
|
832
846
|
enable: Boolean(decode_json_number(cell.parameters.EN_POLARITY))
|
|
833
847
|
};
|
|
834
848
|
break;
|
|
835
849
|
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
850
|
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
841
851
|
dev.polarity = {
|
|
842
852
|
enable: Boolean(decode_json_number(cell.parameters.EN_POLARITY)),
|
|
@@ -853,8 +863,6 @@ function yosys_to_digitaljs_mod(name: string, mod: Yosys.Module, portmaps: Portm
|
|
|
853
863
|
};
|
|
854
864
|
break;
|
|
855
865
|
case '$dffsre':
|
|
856
|
-
assert(cell.connections.EN.length == 1);
|
|
857
|
-
assert(cell.port_directions.EN == 'input');
|
|
858
866
|
dev.bits = decode_json_number(cell.parameters.WIDTH);
|
|
859
867
|
dev.polarity = {
|
|
860
868
|
clock: Boolean(decode_json_number(cell.parameters.CLK_POLARITY)),
|
|
@@ -1172,6 +1180,18 @@ export async function verilator_lint(filenames: string[], dirname?: string, opti
|
|
|
1172
1180
|
}
|
|
1173
1181
|
}
|
|
1174
1182
|
|
|
1183
|
+
export function yosys2digitaljs(obj: Yosys.Output, options: ConvertOptions = {}): Digitaljs.TopModule {
|
|
1184
|
+
const portmaps = order_ports(obj);
|
|
1185
|
+
const out = yosys_to_digitaljs(obj, portmaps, options);
|
|
1186
|
+
const toporder = topsort(module_deps(obj));
|
|
1187
|
+
toporder.pop();
|
|
1188
|
+
const toplevel = toporder.pop();
|
|
1189
|
+
const output: Digitaljs.TopModule = { subcircuits: {}, ... out[toplevel] };
|
|
1190
|
+
for (const x of toporder)
|
|
1191
|
+
output.subcircuits[x] = out[x];
|
|
1192
|
+
return output;
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1175
1195
|
export async function process(filenames: string[], dirname?: string, options: Options = {}): Promise<Output> {
|
|
1176
1196
|
const optimize_simp = options.optimize ? "; opt" : "; opt_clean";
|
|
1177
1197
|
const optimize = options.optimize ? "; opt -full" : "; opt_clean";
|
|
@@ -1198,13 +1218,7 @@ export async function process(filenames: string[], dirname?: string, options: Op
|
|
|
1198
1218
|
}
|
|
1199
1219
|
obj = JSON.parse(fs.readFileSync(tmpjson, 'utf8'));
|
|
1200
1220
|
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];
|
|
1221
|
+
const output = yosys2digitaljs(obj, options);
|
|
1208
1222
|
const ret: Output = {
|
|
1209
1223
|
output: output,
|
|
1210
1224
|
yosys_output: obj,
|
|
@@ -1239,7 +1253,7 @@ export function io_ui(output: Digitaljs.Module) {
|
|
|
1239
1253
|
}
|
|
1240
1254
|
}
|
|
1241
1255
|
|
|
1242
|
-
export async function process_files(data: {[key: string]: string}, options: Options): Promise<Output> {
|
|
1256
|
+
export async function process_files(data: {[key: string]: string}, options: Options = {}): Promise<Output> {
|
|
1243
1257
|
const dir = await tmp.dir();
|
|
1244
1258
|
const names = [];
|
|
1245
1259
|
try {
|
|
@@ -1257,12 +1271,12 @@ export async function process_files(data: {[key: string]: string}, options: Opti
|
|
|
1257
1271
|
}
|
|
1258
1272
|
}
|
|
1259
1273
|
|
|
1260
|
-
export async function process_sv(text: string): Promise<Output> {
|
|
1274
|
+
export async function process_sv(text: string, options: Options = {}): Promise<Output> {
|
|
1261
1275
|
const tmpsv = await tmp.file({ postfix: '.sv' });
|
|
1262
1276
|
try {
|
|
1263
1277
|
await promisify(fs.write)(tmpsv.fd, text);
|
|
1264
1278
|
await promisify(fs.close)(tmpsv.fd);
|
|
1265
|
-
return await process([tmpsv.path]);
|
|
1279
|
+
return await process([tmpsv.path], undefined, options);
|
|
1266
1280
|
} finally {
|
|
1267
1281
|
tmpsv.cleanup();
|
|
1268
1282
|
}
|