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 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
- [![Build Status](https://travis-ci.org/tilk/yosys2digitaljs.svg?branch=master)](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
- - `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");
@@ -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 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];
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yosys2digitaljs",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Export Yosys netlists to a logic simulator",
5
5
  "main": "dist/index",
6
6
  "types": "dist/index.d.ts",
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 Options = {
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: Options = {}): {[key: string]: Digitaljs.Module} {
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: Options = {}): Digitaljs.Module {
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 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];
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
  }
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"