完成 的支持 | 优化工具函数
This commit is contained in:
parent
55d5c51f29
commit
a8804d9cc0
25
README.md
25
README.md
@ -11,13 +11,11 @@ Value Change Dump ([VCD](https://en.wikipedia.org/wiki/Value_change_dump)) parse
|
|||||||
```bash
|
```bash
|
||||||
source $EMCC_HOME/emsdk_env.sh
|
source $EMCC_HOME/emsdk_env.sh
|
||||||
# once only
|
# once only
|
||||||
npm install browserify terser -g
|
npm install browserify terser node-gyp -g
|
||||||
# once only
|
# once only
|
||||||
node bin/build.js
|
npm i
|
||||||
# build
|
# build
|
||||||
make -j 12
|
make -j 12
|
||||||
# adjust to browser environment
|
|
||||||
browserify ./bin/vcd.js | terser --compress -o ./out/vcd.js
|
|
||||||
```
|
```
|
||||||
|
|
||||||
production are :
|
production are :
|
||||||
@ -27,6 +25,25 @@ production are :
|
|||||||
|
|
||||||
move them to your development worksapce.
|
move them to your development worksapce.
|
||||||
|
|
||||||
|
|
||||||
|
## Test
|
||||||
|
|
||||||
|
After first building, run following
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run test
|
||||||
|
```
|
||||||
|
|
||||||
|
note: don't run `browserify` if you want to test.
|
||||||
|
|
||||||
|
## Deploy to web
|
||||||
|
|
||||||
|
```bash
|
||||||
|
source deploy.sh /path/to/digital-vcd-render
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Only stream of Uint8 is supported as input. e.g. we want to parse a certain `*.vcd` read in browser-like environment. Mount vcd to window in your `index.html`:
|
Only stream of Uint8 is supported as input. e.g. we want to parse a certain `*.vcd` read in browser-like environment. Mount vcd to window in your `index.html`:
|
||||||
|
67
backup/napi_any.js
Normal file
67
backup/napi_any.js
Normal file
File diff suppressed because one or more lines are too long
138
backup/napi_basic.js
Normal file
138
backup/napi_basic.js
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
// 'use strict';
|
||||||
|
|
||||||
|
// /* eslint-disable no-console */
|
||||||
|
// /* eslint-disable indent */
|
||||||
|
|
||||||
|
// const expect = require('chai').expect;
|
||||||
|
// const parser = require('../lib/parser.js');
|
||||||
|
|
||||||
|
// describe('basic', () => {
|
||||||
|
|
||||||
|
// it('typeof vcd', done => {
|
||||||
|
// expect(parser).to.be.an('function');
|
||||||
|
// done();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it('typeof vcd instance', done => {
|
||||||
|
// expect(parser()).to.be.an('object');
|
||||||
|
// done();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it('fail: foo bar', done => {
|
||||||
|
// const inst = parser();
|
||||||
|
// expect(() => {
|
||||||
|
// inst.write(Buffer.from(' foo bar ???'));
|
||||||
|
// }).not.to.throw();
|
||||||
|
// expect(inst.info).to.deep.eq({
|
||||||
|
// stack: [{}],
|
||||||
|
// status: 'declaration',
|
||||||
|
// wires: {}
|
||||||
|
// });
|
||||||
|
// done();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it('fail: $comment', done => {
|
||||||
|
// const inst = parser();
|
||||||
|
// expect(() => {
|
||||||
|
// inst.write(Buffer.from(
|
||||||
|
// ' \n $comment some text $end $comment more text $end ???'
|
||||||
|
// ));
|
||||||
|
// }).not.to.throw();
|
||||||
|
// expect(inst.info).to.deep.eq({
|
||||||
|
// comment: ' more text ',
|
||||||
|
// stack: [{}],
|
||||||
|
// status: 'declaration',
|
||||||
|
// wires: {}
|
||||||
|
// });
|
||||||
|
// done();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it('$version', done => {
|
||||||
|
// const inst = parser();
|
||||||
|
// expect(inst.write(`
|
||||||
|
// $version Generated by VerilatedVcd $end
|
||||||
|
// $date Wed Sep 18 22:59:07 2019
|
||||||
|
// $end
|
||||||
|
// $timescale 1ns $end
|
||||||
|
|
||||||
|
// $scope module top $end
|
||||||
|
// $var wire 1 "}G clock $end
|
||||||
|
// $scope module leaf $end
|
||||||
|
// $var wire 64 {u counter [63:0] $end
|
||||||
|
// $upscope $end
|
||||||
|
// $scope module fruit $end
|
||||||
|
// $var wire 4 u) point [3:0] $end
|
||||||
|
// $upscope $end
|
||||||
|
// $upscope $end
|
||||||
|
|
||||||
|
// $enddefinitions $end
|
||||||
|
// `
|
||||||
|
// )).to.eq(true);
|
||||||
|
|
||||||
|
// expect(inst.write(`
|
||||||
|
|
||||||
|
// #1
|
||||||
|
// 0"}G
|
||||||
|
// #2
|
||||||
|
// 1"}G
|
||||||
|
// #300
|
||||||
|
// 0"}G
|
||||||
|
// b1111000000000000 {u
|
||||||
|
// #301
|
||||||
|
// b0000111100000000 {u
|
||||||
|
// #302
|
||||||
|
// b0000000011110000 {u
|
||||||
|
// #303
|
||||||
|
// b0000000000001111 {u
|
||||||
|
// `
|
||||||
|
// )).to.eq(true);
|
||||||
|
|
||||||
|
// console.log(inst.info);
|
||||||
|
|
||||||
|
// expect(inst.info).to.deep.eq({
|
||||||
|
// status: 'simulation',
|
||||||
|
// date: ' Wed Sep 18 22:59:07 2019\n ',
|
||||||
|
// version: ' Generated by VerilatedVcd ',
|
||||||
|
// timescale: ' 1ns ',
|
||||||
|
// t0: 1,
|
||||||
|
// varId: 'u)',
|
||||||
|
// wires: {
|
||||||
|
// top: {
|
||||||
|
// clock: '"}G',
|
||||||
|
// fruit: {
|
||||||
|
// point: 'u)'
|
||||||
|
// },
|
||||||
|
// leaf: {
|
||||||
|
// counter: '{u'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// stack: [{
|
||||||
|
// top: {
|
||||||
|
// clock: '"}G',
|
||||||
|
// fruit: {
|
||||||
|
// point: 'u)'
|
||||||
|
// },
|
||||||
|
// leaf: {
|
||||||
|
// counter: '{u'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// clock: '"}G',
|
||||||
|
// fruit: {
|
||||||
|
// point: 'u)'
|
||||||
|
// },
|
||||||
|
// leaf: {
|
||||||
|
// counter: '{u'
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// point: 'u)'
|
||||||
|
// }]
|
||||||
|
// });
|
||||||
|
// done();
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
// /* eslint-env mocha */
|
88
backup/napi_dump.js
Normal file
88
backup/napi_dump.js
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
// 'use strict';
|
||||||
|
|
||||||
|
// const fs = require('fs');
|
||||||
|
// const path = require('path');
|
||||||
|
|
||||||
|
// const expect = require('chai').expect;
|
||||||
|
// const parser = require('../lib/parser.js');
|
||||||
|
// const chopper = require('../lib/chopper.js');
|
||||||
|
|
||||||
|
// const expectaitions = [
|
||||||
|
// { id: '"}G', time: 100n, cmd: 14, value: 0n, mask: 0n },
|
||||||
|
// { id: '"}G', time: 200n, cmd: 15, value: 0n, mask: 0n },
|
||||||
|
// { id: '{u', time: 200n, cmd: 30, value: 0xf0f0f0f0f0f0f0f0n, mask: 0xff00ff00ff00ff00n },
|
||||||
|
// { id: '"}G', time: 300n, cmd: 14, value: 0n, mask: 0n },
|
||||||
|
// { id: '{u', time: 300n, cmd: 30, value: 0xf000000000000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 300n, cmd: 30, value: 0n, mask: 0n },
|
||||||
|
// { id: '{u', time: 301n, cmd: 30, value: 0x0f00000000000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 301n, cmd: 30, value: 1n, mask: 0n },
|
||||||
|
// { id: '{u', time: 302n, cmd: 30, value: 0x00f0000000000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 302n, cmd: 30, value: 2n, mask: 0n },
|
||||||
|
// { id: '{u', time: 303n, cmd: 30, value: 0x000f000000000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 303n, cmd: 30, value: 3n, mask: 0n },
|
||||||
|
// { id: '{u', time: 304n, cmd: 30, value: 0x0000f00000000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 304n, cmd: 30, value: 4n, mask: 0n },
|
||||||
|
// { id: '{u', time: 305n, cmd: 30, value: 0x00000f0000000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 305n, cmd: 30, value: 5n, mask: 0n },
|
||||||
|
// { id: '{u', time: 306n, cmd: 30, value: 0x000000f000000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 306n, cmd: 30, value: 6n, mask: 0n },
|
||||||
|
// { id: '{u', time: 307n, cmd: 30, value: 0x0000000f00000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 307n, cmd: 30, value: 7n, mask: 0n },
|
||||||
|
// { id: '{u', time: 308n, cmd: 31, value: 0x00000000f0000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 308n, cmd: 30, value: 8n, mask: 0n },
|
||||||
|
// { id: '{u', time: 309n, cmd: 30, value: 0x000000000f000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 309n, cmd: 30, value: 9n, mask: 0n },
|
||||||
|
// { id: '{u', time: 310n, cmd: 30, value: 0x0000000000f00000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 310n, cmd: 30, value: 10n, mask: 0n },
|
||||||
|
// { id: '{u', time: 311n, cmd: 30, value: 0x00000000000f0000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 311n, cmd: 30, value: 11n, mask: 0n },
|
||||||
|
// { id: '{u', time: 312n, cmd: 30, value: 0x000000000000f000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 312n, cmd: 30, value: 12n, mask: 0n },
|
||||||
|
// { id: '{u', time: 313n, cmd: 30, value: 0x0000000000000f00n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 313n, cmd: 30, value: 13n, mask: 0n },
|
||||||
|
// { id: '{u', time: 314n, cmd: 30, value: 0x00000000000000f0n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 314n, cmd: 30, value: 14n, mask: 0n },
|
||||||
|
// { id: '{u', time: 315n, cmd: 30, value: 0x000000000000000fn, mask: 0n },
|
||||||
|
// { id: 'u)', time: 315n, cmd: 30, value: 15n, mask: 0n },
|
||||||
|
// { id: '"}G', time: 316n, cmd: 15, value: 0n, mask: 0n }
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// describe('napi dump', function () {
|
||||||
|
// it('simple napi', done => {
|
||||||
|
// fs.readFile(path.join(__dirname, 'dump.vcd'), function (err, src) {
|
||||||
|
// if (err) {
|
||||||
|
// throw new Error(err);
|
||||||
|
// }
|
||||||
|
// const inst = parser();
|
||||||
|
// const dump = [];
|
||||||
|
// ['"}G', '{u', 'u)'] // array of all signal ids
|
||||||
|
// .map(id =>
|
||||||
|
// inst.change.on(id, (time, cmd, value, mask) => {
|
||||||
|
// const row = {
|
||||||
|
// id,
|
||||||
|
// time: BigInt(time),
|
||||||
|
// cmd,
|
||||||
|
// value,
|
||||||
|
// mask
|
||||||
|
// };
|
||||||
|
// dump.push(row);
|
||||||
|
// // console.log(row);
|
||||||
|
// })
|
||||||
|
// );
|
||||||
|
|
||||||
|
// inst.on('finish', () => {
|
||||||
|
// expect(inst.getTime()).to.eq(316n);
|
||||||
|
// expect(dump).to.deep.eq(expectaitions);
|
||||||
|
// done();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// for (const chunk of chopper(src, 100)) {
|
||||||
|
// // console.log('\u001b[31m[\u001b[0m' + chunk.toString() + '\u001b[31m]\u001b[0m');
|
||||||
|
// inst.write(chunk);
|
||||||
|
// }
|
||||||
|
// inst.end();
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
// /* eslint-env mocha */
|
79
backup/napi_events.js
Normal file
79
backup/napi_events.js
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// 'use strict';
|
||||||
|
|
||||||
|
// const expect = require('chai').expect;
|
||||||
|
// const parser = require('../lib/parser.js');
|
||||||
|
|
||||||
|
// describe('events', () => {
|
||||||
|
|
||||||
|
// it('$enddefinitions', done => {
|
||||||
|
// const inst = parser();
|
||||||
|
// inst.on('$enddefinitions', () => {
|
||||||
|
// expect(inst.info).to.deep.eq({
|
||||||
|
// status: 'simulation',
|
||||||
|
// date: ' Wed Sep 18 22:59:07 2019\n ',
|
||||||
|
// version: ' Generated by VerilatedVcd ',
|
||||||
|
// timescale: ' 1ns ',
|
||||||
|
// varId: 'u)',
|
||||||
|
// wires: {
|
||||||
|
// top: {
|
||||||
|
// clock: '"}G',
|
||||||
|
// fruit: {
|
||||||
|
// point: 'u)'
|
||||||
|
// },
|
||||||
|
// leaf: {
|
||||||
|
// counter: '{u'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// stack: [{
|
||||||
|
// top: {
|
||||||
|
// clock: '"}G',
|
||||||
|
// fruit: {
|
||||||
|
// point: 'u)'
|
||||||
|
// },
|
||||||
|
// leaf: {
|
||||||
|
// counter: '{u'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// clock: '"}G',
|
||||||
|
// fruit: {
|
||||||
|
// point: 'u)'
|
||||||
|
// },
|
||||||
|
// leaf: {
|
||||||
|
// counter: '{u'
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// point: 'u)'
|
||||||
|
// }]
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// expect(inst.write(`
|
||||||
|
// $version Generated by VerilatedVcd $end
|
||||||
|
// $date Wed Sep 18 22:59:07 2019
|
||||||
|
// $end
|
||||||
|
// $timescale 1ns $end
|
||||||
|
|
||||||
|
// $scope module top $end
|
||||||
|
// $var wire 1 "}G clock $end
|
||||||
|
// $scope module leaf $end
|
||||||
|
// $var wire 64 {u counter [63:0] $end
|
||||||
|
// $upscope $end
|
||||||
|
// $scope module fruit $end
|
||||||
|
// $var wire 4 u) point [3:0] $end
|
||||||
|
// $upscope $end
|
||||||
|
// $upscope $end
|
||||||
|
|
||||||
|
// $enddefinitions $end
|
||||||
|
// `
|
||||||
|
// )).to.eq(true);
|
||||||
|
|
||||||
|
// done();
|
||||||
|
// });
|
||||||
|
|
||||||
|
|
||||||
|
// });
|
||||||
|
|
||||||
|
// /* eslint-env mocha */
|
72
backup/wasm_any.js
Normal file
72
backup/wasm_any.js
Normal file
File diff suppressed because one or more lines are too long
135
backup/wasm_basic.js
Normal file
135
backup/wasm_basic.js
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
// 'use strict';
|
||||||
|
// /* eslint-disable no-console */
|
||||||
|
// /* eslint-disable indent */
|
||||||
|
// /* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
|
// const expect = require('chai').expect;
|
||||||
|
// const createVCD = require('../out/vcd.js');
|
||||||
|
// const webVcdParser = require('../lib/web-vcd-parser.js');
|
||||||
|
|
||||||
|
// describe('wasm basic', () => {
|
||||||
|
|
||||||
|
// it('typeof vcd', async function () {
|
||||||
|
// const mod = await createVCD();
|
||||||
|
// expect(mod).to.be.an('object');
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it('typeof vcd instance', async function () {
|
||||||
|
// const mod = await createVCD();
|
||||||
|
// const inst = await webVcdParser(mod);
|
||||||
|
// expect(inst).to.be.an('object');
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it('fail: foo bar', async function () {
|
||||||
|
// const mod = await createVCD();
|
||||||
|
// const inst = await webVcdParser(mod);
|
||||||
|
// expect(inst.write(Buffer.from(' foo bar ???'))).to.eq(true);
|
||||||
|
// expect(inst.info).to.deep.eq({
|
||||||
|
// stack: [{}],
|
||||||
|
// status: 'declaration',
|
||||||
|
// wires: {}
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it('$comment', async function () {
|
||||||
|
// const mod = await createVCD();
|
||||||
|
// const inst = await webVcdParser(mod);
|
||||||
|
// expect(inst.write(Buffer.from(
|
||||||
|
// ' \n $comment some text $end $comment more text $end ???'
|
||||||
|
// ))).to.eq(true);
|
||||||
|
// expect(inst.info).to.deep.eq({
|
||||||
|
// comment: ' more text ',
|
||||||
|
// stack: [{}],
|
||||||
|
// status: 'declaration',
|
||||||
|
// wires: {}
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it('$version', async function () {
|
||||||
|
// const mod = await createVCD();
|
||||||
|
// const inst = await webVcdParser(mod);
|
||||||
|
// expect(inst.write(`
|
||||||
|
// $version Generated by VerilatedVcd $end
|
||||||
|
// $date Wed Sep 18 22:59:07 2019
|
||||||
|
// $end
|
||||||
|
// $timescale 1ns $end
|
||||||
|
|
||||||
|
// $scope module top $end
|
||||||
|
// $var wire 1 "}G clock $end
|
||||||
|
// $scope module leaf $end
|
||||||
|
// $var wire 64 {u counter [63:0] $end
|
||||||
|
// $upscope $end
|
||||||
|
// $scope module fruit $end
|
||||||
|
// $var wire 4 u) point [3:0] $end
|
||||||
|
// $upscope $end
|
||||||
|
// $upscope $end
|
||||||
|
|
||||||
|
// $enddefinitions $end
|
||||||
|
// `
|
||||||
|
// )).to.eq(true);
|
||||||
|
|
||||||
|
// expect(inst.write(`
|
||||||
|
|
||||||
|
// #1
|
||||||
|
// 0"}G
|
||||||
|
// #2
|
||||||
|
// 1"}G
|
||||||
|
// #300
|
||||||
|
// 0"}G
|
||||||
|
// b1111000000000000 {u
|
||||||
|
// #301
|
||||||
|
// b0000111100000000 {u
|
||||||
|
// #302
|
||||||
|
// b0000000011110000 {u
|
||||||
|
// #303
|
||||||
|
// b0000000000001111 {u
|
||||||
|
// `
|
||||||
|
// )).to.eq(true);
|
||||||
|
|
||||||
|
// expect(inst.info).to.deep.eq({
|
||||||
|
// status: 'simulation',
|
||||||
|
// date: ' Wed Sep 18 22:59:07 2019\n ',
|
||||||
|
// version: ' Generated by VerilatedVcd ',
|
||||||
|
// timescale: ' 1ns ',
|
||||||
|
// t0: 1,
|
||||||
|
// varId: 'u)',
|
||||||
|
// wires: {
|
||||||
|
// top: {
|
||||||
|
// clock: '"}G',
|
||||||
|
// fruit: {
|
||||||
|
// point: 'u)'
|
||||||
|
// },
|
||||||
|
// leaf: {
|
||||||
|
// counter: '{u'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// stack: [{
|
||||||
|
// top: {
|
||||||
|
// clock: '"}G',
|
||||||
|
// fruit: {
|
||||||
|
// point: 'u)'
|
||||||
|
// },
|
||||||
|
// leaf: {
|
||||||
|
// counter: '{u'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// clock: '"}G',
|
||||||
|
// fruit: {
|
||||||
|
// point: 'u)'
|
||||||
|
// },
|
||||||
|
// leaf: {
|
||||||
|
// counter: '{u'
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// point: 'u)'
|
||||||
|
// }]
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
// });
|
||||||
|
|
||||||
|
// /* eslint-env mocha */
|
98
backup/wasm_dump.js
Normal file
98
backup/wasm_dump.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// 'use strict';
|
||||||
|
// /* eslint-disable no-console */
|
||||||
|
// /* eslint-disable indent */
|
||||||
|
// /* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
|
// const fs = require('fs');
|
||||||
|
// const path = require('path');
|
||||||
|
|
||||||
|
// const expect = require('chai').expect;
|
||||||
|
// const createVCD = require('../out/vcd.js');
|
||||||
|
// const webVcdParser = require('../lib/web-vcd-parser.js');
|
||||||
|
// const chopper = require('../lib/chopper.js');
|
||||||
|
|
||||||
|
// const expectaitions = [
|
||||||
|
// { id: '"}G', time: 100n, cmd: 14, value: undefined, mask: undefined },
|
||||||
|
// { id: '"}G', time: 200n, cmd: 15, value: undefined, mask: undefined },
|
||||||
|
// { id: '{u', time: 200n, cmd: 30, value: 0xf0f0f0f0f0f0f0f0n, mask: 0xff00ff00ff00ff00n },
|
||||||
|
// { id: '"}G', time: 300n, cmd: 14, value: undefined, mask: undefined },
|
||||||
|
// { id: '{u', time: 300n, cmd: 30, value: 0xf000000000000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 300n, cmd: 30, value: 0n, mask: 0n },
|
||||||
|
// { id: '{u', time: 301n, cmd: 30, value: 0x0f00000000000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 301n, cmd: 30, value: 1n, mask: 0n },
|
||||||
|
// { id: '{u', time: 302n, cmd: 30, value: 0x00f0000000000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 302n, cmd: 30, value: 2n, mask: 0n },
|
||||||
|
// { id: '{u', time: 303n, cmd: 30, value: 0x000f000000000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 303n, cmd: 30, value: 3n, mask: 0n },
|
||||||
|
// { id: '{u', time: 304n, cmd: 30, value: 0x0000f00000000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 304n, cmd: 30, value: 4n, mask: 0n },
|
||||||
|
// { id: '{u', time: 305n, cmd: 30, value: 0x00000f0000000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 305n, cmd: 30, value: 5n, mask: 0n },
|
||||||
|
// { id: '{u', time: 306n, cmd: 30, value: 0x000000f000000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 306n, cmd: 30, value: 6n, mask: 0n },
|
||||||
|
// { id: '{u', time: 307n, cmd: 30, value: 0x0000000f00000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 307n, cmd: 30, value: 7n, mask: 0n },
|
||||||
|
// { id: '{u', time: 308n, cmd: 31, value: 0x00000000f0000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 308n, cmd: 30, value: 8n, mask: 0n },
|
||||||
|
// { id: '{u', time: 309n, cmd: 30, value: 0x000000000f000000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 309n, cmd: 30, value: 9n, mask: 0n },
|
||||||
|
// { id: '{u', time: 310n, cmd: 30, value: 0x0000000000f00000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 310n, cmd: 30, value: 10n, mask: 0n },
|
||||||
|
// { id: '{u', time: 311n, cmd: 30, value: 0x00000000000f0000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 311n, cmd: 30, value: 11n, mask: 0n },
|
||||||
|
// { id: '{u', time: 312n, cmd: 30, value: 0x000000000000f000n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 312n, cmd: 30, value: 12n, mask: 0n },
|
||||||
|
// { id: '{u', time: 313n, cmd: 30, value: 0x0000000000000f00n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 313n, cmd: 30, value: 13n, mask: 0n },
|
||||||
|
// { id: '{u', time: 314n, cmd: 30, value: 0x00000000000000f0n, mask: 0n },
|
||||||
|
// { id: 'u)', time: 314n, cmd: 30, value: 14n, mask: 0n },
|
||||||
|
// { id: '{u', time: 315n, cmd: 30, value: 0x000000000000000fn, mask: 0n },
|
||||||
|
// { id: 'u)', time: 315n, cmd: 30, value: 15n, mask: 0n },
|
||||||
|
// { id: '"}G', time: 316n, cmd: 15, value: undefined, mask: undefined }
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// describe('wasm dump', () => {
|
||||||
|
// it('simple wasm', done => {
|
||||||
|
// fs.readFile(path.join(__dirname, 'dump.vcd'), function (err, src) {
|
||||||
|
// if (err) {
|
||||||
|
// throw new Error(err);
|
||||||
|
// }
|
||||||
|
// createVCD().then((mod) => {
|
||||||
|
// webVcdParser(mod).then((inst) => {
|
||||||
|
// const dump = [];
|
||||||
|
// ['"}G', '{u', 'u)'] // array of all signal ids
|
||||||
|
// .map(id =>
|
||||||
|
// inst.change.on(id, (time, cmd, value, mask) => {
|
||||||
|
// const row = {
|
||||||
|
// id,
|
||||||
|
// time,
|
||||||
|
// cmd,
|
||||||
|
// value,
|
||||||
|
// mask
|
||||||
|
// };
|
||||||
|
// dump.push(row);
|
||||||
|
// // console.log(row);
|
||||||
|
// })
|
||||||
|
// );
|
||||||
|
|
||||||
|
// inst.on('finish', () => {
|
||||||
|
// expect(inst.getTime()).to.eq(316n);
|
||||||
|
// // console.log(dump);
|
||||||
|
// // expect(dump.length).to.eq(expectaitions.length);
|
||||||
|
// expect(dump).to.deep.eq(expectaitions);
|
||||||
|
// done();
|
||||||
|
// });
|
||||||
|
// const step = (Math.random() * 500) |0;
|
||||||
|
// for (const chunk of chopper(src, step)) {
|
||||||
|
// // console.log('\n\u001b[31m[\u001b[0m' + chunk.toString() + '\u001b[31m](\u001b[0m\n' + chunk.length + '\u001b[31m)\u001b[0m\n');
|
||||||
|
// inst.write(chunk);
|
||||||
|
// }
|
||||||
|
// inst.end();
|
||||||
|
// // console.log(step);
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
// /* eslint-env mocha */
|
83
backup/wasm_events.js
Normal file
83
backup/wasm_events.js
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// 'use strict';
|
||||||
|
// /* eslint-disable no-console */
|
||||||
|
// /* eslint-disable indent */
|
||||||
|
// /* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
|
// const expect = require('chai').expect;
|
||||||
|
// const createVCD = require('../out/vcd.js');
|
||||||
|
// const webVcdParser = require('../lib/web-vcd-parser.js');
|
||||||
|
|
||||||
|
// describe('wasm events', () => {
|
||||||
|
|
||||||
|
// it('$enddefinitions', async function () {
|
||||||
|
// const mod = await createVCD();
|
||||||
|
// const inst = await webVcdParser(mod);
|
||||||
|
|
||||||
|
// inst.on('$enddefinitions', () => {
|
||||||
|
// expect(inst.info).to.deep.eq({
|
||||||
|
// status: 'simulation',
|
||||||
|
// timescale: ' 1ns ',
|
||||||
|
// date: ' Wed Sep 18 22:59:07 2019\n ',
|
||||||
|
// version: ' Generated by VerilatedVcd ',
|
||||||
|
// varId: 'u)',
|
||||||
|
// wires: {
|
||||||
|
// top: {
|
||||||
|
// clock: '"}G',
|
||||||
|
// fruit: {
|
||||||
|
// point: 'u)'
|
||||||
|
// },
|
||||||
|
// leaf: {
|
||||||
|
// counter: '{u'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// stack: [{
|
||||||
|
// top: {
|
||||||
|
// clock: '"}G',
|
||||||
|
// fruit: {
|
||||||
|
// point: 'u)'
|
||||||
|
// },
|
||||||
|
// leaf: {
|
||||||
|
// counter: '{u'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// clock: '"}G',
|
||||||
|
// fruit: {
|
||||||
|
// point: 'u)'
|
||||||
|
// },
|
||||||
|
// leaf: {
|
||||||
|
// counter: '{u'
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// point: 'u)'
|
||||||
|
// }]
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// expect(inst.write(`
|
||||||
|
// $version Generated by VerilatedVcd $end
|
||||||
|
// $date Wed Sep 18 22:59:07 2019
|
||||||
|
// $end
|
||||||
|
// $timescale 1ns $end
|
||||||
|
|
||||||
|
// $scope module top $end
|
||||||
|
// $var wire 1 "}G clock $end
|
||||||
|
// $scope module leaf $end
|
||||||
|
// $var wire 64 {u counter [63:0] $end
|
||||||
|
// $upscope $end
|
||||||
|
// $scope module fruit $end
|
||||||
|
// $var wire 4 u) point [3:0] $end
|
||||||
|
// $upscope $end
|
||||||
|
// $upscope $end
|
||||||
|
|
||||||
|
// $enddefinitions $end
|
||||||
|
// `
|
||||||
|
// )).to.eq(true);
|
||||||
|
// });
|
||||||
|
|
||||||
|
|
||||||
|
// });
|
||||||
|
|
||||||
|
// /* eslint-env mocha */
|
444
bin/build.js
444
bin/build.js
@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
|
/* eslint-disable indent */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
@ -7,89 +8,89 @@ const cp = require('child_process');
|
|||||||
const llparse = require('llparse');
|
const llparse = require('llparse');
|
||||||
|
|
||||||
const gyp = cb => {
|
const gyp = cb => {
|
||||||
console.log('build');
|
console.log('build');
|
||||||
const proc = cp.spawn('node-gyp', ['configure', 'build']);
|
const proc = cp.spawn('node-gyp', ['configure', 'build']);
|
||||||
proc.stderr.on('data', data => {
|
proc.stderr.on('data', data => {
|
||||||
console.error(data.toString());
|
console.error(data.toString());
|
||||||
});
|
});
|
||||||
proc.on('close', (cb || (() => {
|
proc.on('close', (cb || (() => {
|
||||||
console.log('done');
|
console.log('done');
|
||||||
})));
|
})));
|
||||||
};
|
};
|
||||||
|
|
||||||
const objection = lut => arg => arg.split(/\s+/).reduce((res, key) => {
|
const objection = lut => arg => arg.split(/\s+/).reduce((res, key) => {
|
||||||
if (lut[key] === undefined) {
|
if (lut[key] === undefined) {
|
||||||
throw new Error(key);
|
throw new Error(key);
|
||||||
}
|
}
|
||||||
res[key] = lut[key];
|
res[key] = lut[key];
|
||||||
return res;
|
return res;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
const properties = {
|
const properties = {
|
||||||
command: 'i8',
|
command: 'i8',
|
||||||
type: 'i8',
|
type: 'i8',
|
||||||
size: 'i32',
|
size: 'i32',
|
||||||
time: 'i64', // current simulation time
|
time: 'i64', // current simulation time
|
||||||
trigger: 'ptr',
|
trigger: 'ptr',
|
||||||
triee: 'ptr', // trigger event emitter
|
triee: 'ptr', // trigger event emitter
|
||||||
lifee: 'ptr', // life cycle event emmiter
|
lifee: 'ptr', // life cycle event emmiter
|
||||||
info: 'ptr',
|
info: 'ptr',
|
||||||
value: 'ptr', // value of the signal on change event
|
value: 'ptr', // value of the signal on change event
|
||||||
mask: 'ptr', // mask (x, z) of the signal on change event
|
mask: 'ptr', // mask (x, z) of the signal on change event
|
||||||
digitCount: 'i32',
|
digitCount: 'i32',
|
||||||
maskCount: 'i32',
|
maskCount: 'i32',
|
||||||
tmpStr: 'ptr',
|
tmpStr: 'ptr',
|
||||||
timeStampStr: 'ptr',
|
timeStampStr: 'ptr',
|
||||||
idStr: 'ptr',
|
idStr: 'ptr',
|
||||||
tmpStr2: 'ptr',
|
tmpStr2: 'ptr',
|
||||||
stackPointer: 'i32',
|
stackPointer: 'i32',
|
||||||
id: 'ptr',
|
id: 'ptr',
|
||||||
napi_env: 'ptr'
|
napi_env: 'ptr'
|
||||||
};
|
};
|
||||||
|
|
||||||
const spaces = [' ', '\n', '\r', '\t'];
|
const spaces = [' ', '\n', '\r', '\t'];
|
||||||
const lineSpaces = [' ', '\t'];
|
const lineSpaces = [' ', '\t'];
|
||||||
|
|
||||||
const generate = (cb) => {
|
const generate = (cb) => {
|
||||||
// const llparseDot = require('llparse-dot');
|
// const llparseDot = require('llparse-dot');
|
||||||
|
|
||||||
const prj = 'vcd_parser';
|
const prj = 'vcd_parser';
|
||||||
const p = new llparse.LLParse(prj);
|
const p = new llparse.LLParse(prj);
|
||||||
|
|
||||||
Object.keys(properties).map(key => p.property(properties[key], key));
|
Object.keys(properties).map(key => p.property(properties[key], key));
|
||||||
|
|
||||||
const {
|
const {
|
||||||
// scopeIdentifierSpan,
|
// scopeIdentifierSpan,
|
||||||
varSizeSpan, varIdSpan, varNameSpan,
|
varSizeSpan, varIdSpan, varNameSpan,
|
||||||
idSpan,
|
idSpan,
|
||||||
commandSpan,
|
commandSpan,
|
||||||
timeSpan
|
timeSpan
|
||||||
} = `
|
} = `
|
||||||
varSizeSpan varIdSpan varNameSpan
|
varSizeSpan varIdSpan varNameSpan
|
||||||
idSpan
|
idSpan
|
||||||
commandSpan
|
commandSpan
|
||||||
timeSpan
|
timeSpan
|
||||||
`
|
`
|
||||||
.trim().split(/\s+/)
|
.trim().split(/\s+/)
|
||||||
.reduce((res, n) => Object.assign(res, {[n]: p.span(p.code.span(n))}), {});
|
.reduce((res, n) => Object.assign(res, { [n]: p.span(p.code.span(n)) }), {});
|
||||||
|
|
||||||
// scopeIdentifierSpan
|
// scopeIdentifierSpan
|
||||||
|
|
||||||
const {
|
const {
|
||||||
declaration,
|
declaration,
|
||||||
// scopeType, scopeTypeEnd,
|
// scopeType, scopeTypeEnd,
|
||||||
// scopeIdentifier, scopeIdentifierEnd,
|
// scopeIdentifier, scopeIdentifierEnd,
|
||||||
varType, varTypeEnd,
|
varType, varTypeEnd,
|
||||||
varSize, varSizeEnd,
|
varSize, varSizeEnd,
|
||||||
varId, varIdEnd,
|
varId, varIdEnd,
|
||||||
varName, varNameEnd,
|
varName, varNameEnd,
|
||||||
inDeclaration,
|
inDeclaration,
|
||||||
simulation,
|
simulation,
|
||||||
inSimulation,
|
inSimulation,
|
||||||
simulationTime,
|
simulationTime,
|
||||||
simulationVector, simulationVectorEnd, simulationVectorRecovery,
|
simulationVector, simulationVectorEnd, simulationVectorRecovery,
|
||||||
simulationId
|
simulationId
|
||||||
} = `
|
} = `
|
||||||
declaration
|
declaration
|
||||||
varType varTypeEnd
|
varType varTypeEnd
|
||||||
varSize varSizeEnd
|
varSize varSizeEnd
|
||||||
@ -102,211 +103,178 @@ const generate = (cb) => {
|
|||||||
simulationVector simulationVectorEnd simulationVectorRecovery
|
simulationVector simulationVectorEnd simulationVectorRecovery
|
||||||
simulationId
|
simulationId
|
||||||
`
|
`
|
||||||
.trim().split(/\s+/)
|
.trim().split(/\s+/)
|
||||||
.reduce((res, n) => Object.assign(res, {[n]: p.node(n)}), {});
|
.reduce((res, n) => Object.assign(res, { [n]: p.node(n) }), {});
|
||||||
|
|
||||||
// scopeType scopeTypeEnd
|
// scopeType scopeTypeEnd
|
||||||
// scopeIdentifier scopeIdentifierEnd
|
// scopeIdentifier scopeIdentifierEnd
|
||||||
|
|
||||||
const enddefinitions = p.node('inDeclarationEnd');
|
const enddefinitions = p.node('inDeclarationEnd');
|
||||||
|
|
||||||
const cmd = objection({
|
|
||||||
$comment: 1,
|
|
||||||
$date: 2,
|
|
||||||
$scope: 3,
|
|
||||||
$timescale: 4,
|
|
||||||
$upscope: 5,
|
|
||||||
$var: 6,
|
|
||||||
$version: 7,
|
|
||||||
$enddefinitions: 8,
|
|
||||||
$dumpall: 9,
|
|
||||||
$dumpoff: 10,
|
|
||||||
$dumpon: 11,
|
|
||||||
$dumpvars: 12,
|
|
||||||
'#': 13,
|
|
||||||
'0': 14, '1': 15,
|
|
||||||
x: 16, X: 17,
|
|
||||||
z: 18, Z: 19,
|
|
||||||
u: 20, U: 21, // VHDL states
|
|
||||||
w: 22, W: 23,
|
|
||||||
l: 24, L: 25,
|
|
||||||
h: 26, H: 27,
|
|
||||||
'-': 28,
|
|
||||||
b: 30, B: 31, r: 32, R: 33
|
|
||||||
});
|
|
||||||
|
|
||||||
declaration
|
const cmd = objection({
|
||||||
.match(spaces, declaration)
|
$comment: 1,
|
||||||
// .select(cmd('$scope'),
|
$date: 2,
|
||||||
// p.invoke(p.code.store('command'), commandSpan.start(scopeType)))
|
$scope: 3,
|
||||||
// .select(cmd('$var'),
|
$timescale: 4,
|
||||||
// p.invoke(p.code.store('command'), commandSpan.start(varType)))
|
$upscope: 5,
|
||||||
.select(cmd('$scope $var $upscope $comment $date $timescale $version'),
|
$var: 6,
|
||||||
p.invoke(p.code.store('command'), commandSpan.start(inDeclaration)))
|
$version: 7,
|
||||||
.select(cmd('$enddefinitions'),
|
$enddefinitions: 8,
|
||||||
p.invoke(p.code.store('command'), commandSpan.start(enddefinitions)))
|
$dumpall: 9,
|
||||||
.otherwise(p.error(1, 'Expected declaration command'));
|
$dumpoff: 10,
|
||||||
|
$dumpon: 11,
|
||||||
|
$dumpvars: 12,
|
||||||
|
'#': 13,
|
||||||
|
'0': 14, '1': 15,
|
||||||
|
x: 16, X: 17,
|
||||||
|
z: 18, Z: 19,
|
||||||
|
u: 20, U: 21, // VHDL states
|
||||||
|
w: 22, W: 23,
|
||||||
|
l: 24, L: 25,
|
||||||
|
h: 26, H: 27,
|
||||||
|
'-': 28,
|
||||||
|
b: 30, B: 31, r: 32, R: 33
|
||||||
|
});
|
||||||
|
|
||||||
// $scope module clkdiv2n_tb $end
|
declaration
|
||||||
// ^^^^^^
|
.match(spaces, declaration)
|
||||||
|
.select(cmd('$scope $var $upscope $comment $date $timescale $version'),
|
||||||
|
p.invoke(p.code.store('command'), commandSpan.start(inDeclaration)))
|
||||||
|
.select(cmd('$enddefinitions'),
|
||||||
|
p.invoke(p.code.store('command'), commandSpan.start(enddefinitions)))
|
||||||
|
.otherwise(p.error(1, 'Expected declaration command'));
|
||||||
|
|
||||||
// scopeType.match(spaces, scopeType).otherwise(scopeTypeEnd);
|
|
||||||
// scopeTypeEnd
|
|
||||||
// .select(
|
|
||||||
// {
|
|
||||||
// module: 0,
|
|
||||||
// task: 1,
|
|
||||||
// function: 2,
|
|
||||||
// begin: 3,
|
|
||||||
// fork: 4,
|
|
||||||
// // extra scopes from Verilator
|
|
||||||
// generate: 5,
|
|
||||||
// struct: 6,
|
|
||||||
// union: 7,
|
|
||||||
// class: 8,
|
|
||||||
// interface: 9,
|
|
||||||
// package: 10,
|
|
||||||
// program: 11
|
|
||||||
// },
|
|
||||||
// p.invoke(p.code.store('type'), scopeIdentifier))
|
|
||||||
// .otherwise(p.error(2, 'Expected scope type'));
|
|
||||||
|
|
||||||
// $scope module clkdiv2n_tb $end
|
varType.match(spaces, varType).otherwise(varTypeEnd);
|
||||||
// ^^^^^^^^^^^
|
varTypeEnd
|
||||||
|
.select({
|
||||||
|
event: 1,
|
||||||
|
integer: 2,
|
||||||
|
parameter: 3,
|
||||||
|
real: 4,
|
||||||
|
realtime: 5,
|
||||||
|
reg: 6,
|
||||||
|
supply0: 7,
|
||||||
|
supply1: 8,
|
||||||
|
time: 9,
|
||||||
|
tri: 10,
|
||||||
|
triand: 11,
|
||||||
|
trior: 12,
|
||||||
|
trireg: 13,
|
||||||
|
tri0: 14,
|
||||||
|
tri1: 15,
|
||||||
|
wand: 16,
|
||||||
|
wire: 17,
|
||||||
|
wor: 18
|
||||||
|
}, p.invoke(p.code.store('type'), varSize))
|
||||||
|
.otherwise(p.error(3, 'Expected var type'));
|
||||||
|
|
||||||
// scopeIdentifier.match(spaces, scopeIdentifier).otherwise(scopeIdentifierSpan.start(scopeIdentifierEnd));
|
// $var reg 3 ( r_reg [2:0] $end
|
||||||
// scopeIdentifierEnd.match(spaces, scopeIdentifierSpan.end(inDeclaration)).skipTo(scopeIdentifierEnd);
|
// ^
|
||||||
|
|
||||||
// $var reg 3 ( r_reg [2:0] $end
|
varSize.match(spaces, varSize).otherwise(varSizeSpan.start(varSizeEnd));
|
||||||
// ^^^
|
varSizeEnd.match(spaces, varSizeSpan.end(varId)).skipTo(varSizeEnd);
|
||||||
|
|
||||||
varType.match(spaces, varType).otherwise(varTypeEnd);
|
// $var reg 3 ( r_reg [2:0] $end
|
||||||
varTypeEnd
|
// ^
|
||||||
.select({
|
|
||||||
event: 1,
|
|
||||||
integer: 2,
|
|
||||||
parameter: 3,
|
|
||||||
real: 4,
|
|
||||||
realtime: 5,
|
|
||||||
reg: 6,
|
|
||||||
supply0: 7,
|
|
||||||
supply1: 8,
|
|
||||||
time: 9,
|
|
||||||
tri: 10,
|
|
||||||
triand: 11,
|
|
||||||
trior: 12,
|
|
||||||
trireg: 13,
|
|
||||||
tri0: 14,
|
|
||||||
tri1: 15,
|
|
||||||
wand: 16,
|
|
||||||
wire: 17,
|
|
||||||
wor: 18
|
|
||||||
}, p.invoke(p.code.store('type'), varSize))
|
|
||||||
.otherwise(p.error(3, 'Expected var type'));
|
|
||||||
|
|
||||||
// $var reg 3 ( r_reg [2:0] $end
|
varId.match(spaces, varId).otherwise(varIdSpan.start(varIdEnd));
|
||||||
// ^
|
varIdEnd.match(spaces, varIdSpan.end(varName)).skipTo(varIdEnd);
|
||||||
|
|
||||||
varSize.match(spaces, varSize).otherwise(varSizeSpan.start(varSizeEnd));
|
// $var reg 3 ( r_reg [2:0] $end
|
||||||
varSizeEnd.match(spaces, varSizeSpan.end(varId)).skipTo(varSizeEnd);
|
// ^^^^^
|
||||||
|
|
||||||
// $var reg 3 ( r_reg [2:0] $end
|
varName.match(spaces, varName).otherwise(varNameSpan.start(varNameEnd));
|
||||||
// ^
|
varNameEnd.match('$end', commandSpan.end(varNameSpan.end(declaration))).skipTo(varNameEnd);
|
||||||
|
|
||||||
varId.match(spaces, varId).otherwise(varIdSpan.start(varIdEnd));
|
// $end
|
||||||
varIdEnd.match(spaces, varIdSpan.end(varName)).skipTo(varIdEnd);
|
|
||||||
|
|
||||||
// $var reg 3 ( r_reg [2:0] $end
|
inDeclaration
|
||||||
// ^^^^^
|
.match('$end', commandSpan.end(declaration))
|
||||||
|
.skipTo(inDeclaration);
|
||||||
|
|
||||||
varName.match(spaces, varName).otherwise(varNameSpan.start(varNameEnd));
|
enddefinitions
|
||||||
varNameEnd.match('$end', commandSpan.end(varNameSpan.end(declaration))).skipTo(varNameEnd);
|
.match('$end', commandSpan.end(simulation))
|
||||||
|
.skipTo(enddefinitions);
|
||||||
|
|
||||||
// $end
|
simulation
|
||||||
|
.match([' ', '\r', '\n', '\t', '$dumpvars', '$dumpall', '$end'], simulation)
|
||||||
|
.select(cmd('$dumpoff $dumpon $comment'),
|
||||||
|
p.invoke(p.code.store('command'), commandSpan.start(inSimulation)))
|
||||||
|
.select(cmd('#'),
|
||||||
|
p.invoke(p.code.store('command'), timeSpan.start(simulationTime)))
|
||||||
|
.select(cmd('0 1 x X z Z u U w W l L h H -'),
|
||||||
|
p.invoke(p.code.store('command'), idSpan.start(simulationId)))
|
||||||
|
.select(cmd('b B r R'),
|
||||||
|
p.invoke(p.code.store('command'), simulationVector))
|
||||||
|
.otherwise(p.error(4, 'Expected simulation command'));
|
||||||
|
|
||||||
inDeclaration
|
inSimulation
|
||||||
.match('$end', commandSpan.end(declaration))
|
.match('$end', commandSpan.end(simulation))
|
||||||
.skipTo(inDeclaration);
|
.skipTo(inSimulation);
|
||||||
|
|
||||||
enddefinitions
|
simulationTime
|
||||||
.match('$end', commandSpan.end(simulation))
|
.match(spaces, timeSpan.end(p.invoke(p.code.span('onTime'), simulation)))
|
||||||
.skipTo(enddefinitions);
|
.skipTo(simulationTime);
|
||||||
|
|
||||||
simulation
|
simulationVector
|
||||||
.match([' ', '\r', '\n', '\t', '$dumpvars', '$end'], simulation)
|
.select(
|
||||||
.select(cmd('$dumpall $dumpoff $dumpon $comment'),
|
{
|
||||||
p.invoke(p.code.store('command'), commandSpan.start(inSimulation)))
|
0: 0,
|
||||||
.select(cmd('#'),
|
1: 1,
|
||||||
p.invoke(p.code.store('command'), timeSpan.start(simulationTime)))
|
x: 2, X: 2,
|
||||||
.select(cmd('0 1 x X z Z u U w W l L h H -'),
|
z: 3, Z: 3,
|
||||||
p.invoke(p.code.store('command'), idSpan.start(simulationId)))
|
u: 3, U: 3, // VHDL states
|
||||||
.select(cmd('b B r R'),
|
w: 3, W: 3,
|
||||||
p.invoke(p.code.store('command'), simulationVector))
|
l: 3, L: 3,
|
||||||
.otherwise(p.error(4, 'Expected simulation command'));
|
h: 3, H: 3,
|
||||||
|
'-': 3
|
||||||
|
},
|
||||||
|
p.invoke(
|
||||||
|
// p.code.mulAdd('value', {base: 2, signed: false}),
|
||||||
|
p.code.value('onDigit'),
|
||||||
|
{ 1: p.error(5, 'Content-Length overflow') },
|
||||||
|
simulationVector
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.otherwise(simulationVectorEnd);
|
||||||
|
|
||||||
inSimulation
|
simulationVectorEnd
|
||||||
.match('$end', commandSpan.end(simulation))
|
.match(lineSpaces, idSpan.start(simulationId))
|
||||||
.skipTo(inSimulation);
|
.skipTo(simulationVectorRecovery);
|
||||||
|
|
||||||
simulationTime
|
simulationVectorRecovery
|
||||||
.match(spaces, timeSpan.end(p.invoke(p.code.span('onTime'), simulation)))
|
.select(
|
||||||
.skipTo(simulationTime);
|
{
|
||||||
|
'\n': 1, '\r': 1
|
||||||
|
},
|
||||||
|
p.invoke(
|
||||||
|
p.code.value('onRecover'),
|
||||||
|
{ 1: p.error(6, 'recover') },
|
||||||
|
simulation
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.skipTo(simulationVectorRecovery);
|
||||||
|
|
||||||
simulationVector
|
simulationId
|
||||||
.select(
|
.match(spaces, idSpan.end(p.invoke(p.code.span('onId'), simulation)))
|
||||||
{
|
.skipTo(simulationId);
|
||||||
0: 0,
|
|
||||||
1: 1,
|
|
||||||
x: 2, X: 2,
|
|
||||||
z: 3, Z: 3,
|
|
||||||
u: 3, U: 3, // VHDL states
|
|
||||||
w: 3, W: 3,
|
|
||||||
l: 3, L: 3,
|
|
||||||
h: 3, H: 3,
|
|
||||||
'-': 3
|
|
||||||
},
|
|
||||||
p.invoke(
|
|
||||||
// p.code.mulAdd('value', {base: 2, signed: false}),
|
|
||||||
p.code.value('onDigit'),
|
|
||||||
{1: p.error(5, 'Content-Length overflow')},
|
|
||||||
simulationVector
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.otherwise(simulationVectorEnd);
|
|
||||||
|
|
||||||
simulationVectorEnd
|
const artifacts = p.build(declaration);
|
||||||
.match(lineSpaces, idSpan.start(simulationId))
|
|
||||||
.skipTo(simulationVectorRecovery);
|
|
||||||
|
|
||||||
simulationVectorRecovery
|
fs.writeFileSync(prj + '.h', artifacts.header);
|
||||||
.select(
|
// fs.writeFileSync('verilog_preprocessor.bc', artifacts.bitcode);
|
||||||
{
|
fs.writeFileSync(prj + '.c', artifacts.c);
|
||||||
'\n': 1, '\r': 1
|
|
||||||
},
|
|
||||||
p.invoke(
|
|
||||||
p.code.value('onRecover'),
|
|
||||||
{1: p.error(6, 'recover')},
|
|
||||||
simulation
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.skipTo(simulationVectorRecovery);
|
|
||||||
|
|
||||||
simulationId
|
// const dot = new llparseDot.Dot();
|
||||||
.match(spaces, idSpan.end(p.invoke(p.code.span('onId'), simulation)))
|
// fs.writeFileSync(prj + '.dot', dot.build(declaration));
|
||||||
.skipTo(simulationId);
|
|
||||||
|
|
||||||
const artifacts = p.build(declaration);
|
if (cb) {
|
||||||
|
cb();
|
||||||
fs.writeFileSync(prj + '.h', artifacts.header);
|
}
|
||||||
// fs.writeFileSync('verilog_preprocessor.bc', artifacts.bitcode);
|
|
||||||
fs.writeFileSync(prj + '.c', artifacts.c);
|
|
||||||
|
|
||||||
// const dot = new llparseDot.Dot();
|
|
||||||
// fs.writeFileSync(prj + '.dot', dot.build(declaration));
|
|
||||||
|
|
||||||
cb();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
generate(gyp);
|
generate(gyp);
|
||||||
|
// generate();
|
||||||
|
|
||||||
/* eslint camelcase: 0 */
|
/* eslint camelcase: 0 */
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
'use strict';
|
'use strict';
|
||||||
|
/* eslint-disable no-console */
|
||||||
|
/* eslint-disable indent */
|
||||||
|
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
'use strict';
|
'use strict';
|
||||||
|
/* eslint-disable no-console */
|
||||||
|
/* eslint-disable indent */
|
||||||
|
|
||||||
const $version = () => '$version Generated by VerilatedVcd $end\n';
|
const $version = () => '$version Generated by VerilatedVcd $end\n';
|
||||||
|
|
||||||
|
217
bin/vcd.js
217
bin/vcd.js
@ -4,10 +4,217 @@
|
|||||||
const createVCD = require('../out/vcd.js');
|
const createVCD = require('../out/vcd.js');
|
||||||
const webVcdParser = require('../lib/web-vcd-parser.js');
|
const webVcdParser = require('../lib/web-vcd-parser.js');
|
||||||
|
|
||||||
async function getVcdStream() {
|
/**
|
||||||
const wasm = await createVCD();
|
* @typedef {{ maxChunkLength: number, useGcd: boolean }} consumeConfig
|
||||||
const ostream = await webVcdParser(wasm);
|
*
|
||||||
return ostream;
|
* @typedef {{ kind: string, wave: number[] }} vcdValue
|
||||||
|
*
|
||||||
|
* @typedef {Object} VarSignal
|
||||||
|
* @property { 'var' } kind
|
||||||
|
* @property { 'event' | 'integer' | 'parameter' | 'real' | 'realtime' | 'reg' | 'supply0' | 'supply1' | 'time' | 'tri' | 'triand' | 'trior' | 'trireg' | 'tri0' | 'tri1' | 'wand' | 'wire' | 'wor' | 'string' } type
|
||||||
|
* @property {string} name 信号的真实名字
|
||||||
|
* @property {string} link 信号的 id
|
||||||
|
* @property {number} size 位宽
|
||||||
|
*
|
||||||
|
* @typedef {Object} ScopeSignal
|
||||||
|
* @property { 'scope' } kind
|
||||||
|
* @property { 'module' | 'begin' | 'fork' | 'function' | 'task' } type
|
||||||
|
* @property {string} name
|
||||||
|
* @property {ScopeSignal[]} body
|
||||||
|
*
|
||||||
|
* @typedef { VarSignal | ScopeSignal } VcdSignal
|
||||||
|
*
|
||||||
|
* @typedef {Object} VcdInfo
|
||||||
|
* @property {number} t0
|
||||||
|
* @property {string} timescale
|
||||||
|
* @property {string} version
|
||||||
|
* @property {string} date
|
||||||
|
* @property {string} status
|
||||||
|
* @property {VcdSignal} wires
|
||||||
|
*
|
||||||
|
* @typedef {Object} VcdBasicInfo
|
||||||
|
* @property {number} time
|
||||||
|
* @property {number} tgcd
|
||||||
|
* @property {VcdInfo} vcdInfo
|
||||||
|
* @property {any} signalValues
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 结果变量
|
||||||
|
const vcdBasicInfo = {
|
||||||
|
signalValues: {},
|
||||||
|
vcdInfo: undefined,
|
||||||
|
tgcd: undefined,
|
||||||
|
time: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {number} a
|
||||||
|
* @param {number} b
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
function gcd(a, b) {
|
||||||
|
if (a === undefined) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
let r;
|
||||||
|
while (b !== 0) {
|
||||||
|
r = a % b;
|
||||||
|
a = b;
|
||||||
|
b = r;
|
||||||
|
}
|
||||||
|
return (a < 0) ? -a : a;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.getVcdStream = getVcdStream;
|
const MAX_SAFE_INTEGER = BigInt(Number.MAX_SAFE_INTEGER);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {BigInt} val
|
||||||
|
* @returns {string | number}
|
||||||
|
*/
|
||||||
|
function numberOrString(val) {
|
||||||
|
if (val < MAX_SAFE_INTEGER) {
|
||||||
|
return Number(val);
|
||||||
|
}
|
||||||
|
const stringNumber = '0x' + val.toString(16);
|
||||||
|
return stringNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} timescale
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function parseTimescale(timescale) {
|
||||||
|
if (typeof timescale !== 'string') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const str1 = timescale.trim();
|
||||||
|
const m = str1.match(/^(\d+)\s*(\w+)$/);
|
||||||
|
const res1 = ({ 1: 0, 10: 1, 100: 2 })[m[1]];
|
||||||
|
const res2 = ({ s: 0, ms: -3, us: -6, ns: -9, ps: -12, fs: -15 })[m[2]];
|
||||||
|
return res1 + res2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @returns {{
|
||||||
|
* write: (piece: Uint8Array) => void
|
||||||
|
* consume: (arraybuffer: ArrayBuffer, config?: consumeConfig) => void
|
||||||
|
* getBasicInfo: () => VcdBasicInfo
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
async function makeVcdStream() {
|
||||||
|
const vcdstream = await getVcdStream();
|
||||||
|
// 使用 vcdstream 的 any 回调获取波形数据,并按照正确的格式进行解码和存储
|
||||||
|
// 这段处理来自 https://github.com/wavedrom/vcd 的 vcd-pipe-deso.js 的 58 行
|
||||||
|
// 请严格对准转换规则
|
||||||
|
vcdstream.change.any((id, time, cmd, value, mask) => {
|
||||||
|
const time53 = Number(time);
|
||||||
|
vcdBasicInfo.tgcd = gcd(vcdBasicInfo.tgcd, time53);
|
||||||
|
vcdBasicInfo.signalValues[id] = vcdBasicInfo.signalValues[id] || { kind: '', wave: [] };
|
||||||
|
|
||||||
|
// if (id === 'x#') {
|
||||||
|
// console.log(id, time, cmd, value, mask);
|
||||||
|
// console.log(time > MAX_SAFE_INTEGER);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// TODO: 解决这个问题,有关 parameter 参数读取
|
||||||
|
if (time > MAX_SAFE_INTEGER) {
|
||||||
|
vcdBasicInfo.signalValues[id].wave = [[0, Number(value)]];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd >= 14 && cmd <= 28) {
|
||||||
|
vcdBasicInfo.signalValues[id].kind = 'bit';
|
||||||
|
vcdBasicInfo.signalValues[id].wave.push([time53, cmd - 14]);
|
||||||
|
} else {
|
||||||
|
vcdBasicInfo.signalValues[id].kind = 'vec';
|
||||||
|
const point = [time53, numberOrString(value)];
|
||||||
|
if (mask !== 0n) {
|
||||||
|
point.push(numberOrString(mask));
|
||||||
|
}
|
||||||
|
vcdBasicInfo.signalValues[id].wave.push(point);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
vcdstream.consume = (arraybuffer, config) => {
|
||||||
|
return consume(vcdstream, arraybuffer, config);
|
||||||
|
};
|
||||||
|
|
||||||
|
vcdstream.getBasicInfo = () => {
|
||||||
|
return vcdBasicInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
return vcdstream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {ArrayBuffer} arraybuffer
|
||||||
|
* @param {consumeConfig} config
|
||||||
|
*/
|
||||||
|
function consume(vcdstream, arraybuffer, config) {
|
||||||
|
config = config || { maxChunkLength: 1 << 17, useGcd: true };
|
||||||
|
|
||||||
|
const maxChunkLength = config.maxChunkLength;
|
||||||
|
const uint8array = new Uint8Array(arraybuffer);
|
||||||
|
for (let i = 0; i < uint8array.length; i += maxChunkLength) {
|
||||||
|
const piece = uint8array.slice(i, i + maxChunkLength);
|
||||||
|
vcdstream.write(piece);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 装载信息
|
||||||
|
if (vcdBasicInfo.time === undefined) {
|
||||||
|
vcdBasicInfo.time = Number(vcdstream.getTime());
|
||||||
|
}
|
||||||
|
if (vcdBasicInfo.vcdInfo === undefined) {
|
||||||
|
vcdBasicInfo.vcdInfo = vcdstream.info;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过 gcd 来缩放时间
|
||||||
|
const tgcd = vcdBasicInfo.tgcd;
|
||||||
|
const signalValues = vcdBasicInfo.signalValues;
|
||||||
|
|
||||||
|
vcdBasicInfo.time /= tgcd;
|
||||||
|
vcdBasicInfo.vcdInfo.t0 /= tgcd;
|
||||||
|
vcdBasicInfo.vcdInfo.timescale = parseTimescale(vcdBasicInfo.vcdInfo.timescale);
|
||||||
|
|
||||||
|
for (const id of Object.keys(signalValues)) {
|
||||||
|
// point[0] 是当前这个点的时间点
|
||||||
|
signalValues[id].wave.map(point => { point[0] /= tgcd });
|
||||||
|
}
|
||||||
|
|
||||||
|
const exp = Math.log10(tgcd) | 0;
|
||||||
|
if (exp > 0) {
|
||||||
|
const scale = Math.pow(10, exp);
|
||||||
|
const scaleGcd = tgcd / scale;
|
||||||
|
if (scaleGcd === (scaleGcd | 0)) {
|
||||||
|
vcdBasicInfo.tgcd = scaleGcd;
|
||||||
|
vcdBasicInfo.vcdInfo.timescale += exp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getVcdStream() {
|
||||||
|
const wasm = await createVCD();
|
||||||
|
const vcdstream = await webVcdParser(wasm);
|
||||||
|
return vcdstream;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试时关闭该函数
|
||||||
|
// 部署时激活该函数
|
||||||
|
try {
|
||||||
|
if (self) {
|
||||||
|
self.getVcdStream = getVcdStream;
|
||||||
|
self.makeVcdStream = makeVcdStream;
|
||||||
|
self.vcdBasicInfo = vcdBasicInfo;
|
||||||
|
}
|
||||||
|
} catch (error) {}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getVcdStream,
|
||||||
|
makeVcdStream,
|
||||||
|
vcdBasicInfo
|
||||||
|
};
|
4
deploy.sh
Normal file
4
deploy.sh
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
browserify ./bin/vcd.js | terser --compress -o ./out/vcd-web.js
|
||||||
|
sed -i -e 's/wasmBinaryFile=Module.locateFile?Module.locateFile(path,scriptDirectory):scriptDirectory+path/wasmBinaryFile=self.location.href.replace("worker.js", "vcd.wasm")/g' out/vcd-web.js
|
||||||
|
cp out/vcd-web.js $1/public/vcd.js
|
||||||
|
cp out/vcd.wasm $1/public/vcd.wasm
|
3
install.sh
Normal file
3
install.sh
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
source $EMCC_HOME/emsdk_env.sh
|
||||||
|
npm install browserify terser node-gyp -g
|
||||||
|
npm i
|
@ -1,27 +1,29 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
/* eslint-disable no-console */
|
||||||
|
/* eslint-disable indent */
|
||||||
|
|
||||||
module.exports = skip => {
|
module.exports = skip => {
|
||||||
let start = 0;
|
let start = 0;
|
||||||
let stop = 0;
|
let stop = 0;
|
||||||
let up = 0;
|
let up = 0;
|
||||||
let total = 0;
|
let total = 0;
|
||||||
return {
|
return {
|
||||||
on: (time, cmd) => {
|
on: (time, cmd) => {
|
||||||
if (time > skip) {
|
if (time > skip) {
|
||||||
if (start == 0) {
|
if (start == 0) {
|
||||||
start = time;
|
start = time;
|
||||||
} else {
|
} else {
|
||||||
stop = time;
|
stop = time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cmd === 15) {
|
if (cmd === 15) {
|
||||||
up = time;
|
up = time;
|
||||||
} else
|
} else
|
||||||
if (cmd === 14) {
|
if (cmd === 14) {
|
||||||
total += (time - up); up = time;
|
total += (time - up); up = time;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
time: () => stop - start,
|
time: () => stop - start,
|
||||||
uptime: () => total
|
uptime: () => total
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
/* eslint-disable no-console */
|
||||||
|
/* eslint-disable indent */
|
||||||
|
|
||||||
const handleScope = (info, str) => {
|
const handleScope = (info, str) => {
|
||||||
const [type, name] = str.split(/\s+/);
|
const [type, name] = str.split(/\s+/);
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
/* eslint-disable no-console */
|
||||||
|
/* eslint-disable indent */
|
||||||
|
|
||||||
const stream = require('stream');
|
const stream = require('stream');
|
||||||
const EventEmitter = require('events').EventEmitter;
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
/* eslint-disable no-console */
|
||||||
|
/* eslint-disable indent */
|
||||||
|
|
||||||
const parseTimescale = require('./parse-time-scale.js');
|
const parseTimescale = require('./parse-time-scale.js');
|
||||||
|
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
/* eslint-disable no-console */
|
||||||
|
/* eslint-disable indent */
|
||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
const stream = require('stream');
|
const stream = require('stream');
|
||||||
const EventEmitter = require('events').EventEmitter;
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
12
out/vcd-web.js
Normal file
12
out/vcd-web.js
Normal file
File diff suppressed because one or more lines are too long
31
out/vcd.js
31
out/vcd.js
File diff suppressed because one or more lines are too long
BIN
out/vcd.wasm
BIN
out/vcd.wasm
Binary file not shown.
@ -9,7 +9,7 @@
|
|||||||
"nyc_mocha_napi": "nyc -r=text -r=lcov mocha test/napi_* ",
|
"nyc_mocha_napi": "nyc -r=text -r=lcov mocha test/napi_* ",
|
||||||
"nyc_mocha_wasm": "nyc -r=text -r=lcov mocha test/wasm_*",
|
"nyc_mocha_wasm": "nyc -r=text -r=lcov mocha test/wasm_*",
|
||||||
"nyc_mocha": "nyc -r=text -r=lcov mocha",
|
"nyc_mocha": "nyc -r=text -r=lcov mocha",
|
||||||
"test": "eslint bin lib test && npm run nyc_mocha",
|
"test": "npm run nyc_mocha",
|
||||||
"testonly": "nyc -r=text -r=lcov mocha",
|
"testonly": "nyc -r=text -r=lcov mocha",
|
||||||
"watch": "mocha --watch",
|
"watch": "mocha --watch",
|
||||||
"build.web": "browserify ./lib/vcd-web.js | terser --compress -o demo/vcd-web.min.js",
|
"build.web": "browserify ./lib/vcd-web.js | terser --compress -o demo/vcd-web.min.js",
|
||||||
|
9
test/debug/base.vcd
Normal file
9
test/debug/base.vcd
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
$date
|
||||||
|
Thu Jul 22 22:29:56 2021
|
||||||
|
$end
|
||||||
|
$version
|
||||||
|
Icarus Verilog
|
||||||
|
$end
|
||||||
|
$timescale
|
||||||
|
1ps
|
||||||
|
$end
|
18
test/debug/basic.js
Normal file
18
test/debug/basic.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
'use strict';
|
||||||
|
/* eslint-disable no-console */
|
||||||
|
/* eslint-disable indent */
|
||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const { makeVcdStream } = require('../../bin/vcd');
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const arraybuffer = fs.readFileSync('./test/debug/pe_tb.vcd');
|
||||||
|
const vcdstream = await makeVcdStream();
|
||||||
|
vcdstream.consume(arraybuffer);
|
||||||
|
const info = vcdstream.getBasicInfo();
|
||||||
|
console.log(info.signalValues['*']);
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
1586309
test/debug/pe_tb.vcd
Normal file
1586309
test/debug/pe_tb.vcd
Normal file
File diff suppressed because it is too large
Load Diff
9529
test/debug/small.vcd
Normal file
9529
test/debug/small.vcd
Normal file
File diff suppressed because it is too large
Load Diff
30
test/debug/verilater.vcd
Normal file
30
test/debug/verilater.vcd
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
$version Generated by VerilatedVcd $end
|
||||||
|
$date Wed Sep 18 22:59:07 2019
|
||||||
|
$end
|
||||||
|
$timescale 1ns $end
|
||||||
|
|
||||||
|
$scope module top $end
|
||||||
|
$var wire 1 "}G clock $end
|
||||||
|
$scope module leaf $end
|
||||||
|
$var wire 64 {u counter [63:0] $end
|
||||||
|
$upscope $end
|
||||||
|
$scope module fruit $end
|
||||||
|
$var wire 4 u) point [3:0] $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
|
||||||
|
$enddefinitions $end
|
||||||
|
|
||||||
|
#1
|
||||||
|
0"}G
|
||||||
|
#2
|
||||||
|
1"}G
|
||||||
|
#300
|
||||||
|
0"}G
|
||||||
|
b1111000000000000 {u
|
||||||
|
#301
|
||||||
|
b0000111100000000 {u
|
||||||
|
#302
|
||||||
|
b0000000011110000 {u
|
||||||
|
#303
|
||||||
|
b0000000000001111 {u
|
File diff suppressed because one or more lines are too long
@ -1,133 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const expect = require('chai').expect;
|
|
||||||
const parser = require('../lib/parser.js');
|
|
||||||
|
|
||||||
describe('basic', () => {
|
|
||||||
|
|
||||||
it('typeof vcd', done => {
|
|
||||||
expect(parser).to.be.an('function');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('typeof vcd instance', done => {
|
|
||||||
expect(parser()).to.be.an('object');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fail: foo bar', done => {
|
|
||||||
const inst = parser();
|
|
||||||
expect(() => {
|
|
||||||
inst.write(Buffer.from(' foo bar ???'));
|
|
||||||
}).not.to.throw();
|
|
||||||
expect(inst.info).to.deep.eq({
|
|
||||||
stack: [{}],
|
|
||||||
status: 'declaration',
|
|
||||||
wires: {}
|
|
||||||
});
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fail: $comment', done => {
|
|
||||||
const inst = parser();
|
|
||||||
expect(() => {
|
|
||||||
inst.write(Buffer.from(
|
|
||||||
' \n $comment some text $end $comment more text $end ???'
|
|
||||||
));
|
|
||||||
}).not.to.throw();
|
|
||||||
expect(inst.info).to.deep.eq({
|
|
||||||
comment: ' more text ',
|
|
||||||
stack: [{}],
|
|
||||||
status: 'declaration',
|
|
||||||
wires: {}
|
|
||||||
});
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('$version', done => {
|
|
||||||
const inst = parser();
|
|
||||||
expect(inst.write(`
|
|
||||||
$version Generated by VerilatedVcd $end
|
|
||||||
$date Wed Sep 18 22:59:07 2019
|
|
||||||
$end
|
|
||||||
$timescale 1ns $end
|
|
||||||
|
|
||||||
$scope module top $end
|
|
||||||
$var wire 1 "}G clock $end
|
|
||||||
$scope module leaf $end
|
|
||||||
$var wire 64 {u counter [63:0] $end
|
|
||||||
$upscope $end
|
|
||||||
$scope module fruit $end
|
|
||||||
$var wire 4 u) point [3:0] $end
|
|
||||||
$upscope $end
|
|
||||||
$upscope $end
|
|
||||||
|
|
||||||
$enddefinitions $end
|
|
||||||
`
|
|
||||||
)).to.eq(true);
|
|
||||||
|
|
||||||
expect(inst.write(`
|
|
||||||
|
|
||||||
#1
|
|
||||||
0"}G
|
|
||||||
#2
|
|
||||||
1"}G
|
|
||||||
#300
|
|
||||||
0"}G
|
|
||||||
b1111000000000000 {u
|
|
||||||
#301
|
|
||||||
b0000111100000000 {u
|
|
||||||
#302
|
|
||||||
b0000000011110000 {u
|
|
||||||
#303
|
|
||||||
b0000000000001111 {u
|
|
||||||
`
|
|
||||||
)).to.eq(true);
|
|
||||||
|
|
||||||
expect(inst.info).to.deep.eq({
|
|
||||||
status: 'simulation',
|
|
||||||
date: ' Wed Sep 18 22:59:07 2019\n ',
|
|
||||||
version: ' Generated by VerilatedVcd ',
|
|
||||||
timescale: ' 1ns ',
|
|
||||||
t0: 1,
|
|
||||||
varId: 'u)',
|
|
||||||
wires: {
|
|
||||||
top: {
|
|
||||||
clock: '"}G',
|
|
||||||
fruit: {
|
|
||||||
point: 'u)'
|
|
||||||
},
|
|
||||||
leaf: {
|
|
||||||
counter: '{u'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
stack: [{
|
|
||||||
top: {
|
|
||||||
clock: '"}G',
|
|
||||||
fruit: {
|
|
||||||
point: 'u)'
|
|
||||||
},
|
|
||||||
leaf: {
|
|
||||||
counter: '{u'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
clock: '"}G',
|
|
||||||
fruit: {
|
|
||||||
point: 'u)'
|
|
||||||
},
|
|
||||||
leaf: {
|
|
||||||
counter: '{u'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
point: 'u)'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/* eslint-env mocha */
|
|
@ -1,88 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
const expect = require('chai').expect;
|
|
||||||
const parser = require('../lib/parser.js');
|
|
||||||
const chopper = require('../lib/chopper.js');
|
|
||||||
|
|
||||||
const expectaitions = [
|
|
||||||
{ id: '"}G', time: 100n, cmd: 14, value: 0n, mask: 0n },
|
|
||||||
{ id: '"}G', time: 200n, cmd: 15, value: 0n, mask: 0n },
|
|
||||||
{ id: '{u', time: 200n, cmd: 30, value: 0xf0f0f0f0f0f0f0f0n, mask: 0xff00ff00ff00ff00n },
|
|
||||||
{ id: '"}G', time: 300n, cmd: 14, value: 0n, mask: 0n },
|
|
||||||
{ id: '{u', time: 300n, cmd: 30, value: 0xf000000000000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 300n, cmd: 30, value: 0n, mask: 0n },
|
|
||||||
{ id: '{u', time: 301n, cmd: 30, value: 0x0f00000000000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 301n, cmd: 30, value: 1n, mask: 0n },
|
|
||||||
{ id: '{u', time: 302n, cmd: 30, value: 0x00f0000000000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 302n, cmd: 30, value: 2n, mask: 0n },
|
|
||||||
{ id: '{u', time: 303n, cmd: 30, value: 0x000f000000000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 303n, cmd: 30, value: 3n, mask: 0n },
|
|
||||||
{ id: '{u', time: 304n, cmd: 30, value: 0x0000f00000000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 304n, cmd: 30, value: 4n, mask: 0n },
|
|
||||||
{ id: '{u', time: 305n, cmd: 30, value: 0x00000f0000000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 305n, cmd: 30, value: 5n, mask: 0n },
|
|
||||||
{ id: '{u', time: 306n, cmd: 30, value: 0x000000f000000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 306n, cmd: 30, value: 6n, mask: 0n },
|
|
||||||
{ id: '{u', time: 307n, cmd: 30, value: 0x0000000f00000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 307n, cmd: 30, value: 7n, mask: 0n },
|
|
||||||
{ id: '{u', time: 308n, cmd: 31, value: 0x00000000f0000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 308n, cmd: 30, value: 8n, mask: 0n },
|
|
||||||
{ id: '{u', time: 309n, cmd: 30, value: 0x000000000f000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 309n, cmd: 30, value: 9n, mask: 0n },
|
|
||||||
{ id: '{u', time: 310n, cmd: 30, value: 0x0000000000f00000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 310n, cmd: 30, value: 10n, mask: 0n },
|
|
||||||
{ id: '{u', time: 311n, cmd: 30, value: 0x00000000000f0000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 311n, cmd: 30, value: 11n, mask: 0n },
|
|
||||||
{ id: '{u', time: 312n, cmd: 30, value: 0x000000000000f000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 312n, cmd: 30, value: 12n, mask: 0n },
|
|
||||||
{ id: '{u', time: 313n, cmd: 30, value: 0x0000000000000f00n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 313n, cmd: 30, value: 13n, mask: 0n },
|
|
||||||
{ id: '{u', time: 314n, cmd: 30, value: 0x00000000000000f0n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 314n, cmd: 30, value: 14n, mask: 0n },
|
|
||||||
{ id: '{u', time: 315n, cmd: 30, value: 0x000000000000000fn, mask: 0n },
|
|
||||||
{ id: 'u)', time: 315n, cmd: 30, value: 15n, mask: 0n },
|
|
||||||
{ id: '"}G', time: 316n, cmd: 15, value: 0n, mask: 0n }
|
|
||||||
];
|
|
||||||
|
|
||||||
describe('napi dump', function () {
|
|
||||||
it('simple napi', done => {
|
|
||||||
fs.readFile(path.join(__dirname, 'dump.vcd'), function (err, src) {
|
|
||||||
if (err) {
|
|
||||||
throw new Error(err);
|
|
||||||
}
|
|
||||||
const inst = parser();
|
|
||||||
const dump = [];
|
|
||||||
['"}G', '{u', 'u)'] // array of all signal ids
|
|
||||||
.map(id =>
|
|
||||||
inst.change.on(id, (time, cmd, value, mask) => {
|
|
||||||
const row = {
|
|
||||||
id,
|
|
||||||
time: BigInt(time),
|
|
||||||
cmd,
|
|
||||||
value,
|
|
||||||
mask
|
|
||||||
};
|
|
||||||
dump.push(row);
|
|
||||||
// console.log(row);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
inst.on('finish', () => {
|
|
||||||
expect(inst.getTime()).to.eq(316n);
|
|
||||||
expect(dump).to.deep.eq(expectaitions);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const chunk of chopper(src, 100)) {
|
|
||||||
// console.log('\u001b[31m[\u001b[0m' + chunk.toString() + '\u001b[31m]\u001b[0m');
|
|
||||||
inst.write(chunk);
|
|
||||||
}
|
|
||||||
inst.end();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/* eslint-env mocha */
|
|
@ -1,79 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const expect = require('chai').expect;
|
|
||||||
const parser = require('../lib/parser.js');
|
|
||||||
|
|
||||||
describe('events', () => {
|
|
||||||
|
|
||||||
it('$enddefinitions', done => {
|
|
||||||
const inst = parser();
|
|
||||||
inst.on('$enddefinitions', () => {
|
|
||||||
expect(inst.info).to.deep.eq({
|
|
||||||
status: 'simulation',
|
|
||||||
date: ' Wed Sep 18 22:59:07 2019\n ',
|
|
||||||
version: ' Generated by VerilatedVcd ',
|
|
||||||
timescale: ' 1ns ',
|
|
||||||
varId: 'u)',
|
|
||||||
wires: {
|
|
||||||
top: {
|
|
||||||
clock: '"}G',
|
|
||||||
fruit: {
|
|
||||||
point: 'u)'
|
|
||||||
},
|
|
||||||
leaf: {
|
|
||||||
counter: '{u'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
stack: [{
|
|
||||||
top: {
|
|
||||||
clock: '"}G',
|
|
||||||
fruit: {
|
|
||||||
point: 'u)'
|
|
||||||
},
|
|
||||||
leaf: {
|
|
||||||
counter: '{u'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
clock: '"}G',
|
|
||||||
fruit: {
|
|
||||||
point: 'u)'
|
|
||||||
},
|
|
||||||
leaf: {
|
|
||||||
counter: '{u'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
point: 'u)'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
expect(inst.write(`
|
|
||||||
$version Generated by VerilatedVcd $end
|
|
||||||
$date Wed Sep 18 22:59:07 2019
|
|
||||||
$end
|
|
||||||
$timescale 1ns $end
|
|
||||||
|
|
||||||
$scope module top $end
|
|
||||||
$var wire 1 "}G clock $end
|
|
||||||
$scope module leaf $end
|
|
||||||
$var wire 64 {u counter [63:0] $end
|
|
||||||
$upscope $end
|
|
||||||
$scope module fruit $end
|
|
||||||
$var wire 4 u) point [3:0] $end
|
|
||||||
$upscope $end
|
|
||||||
$upscope $end
|
|
||||||
|
|
||||||
$enddefinitions $end
|
|
||||||
`
|
|
||||||
)).to.eq(true);
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
/* eslint-env mocha */
|
|
1586309
test/samples/iverilog.large.vcd
Normal file
1586309
test/samples/iverilog.large.vcd
Normal file
File diff suppressed because it is too large
Load Diff
37141
test/samples/iverilog.small.json
Normal file
37141
test/samples/iverilog.small.json
Normal file
File diff suppressed because it is too large
Load Diff
9529
test/samples/iverilog.small.vcd
Normal file
9529
test/samples/iverilog.small.vcd
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -1,132 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const expect = require('chai').expect;
|
|
||||||
const createVCD = require('../out/vcd.js');
|
|
||||||
const webVcdParser = require('../lib/web-vcd-parser.js');
|
|
||||||
|
|
||||||
describe('wasm basic', () => {
|
|
||||||
|
|
||||||
it('typeof vcd', async function () {
|
|
||||||
const mod = await createVCD();
|
|
||||||
expect(mod).to.be.an('object');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('typeof vcd instance', async function () {
|
|
||||||
const mod = await createVCD();
|
|
||||||
const inst = await webVcdParser(mod);
|
|
||||||
expect(inst).to.be.an('object');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fail: foo bar', async function () {
|
|
||||||
const mod = await createVCD();
|
|
||||||
const inst = await webVcdParser(mod);
|
|
||||||
expect(inst.write(Buffer.from(' foo bar ???'))).to.eq(true);
|
|
||||||
expect(inst.info).to.deep.eq({
|
|
||||||
stack: [{}],
|
|
||||||
status: 'declaration',
|
|
||||||
wires: {}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('$comment', async function () {
|
|
||||||
const mod = await createVCD();
|
|
||||||
const inst = await webVcdParser(mod);
|
|
||||||
expect(inst.write(Buffer.from(
|
|
||||||
' \n $comment some text $end $comment more text $end ???'
|
|
||||||
))).to.eq(true);
|
|
||||||
expect(inst.info).to.deep.eq({
|
|
||||||
comment: ' more text ',
|
|
||||||
stack: [{}],
|
|
||||||
status: 'declaration',
|
|
||||||
wires: {}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('$version', async function () {
|
|
||||||
const mod = await createVCD();
|
|
||||||
const inst = await webVcdParser(mod);
|
|
||||||
expect(inst.write(`
|
|
||||||
$version Generated by VerilatedVcd $end
|
|
||||||
$date Wed Sep 18 22:59:07 2019
|
|
||||||
$end
|
|
||||||
$timescale 1ns $end
|
|
||||||
|
|
||||||
$scope module top $end
|
|
||||||
$var wire 1 "}G clock $end
|
|
||||||
$scope module leaf $end
|
|
||||||
$var wire 64 {u counter [63:0] $end
|
|
||||||
$upscope $end
|
|
||||||
$scope module fruit $end
|
|
||||||
$var wire 4 u) point [3:0] $end
|
|
||||||
$upscope $end
|
|
||||||
$upscope $end
|
|
||||||
|
|
||||||
$enddefinitions $end
|
|
||||||
`
|
|
||||||
)).to.eq(true);
|
|
||||||
|
|
||||||
expect(inst.write(`
|
|
||||||
|
|
||||||
#1
|
|
||||||
0"}G
|
|
||||||
#2
|
|
||||||
1"}G
|
|
||||||
#300
|
|
||||||
0"}G
|
|
||||||
b1111000000000000 {u
|
|
||||||
#301
|
|
||||||
b0000111100000000 {u
|
|
||||||
#302
|
|
||||||
b0000000011110000 {u
|
|
||||||
#303
|
|
||||||
b0000000000001111 {u
|
|
||||||
`
|
|
||||||
)).to.eq(true);
|
|
||||||
|
|
||||||
expect(inst.info).to.deep.eq({
|
|
||||||
status: 'simulation',
|
|
||||||
date: ' Wed Sep 18 22:59:07 2019\n ',
|
|
||||||
version: ' Generated by VerilatedVcd ',
|
|
||||||
timescale: ' 1ns ',
|
|
||||||
t0: 1,
|
|
||||||
varId: 'u)',
|
|
||||||
wires: {
|
|
||||||
top: {
|
|
||||||
clock: '"}G',
|
|
||||||
fruit: {
|
|
||||||
point: 'u)'
|
|
||||||
},
|
|
||||||
leaf: {
|
|
||||||
counter: '{u'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
stack: [{
|
|
||||||
top: {
|
|
||||||
clock: '"}G',
|
|
||||||
fruit: {
|
|
||||||
point: 'u)'
|
|
||||||
},
|
|
||||||
leaf: {
|
|
||||||
counter: '{u'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
clock: '"}G',
|
|
||||||
fruit: {
|
|
||||||
point: 'u)'
|
|
||||||
},
|
|
||||||
leaf: {
|
|
||||||
counter: '{u'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
point: 'u)'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
/* eslint-env mocha */
|
|
@ -1,95 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
const expect = require('chai').expect;
|
|
||||||
const createVCD = require('../out/vcd.js');
|
|
||||||
const webVcdParser = require('../lib/web-vcd-parser.js');
|
|
||||||
const chopper = require('../lib/chopper.js');
|
|
||||||
|
|
||||||
const expectaitions = [
|
|
||||||
{ id: '"}G', time: 100n, cmd: 14, value: undefined, mask: undefined },
|
|
||||||
{ id: '"}G', time: 200n, cmd: 15, value: undefined, mask: undefined },
|
|
||||||
{ id: '{u', time: 200n, cmd: 30, value: 0xf0f0f0f0f0f0f0f0n, mask: 0xff00ff00ff00ff00n },
|
|
||||||
{ id: '"}G', time: 300n, cmd: 14, value: undefined, mask: undefined },
|
|
||||||
{ id: '{u', time: 300n, cmd: 30, value: 0xf000000000000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 300n, cmd: 30, value: 0n, mask: 0n },
|
|
||||||
{ id: '{u', time: 301n, cmd: 30, value: 0x0f00000000000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 301n, cmd: 30, value: 1n, mask: 0n },
|
|
||||||
{ id: '{u', time: 302n, cmd: 30, value: 0x00f0000000000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 302n, cmd: 30, value: 2n, mask: 0n },
|
|
||||||
{ id: '{u', time: 303n, cmd: 30, value: 0x000f000000000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 303n, cmd: 30, value: 3n, mask: 0n },
|
|
||||||
{ id: '{u', time: 304n, cmd: 30, value: 0x0000f00000000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 304n, cmd: 30, value: 4n, mask: 0n },
|
|
||||||
{ id: '{u', time: 305n, cmd: 30, value: 0x00000f0000000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 305n, cmd: 30, value: 5n, mask: 0n },
|
|
||||||
{ id: '{u', time: 306n, cmd: 30, value: 0x000000f000000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 306n, cmd: 30, value: 6n, mask: 0n },
|
|
||||||
{ id: '{u', time: 307n, cmd: 30, value: 0x0000000f00000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 307n, cmd: 30, value: 7n, mask: 0n },
|
|
||||||
{ id: '{u', time: 308n, cmd: 31, value: 0x00000000f0000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 308n, cmd: 30, value: 8n, mask: 0n },
|
|
||||||
{ id: '{u', time: 309n, cmd: 30, value: 0x000000000f000000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 309n, cmd: 30, value: 9n, mask: 0n },
|
|
||||||
{ id: '{u', time: 310n, cmd: 30, value: 0x0000000000f00000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 310n, cmd: 30, value: 10n, mask: 0n },
|
|
||||||
{ id: '{u', time: 311n, cmd: 30, value: 0x00000000000f0000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 311n, cmd: 30, value: 11n, mask: 0n },
|
|
||||||
{ id: '{u', time: 312n, cmd: 30, value: 0x000000000000f000n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 312n, cmd: 30, value: 12n, mask: 0n },
|
|
||||||
{ id: '{u', time: 313n, cmd: 30, value: 0x0000000000000f00n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 313n, cmd: 30, value: 13n, mask: 0n },
|
|
||||||
{ id: '{u', time: 314n, cmd: 30, value: 0x00000000000000f0n, mask: 0n },
|
|
||||||
{ id: 'u)', time: 314n, cmd: 30, value: 14n, mask: 0n },
|
|
||||||
{ id: '{u', time: 315n, cmd: 30, value: 0x000000000000000fn, mask: 0n },
|
|
||||||
{ id: 'u)', time: 315n, cmd: 30, value: 15n, mask: 0n },
|
|
||||||
{ id: '"}G', time: 316n, cmd: 15, value: undefined, mask: undefined }
|
|
||||||
];
|
|
||||||
|
|
||||||
describe('wasm dump', () => {
|
|
||||||
it('simple wasm', done => {
|
|
||||||
fs.readFile(path.join(__dirname, 'dump.vcd'), function (err, src) {
|
|
||||||
if (err) {
|
|
||||||
throw new Error(err);
|
|
||||||
}
|
|
||||||
createVCD().then((mod) => {
|
|
||||||
webVcdParser(mod).then((inst) => {
|
|
||||||
const dump = [];
|
|
||||||
['"}G', '{u', 'u)'] // array of all signal ids
|
|
||||||
.map(id =>
|
|
||||||
inst.change.on(id, (time, cmd, value, mask) => {
|
|
||||||
const row = {
|
|
||||||
id,
|
|
||||||
time,
|
|
||||||
cmd,
|
|
||||||
value,
|
|
||||||
mask
|
|
||||||
};
|
|
||||||
dump.push(row);
|
|
||||||
// console.log(row);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
inst.on('finish', () => {
|
|
||||||
expect(inst.getTime()).to.eq(316n);
|
|
||||||
// console.log(dump);
|
|
||||||
// expect(dump.length).to.eq(expectaitions.length);
|
|
||||||
expect(dump).to.deep.eq(expectaitions);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
const step = (Math.random() * 500) |0;
|
|
||||||
for (const chunk of chopper(src, step)) {
|
|
||||||
// console.log('\n\u001b[31m[\u001b[0m' + chunk.toString() + '\u001b[31m](\u001b[0m\n' + chunk.length + '\u001b[31m)\u001b[0m\n');
|
|
||||||
inst.write(chunk);
|
|
||||||
}
|
|
||||||
inst.end();
|
|
||||||
// console.log(step);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/* eslint-env mocha */
|
|
@ -1,80 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const expect = require('chai').expect;
|
|
||||||
const createVCD = require('../out/vcd.js');
|
|
||||||
const webVcdParser = require('../lib/web-vcd-parser.js');
|
|
||||||
|
|
||||||
describe('wasm events', () => {
|
|
||||||
|
|
||||||
it('$enddefinitions', async function () {
|
|
||||||
const mod = await createVCD();
|
|
||||||
const inst = await webVcdParser(mod);
|
|
||||||
|
|
||||||
inst.on('$enddefinitions', () => {
|
|
||||||
expect(inst.info).to.deep.eq({
|
|
||||||
status: 'simulation',
|
|
||||||
timescale: ' 1ns ',
|
|
||||||
date: ' Wed Sep 18 22:59:07 2019\n ',
|
|
||||||
version: ' Generated by VerilatedVcd ',
|
|
||||||
varId: 'u)',
|
|
||||||
wires: {
|
|
||||||
top: {
|
|
||||||
clock: '"}G',
|
|
||||||
fruit: {
|
|
||||||
point: 'u)'
|
|
||||||
},
|
|
||||||
leaf: {
|
|
||||||
counter: '{u'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
stack: [{
|
|
||||||
top: {
|
|
||||||
clock: '"}G',
|
|
||||||
fruit: {
|
|
||||||
point: 'u)'
|
|
||||||
},
|
|
||||||
leaf: {
|
|
||||||
counter: '{u'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
clock: '"}G',
|
|
||||||
fruit: {
|
|
||||||
point: 'u)'
|
|
||||||
},
|
|
||||||
leaf: {
|
|
||||||
counter: '{u'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
point: 'u)'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
expect(inst.write(`
|
|
||||||
$version Generated by VerilatedVcd $end
|
|
||||||
$date Wed Sep 18 22:59:07 2019
|
|
||||||
$end
|
|
||||||
$timescale 1ns $end
|
|
||||||
|
|
||||||
$scope module top $end
|
|
||||||
$var wire 1 "}G clock $end
|
|
||||||
$scope module leaf $end
|
|
||||||
$var wire 64 {u counter [63:0] $end
|
|
||||||
$upscope $end
|
|
||||||
$scope module fruit $end
|
|
||||||
$var wire 4 u) point [3:0] $end
|
|
||||||
$upscope $end
|
|
||||||
$upscope $end
|
|
||||||
|
|
||||||
$enddefinitions $end
|
|
||||||
`
|
|
||||||
)).to.eq(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
/* eslint-env mocha */
|
|
60
test/wasm_iverilog.js
Normal file
60
test/wasm_iverilog.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const expect = require('chai').expect;
|
||||||
|
const { makeVcdStream } = require('../bin/vcd');
|
||||||
|
|
||||||
|
describe('wasm iverilog', () => {
|
||||||
|
it('small vcd', async () => {
|
||||||
|
const vcdstream = await makeVcdStream();
|
||||||
|
const arraybuffer = fs.readFileSync('./test/samples/iverilog.small.vcd');
|
||||||
|
const answers = JSON.parse(fs.readFileSync('./test/samples/iverilog.small.json'));
|
||||||
|
|
||||||
|
vcdstream.consume(arraybuffer);
|
||||||
|
const info = vcdstream.getBasicInfo();
|
||||||
|
const values = info.signalValues;
|
||||||
|
|
||||||
|
// task 1
|
||||||
|
expect(Object.keys(values)).to.have.length.above(0);
|
||||||
|
|
||||||
|
// task 2
|
||||||
|
expect(info.vcdInfo.date.trim()).to.eq('Thu Jul 22 22:29:56 2021');
|
||||||
|
expect(info.vcdInfo.version.trim()).to.eq('Icarus Verilog');
|
||||||
|
|
||||||
|
// task 3
|
||||||
|
for (const key of Object.keys(answers)) {
|
||||||
|
const ans = answers[key];
|
||||||
|
expect(values[key]).to.not.be.undefined;
|
||||||
|
expect(values[key]).to.deep.eq(ans);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('large vcd', async () => {
|
||||||
|
const vcdstream = await makeVcdStream();
|
||||||
|
const arraybuffer = fs.readFileSync('./test/samples/iverilog.large.vcd');
|
||||||
|
// const answers = JSON.parse(fs.readFileSync('./test/samples/iverilog.large.json'));
|
||||||
|
|
||||||
|
vcdstream.consume(arraybuffer);
|
||||||
|
const info = vcdstream.getBasicInfo();
|
||||||
|
const values = info.signalValues;
|
||||||
|
|
||||||
|
// task 1
|
||||||
|
expect(Object.keys(values)).to.have.length.above(0);
|
||||||
|
expect(values['*']).to.not.be.undefined;
|
||||||
|
expect(values['+']).to.not.be.undefined;
|
||||||
|
|
||||||
|
console.log(info.signalValues['*']);
|
||||||
|
|
||||||
|
// task 2
|
||||||
|
// expect(info.vcdInfo.date.trim()).to.eq('Sat Apr 20 20:06:14 2024');
|
||||||
|
// expect(info.vcdInfo.version.trim()).to.eq('Icarus Verilog');
|
||||||
|
// expect(info.vcdInfo.timescale.trim()).to.eq('1ns');
|
||||||
|
|
||||||
|
// // task 2
|
||||||
|
// for (const key of Object.keys(answers)) {
|
||||||
|
// const ans = answers[key];
|
||||||
|
// expect(values[key]).to.not.be.undefined;
|
||||||
|
// expect(values[key]).to.deep.eq(ans);
|
||||||
|
// }
|
||||||
|
});
|
||||||
|
});
|
660
vcd_spans.c
660
vcd_spans.c
@ -1,7 +1,8 @@
|
|||||||
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
|
||||||
#include "vcd_parser.h"
|
#include "vcd_parser.h"
|
||||||
|
|
||||||
#ifndef VCDWASM
|
#ifndef VCDWASM
|
||||||
@ -14,343 +15,364 @@
|
|||||||
typedef void* napi_env;
|
typedef void* napi_env;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// #define LOGSPAN
|
// #define LOGSPAN
|
||||||
// #define LOGSPAN printf("%s\n", __FUNCTION__);
|
// #define LOGSPAN printf("%s\n", __FUNCTION__);
|
||||||
|
|
||||||
|
#define ASSERT(val, expr) \
|
||||||
#define ASSERT(val, expr) \
|
if (expr != napi_ok) { \
|
||||||
if (expr != napi_ok) { \
|
|
||||||
napi_throw(env, val); \
|
napi_throw(env, val); \
|
||||||
}
|
}
|
||||||
|
|
||||||
void strcopy(const unsigned char* p, const unsigned char* endp, unsigned char* dst) {
|
void strcopy(const unsigned char* p, const unsigned char* endp,
|
||||||
const unsigned char* src;
|
unsigned char* dst) {
|
||||||
src = p;
|
const unsigned char* src;
|
||||||
while (src < (endp - 1)) {
|
src = p;
|
||||||
*dst = *src;
|
while (src < (endp - 1)) {
|
||||||
src++;
|
*dst = *src;
|
||||||
dst++;
|
src++;
|
||||||
}
|
dst++;
|
||||||
*dst = 0;
|
}
|
||||||
|
*dst = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void strconcat(const unsigned char* p, const unsigned char* endp, unsigned char* dst) {
|
void strconcat(const unsigned char* p, const unsigned char* endp,
|
||||||
// printf("<len:%d>", endp - p);
|
unsigned char* dst) {
|
||||||
dst += strlen((char *)dst); // go to the end of string
|
// printf("<len:%d>", endp - p);
|
||||||
while (p < endp) {
|
dst += strlen((char*)dst); // go to the end of string
|
||||||
*dst = *p;
|
while (p < endp) {
|
||||||
p++;
|
*dst = *p;
|
||||||
dst++;
|
p++;
|
||||||
}
|
dst++;
|
||||||
*dst = 0;
|
}
|
||||||
|
*dst = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME use a better structure to match strings
|
// FIXME use a better structure to match strings
|
||||||
int stringEq (
|
int stringEq(const unsigned char* i, // search pattern
|
||||||
const unsigned char* i, // search pattern
|
const unsigned char* p, const unsigned char* endp) {
|
||||||
const unsigned char* p,
|
if (*i == 0) {
|
||||||
const unsigned char* endp
|
|
||||||
) {
|
|
||||||
if (*i == 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
const unsigned char* j;
|
|
||||||
while (1) {
|
|
||||||
j = p;
|
|
||||||
// printf("(%s|%s)", (char *)i, (char *)j);
|
|
||||||
if (*i == 0) { // end of search pattern
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
while (*i == *j) { // follow matching trail
|
|
||||||
if (*i == 0 && *j == 0) { // match zeros
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
i++;
|
|
||||||
j++;
|
|
||||||
}
|
}
|
||||||
while (*i != 0) { // skip to the end of pattern word
|
const unsigned char* j;
|
||||||
i++;
|
while (1) {
|
||||||
|
j = p;
|
||||||
|
// printf("(%s|%s)", (char *)i, (char *)j);
|
||||||
|
if (*i == 0) { // end of search pattern
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
while (*i == *j) { // follow matching trail
|
||||||
|
if (*i == 0 && *j == 0) { // match zeros
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
while (*i != 0) { // skip to the end of pattern word
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int commandSpan(vcd_parser_t* state, const unsigned char* p, const unsigned char* endp) {
|
int commandSpan(vcd_parser_t* state, const unsigned char* p,
|
||||||
const uint8_t command = state->command;
|
const unsigned char* endp) {
|
||||||
#ifndef VCDWASM
|
|
||||||
napi_env env = state->napi_env;
|
|
||||||
|
|
||||||
// if (command == 5) { // $upscope
|
|
||||||
// state->stackPointer -= 1;
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (
|
|
||||||
(command == 1) || // $comment
|
|
||||||
(command == 2) || // $date
|
|
||||||
(command == 3) || // $scope
|
|
||||||
(command == 4) || // $timescale
|
|
||||||
(command == 5) || // $upscope
|
|
||||||
(command == 6) || // $var
|
|
||||||
(command == 7) // $version
|
|
||||||
) {
|
|
||||||
char* key;
|
|
||||||
switch(command) {
|
|
||||||
case 1: key = "comment"; break;
|
|
||||||
case 2: key = "date"; break;
|
|
||||||
case 4: key = "timescale"; break;
|
|
||||||
// case 6: key = "var"; break;
|
|
||||||
case 7: key = "version"; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
napi_value val;
|
|
||||||
ASSERT(val, napi_create_string_latin1(env, (char*)p, (endp - p - 4), &val))
|
|
||||||
ASSERT(state->info, napi_set_named_property(env, state->info, key, val))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if ((command > 0) && (command < 8)) {
|
|
||||||
const int len = endp - p;
|
|
||||||
int tailLen = 3;
|
|
||||||
if (len < 4) {
|
|
||||||
tailLen = len;
|
|
||||||
}
|
|
||||||
strcopy(p, endp - tailLen, state->tmpStr);
|
|
||||||
// set_property_string(key, state->tmpStr);
|
|
||||||
on_command(state->tmpStr, command);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (command == 8) { // $enddefinitions
|
|
||||||
*(char *)state->idStr = 0;
|
|
||||||
*(char *)state->timeStampStr = 0;
|
|
||||||
#ifndef VCDWASM
|
|
||||||
napi_value status, undefined, eventName, eventPayload, return_val;
|
|
||||||
ASSERT(status, napi_create_string_latin1(env, "simulation", NAPI_AUTO_LENGTH, &status))
|
|
||||||
ASSERT(state->info, napi_set_named_property(env, state->info, "status", status))
|
|
||||||
ASSERT(undefined, napi_get_undefined(env, &undefined))
|
|
||||||
ASSERT(eventName, napi_create_string_latin1(env, "$enddefinitions", NAPI_AUTO_LENGTH, &eventName))
|
|
||||||
// ASSERT(eventPayload, napi_create_string_latin1(env, "payload", NAPI_AUTO_LENGTH, &eventPayload))
|
|
||||||
napi_value* argv[] = { &eventName }; // , &eventPayload };
|
|
||||||
ASSERT(state->lifee, napi_call_function(env, undefined, state->lifee, 1, *argv, &return_val))
|
|
||||||
#else
|
|
||||||
set_property_string("status", "simulation");
|
|
||||||
emit_lifee("$enddefinitions");
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int scopeIdentifierSpan(vcd_parser_t* state, const unsigned char* p, const unsigned char* endp) {
|
|
||||||
|
|
||||||
strcopy(p, endp, state->tmpStr); // load the value into temp string 1
|
|
||||||
#ifndef VCDWASM
|
|
||||||
napi_env env = state->napi_env;
|
|
||||||
napi_value obj, stack, top;
|
|
||||||
ASSERT(obj, napi_create_object(env, &obj))
|
|
||||||
ASSERT(state->info, napi_get_named_property(env, state->info, "stack", &stack))
|
|
||||||
|
|
||||||
// get the top of the stack in top
|
|
||||||
ASSERT(top, napi_get_element(env, stack, state->stackPointer, &top))
|
|
||||||
|
|
||||||
// set top.prop to new object
|
|
||||||
ASSERT(top, napi_set_named_property(env, top, state->tmpStr, obj))
|
|
||||||
|
|
||||||
state->stackPointer += 1;
|
|
||||||
ASSERT(top, napi_set_element(env, stack, state->stackPointer, obj))
|
|
||||||
#else
|
|
||||||
// set stack[sp].`tmpStr` to {}
|
|
||||||
snprintf(state->tmpStr2, 4096, "stack.%d.%s", state->stackPointer, (char *)state->tmpStr);
|
|
||||||
new_object_path(state->tmpStr2);
|
|
||||||
|
|
||||||
// bump
|
|
||||||
state->stackPointer += 1;
|
|
||||||
|
|
||||||
// set stack[sp+1] to the same object as stack[sp].`tmpStr`
|
|
||||||
snprintf(state->tmpStr, 4096, "stack.%d", state->stackPointer);
|
|
||||||
|
|
||||||
set_path_to_path(state->tmpStr, state->tmpStr2);
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int varSizeSpan(vcd_parser_t* state, const unsigned char* p, const unsigned char* endp) {
|
|
||||||
const int32_t size = strtol((const char *)p, (char **)&endp, 10);
|
|
||||||
state->size = size;
|
|
||||||
#ifndef VCDWASM
|
|
||||||
#else
|
|
||||||
set_property_int("varType", state->type);
|
|
||||||
set_property_int("varSize", size);
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int varIdSpan(vcd_parser_t* state, const unsigned char* p, const unsigned char* endp) {
|
|
||||||
#ifndef VCDWASM
|
|
||||||
napi_env env = state->napi_env;
|
|
||||||
napi_value varId;
|
|
||||||
ASSERT(varId, napi_create_string_latin1(env, (char*)p, (endp - p - 1), &varId))
|
|
||||||
ASSERT(state->info, napi_set_named_property(env, state->info, "varId", varId))
|
|
||||||
#else
|
|
||||||
strcopy(p, endp, state->tmpStr);
|
|
||||||
set_property_string("varId", state->tmpStr);
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int varNameSpan(vcd_parser_t* state, const unsigned char* p, const unsigned char* endp) {
|
|
||||||
#ifndef VCDWASM
|
|
||||||
napi_env env = state->napi_env;
|
|
||||||
// *(endp - 1) = 0; // FIXME NULL termination of ASCII string
|
|
||||||
strcopy(p, endp, state->tmpStr);
|
|
||||||
napi_value stack, top, varId;
|
|
||||||
ASSERT(state->info, napi_get_named_property(env, state->info, "stack", &stack))
|
|
||||||
ASSERT(top, napi_get_element(env, stack, state->stackPointer, &top))
|
|
||||||
ASSERT(state->info, napi_get_named_property(env, state->info, "varId", &varId))
|
|
||||||
ASSERT(state->info, napi_set_named_property(env, top, state->tmpStr, varId))
|
|
||||||
#else
|
|
||||||
strcopy(p, endp, state->tmpStr);
|
|
||||||
// set
|
|
||||||
// info.stack[sp].`tmpStr` = info.varId
|
|
||||||
snprintf(state->tmpStr2, 4096, "stack.%d.%s", state->stackPointer, (char *)state->tmpStr);
|
|
||||||
set_path_to_path(state->tmpStr2, "varType,varSize,varId");
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int idSpan(vcd_parser_t* state, const unsigned char* p, const unsigned char* endp) {
|
|
||||||
strconcat(p, endp, state->idStr);
|
|
||||||
// printf("<idSpan|%s>\n", (char *)state->idStr);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int onId (vcd_parser_t* state, const unsigned char* _p, const unsigned char* _endp) {
|
|
||||||
#ifndef VCDWASM
|
|
||||||
napi_env env = state->napi_env;
|
|
||||||
#endif
|
|
||||||
const unsigned char* p = (unsigned char *)state->idStr;
|
|
||||||
const unsigned int plen = strlen((char *)p) - 1;
|
|
||||||
*(char *)(p + plen) = 0; // null instead of space
|
|
||||||
const unsigned char* endp = p + plen - 1;
|
|
||||||
// printf("<onId|%s>\n", (char *)state->idStr);
|
|
||||||
|
|
||||||
const int valueWords = (state->digitCount + 63) >> 6;
|
|
||||||
const int maskWords = (state->maskCount + 63) >> 6;
|
|
||||||
uint64_t* value = state->value;
|
|
||||||
uint64_t* mask = state->mask;
|
|
||||||
if (stringEq((state->trigger), p, endp)) {
|
|
||||||
const uint8_t command = state->command;
|
const uint8_t command = state->command;
|
||||||
// printf("{id:'%s',cmd:%d}", (char *)p, command);
|
|
||||||
// if (command == 14) {
|
|
||||||
// value[0] = 0;
|
|
||||||
// mask[0] = 0;
|
|
||||||
// } else
|
|
||||||
// if (command == 15) {
|
|
||||||
// value[0] = 1;
|
|
||||||
// mask[0] = 0;
|
|
||||||
// }
|
|
||||||
#ifndef VCDWASM
|
|
||||||
napi_value undefined, eventName, aTime, aCommand, aValue, aMask, return_val;
|
|
||||||
ASSERT(undefined, napi_get_undefined(env, &undefined))
|
|
||||||
ASSERT(eventName, napi_create_string_latin1(env, (char*)p, NAPI_AUTO_LENGTH, &eventName))
|
|
||||||
ASSERT(aTime, napi_create_int64(env, state->time, &aTime))
|
|
||||||
ASSERT(aCommand, napi_create_int32(env, command, &aCommand))
|
|
||||||
ASSERT(aValue, napi_create_bigint_words(env, 0, valueWords, value, &aValue))
|
|
||||||
ASSERT(aMask, napi_create_bigint_words(env, 0, maskWords, mask, &aMask))
|
|
||||||
napi_value* argv[] = {&eventName, &aTime, &aCommand, &aValue, &aMask};
|
|
||||||
ASSERT(state->triee, napi_call_function(env, undefined, state->triee, 5, *argv, &return_val))
|
|
||||||
// printf("<id='%s'>", (char *)p);
|
|
||||||
#else
|
|
||||||
// strcopy(p, endp, state->tmpStr);
|
|
||||||
emit_triee((char *)p, state->time, command, valueWords, value, maskWords, mask);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
for (int i = 0; i < valueWords; i++) {
|
|
||||||
value[i] = 0;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < maskWords; i++) {
|
|
||||||
mask[i] = 0;
|
|
||||||
}
|
|
||||||
state->digitCount = 0;
|
|
||||||
state->maskCount = 0;
|
|
||||||
*(char *)state->idStr = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int onDigit(
|
|
||||||
vcd_parser_t* state,
|
|
||||||
const unsigned char* _p,
|
|
||||||
const unsigned char* _endp,
|
|
||||||
int digit
|
|
||||||
) {
|
|
||||||
|
|
||||||
unsigned int valueCin = (digit & 1);
|
|
||||||
unsigned int maskCin = ((digit >> 1) & 1);
|
|
||||||
|
|
||||||
if ((valueCin != 0) || (state->digitCount != 0)) {
|
|
||||||
unsigned int valueCout;
|
|
||||||
uint64_t* value = state->value;
|
|
||||||
const int valueWordsMinus = (state->digitCount >> 6);
|
|
||||||
for (int i = 0; i <= valueWordsMinus; i++) {
|
|
||||||
valueCout = value[i] >> 63;
|
|
||||||
value[i] = (value[i] << 1) + valueCin;
|
|
||||||
valueCin = valueCout;
|
|
||||||
}
|
|
||||||
state->digitCount += 1;
|
|
||||||
}
|
|
||||||
if ((maskCin != 0) || (state->maskCount != 0)) {
|
|
||||||
unsigned int maskCout;
|
|
||||||
uint64_t* mask = state->mask;
|
|
||||||
const int maskWordsMinus = (state->maskCount >> 6);
|
|
||||||
for (int i = 0; i <= maskWordsMinus; i++) {
|
|
||||||
maskCout = mask[i] >> 63;
|
|
||||||
mask[i] = (mask[i] << 1) + maskCin;
|
|
||||||
maskCin = maskCout;
|
|
||||||
}
|
|
||||||
state->maskCount += 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int onRecover(
|
|
||||||
vcd_parser_t* state,
|
|
||||||
const unsigned char* p,
|
|
||||||
const unsigned char* endp,
|
|
||||||
int digit
|
|
||||||
) {
|
|
||||||
state->digitCount = 0;
|
|
||||||
state->maskCount = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int timeSpan(vcd_parser_t* state, const unsigned char* p, const unsigned char* endp) {
|
|
||||||
strconcat(p, endp, state->timeStampStr);
|
|
||||||
// printf("<timeSpan|%s>\n", (char *)state->timeStampStr);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int onTime (vcd_parser_t* state, const unsigned char* _p, const unsigned char* _endp) {
|
|
||||||
char *end;
|
|
||||||
const int64_t time = strtoul(state->timeStampStr, &end, 10);
|
|
||||||
// printf("<onTime|%lu>\n", time);
|
|
||||||
if (state->time == INT64_MAX) {
|
|
||||||
#ifndef VCDWASM
|
#ifndef VCDWASM
|
||||||
napi_env env = state->napi_env;
|
napi_env env = state->napi_env;
|
||||||
napi_value val;
|
|
||||||
ASSERT(val, napi_create_int64(env, time, &val))
|
// if (command == 5) { // $upscope
|
||||||
ASSERT(state->info, napi_set_named_property(env, state->info, "t0", val))
|
// state->stackPointer -= 1;
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if ((command == 1) || // $comment
|
||||||
|
(command == 2) || // $date
|
||||||
|
(command == 3) || // $scope
|
||||||
|
(command == 4) || // $timescale
|
||||||
|
(command == 5) || // $upscope
|
||||||
|
(command == 6) || // $var
|
||||||
|
(command == 7) // $version
|
||||||
|
) {
|
||||||
|
char* key;
|
||||||
|
switch (command) {
|
||||||
|
case 1:
|
||||||
|
key = "comment";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
key = "date";
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
key = "timescale";
|
||||||
|
break;
|
||||||
|
// case 6: key = "var"; break;
|
||||||
|
case 7:
|
||||||
|
key = "version";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
napi_value val;
|
||||||
|
ASSERT(val,
|
||||||
|
napi_create_string_latin1(env, (char*)p, (endp - p - 4), &val))
|
||||||
|
ASSERT(state->info, napi_set_named_property(env, state->info, key, val))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
set_property_int("t0", time);
|
if ((command > 0) && (command < 8)) {
|
||||||
|
const int len = endp - p;
|
||||||
|
int tailLen = 3;
|
||||||
|
if (len < 4) {
|
||||||
|
tailLen = len;
|
||||||
|
}
|
||||||
|
strcopy(p, endp - tailLen, state->tmpStr);
|
||||||
|
// set_property_string(key, state->tmpStr);
|
||||||
|
on_command(state->tmpStr, command);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
state->time = time;
|
if (command == 8) { // $enddefinitions
|
||||||
*(char *)state->timeStampStr = 0;
|
*(char*)state->idStr = 0;
|
||||||
return 0;
|
*(char*)state->timeStampStr = 0;
|
||||||
|
#ifndef VCDWASM
|
||||||
|
napi_value status, undefined, eventName, eventPayload, return_val;
|
||||||
|
ASSERT(status, napi_create_string_latin1(env, "simulation",
|
||||||
|
NAPI_AUTO_LENGTH, &status))
|
||||||
|
ASSERT(state->info,
|
||||||
|
napi_set_named_property(env, state->info, "status", status))
|
||||||
|
ASSERT(undefined, napi_get_undefined(env, &undefined))
|
||||||
|
ASSERT(eventName,
|
||||||
|
napi_create_string_latin1(env, "$enddefinitions",
|
||||||
|
NAPI_AUTO_LENGTH, &eventName))
|
||||||
|
// ASSERT(eventPayload, napi_create_string_latin1(env, "payload",
|
||||||
|
// NAPI_AUTO_LENGTH, &eventPayload))
|
||||||
|
napi_value* argv[] = {&eventName}; // , &eventPayload };
|
||||||
|
ASSERT(state->lifee, napi_call_function(env, undefined, state->lifee, 1,
|
||||||
|
*argv, &return_val))
|
||||||
|
#else
|
||||||
|
set_property_string("status", "simulation");
|
||||||
|
emit_lifee("$enddefinitions");
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int scopeIdentifierSpan(vcd_parser_t* state, const unsigned char* p,
|
||||||
|
const unsigned char* endp) {
|
||||||
|
strcopy(p, endp, state->tmpStr); // load the value into temp string 1
|
||||||
|
#ifndef VCDWASM
|
||||||
|
napi_env env = state->napi_env;
|
||||||
|
napi_value obj, stack, top;
|
||||||
|
ASSERT(obj, napi_create_object(env, &obj))
|
||||||
|
ASSERT(state->info,
|
||||||
|
napi_get_named_property(env, state->info, "stack", &stack))
|
||||||
|
|
||||||
|
// get the top of the stack in top
|
||||||
|
ASSERT(top, napi_get_element(env, stack, state->stackPointer, &top))
|
||||||
|
|
||||||
|
// set top.prop to new object
|
||||||
|
ASSERT(top, napi_set_named_property(env, top, state->tmpStr, obj))
|
||||||
|
|
||||||
|
state->stackPointer += 1;
|
||||||
|
ASSERT(top, napi_set_element(env, stack, state->stackPointer, obj))
|
||||||
|
#else
|
||||||
|
// set stack[sp].`tmpStr` to {}
|
||||||
|
snprintf(state->tmpStr2, 4096, "stack.%d.%s", state->stackPointer,
|
||||||
|
(char*)state->tmpStr);
|
||||||
|
new_object_path(state->tmpStr2);
|
||||||
|
|
||||||
|
// bump
|
||||||
|
state->stackPointer += 1;
|
||||||
|
|
||||||
|
// set stack[sp+1] to the same object as stack[sp].`tmpStr`
|
||||||
|
snprintf(state->tmpStr, 4096, "stack.%d", state->stackPointer);
|
||||||
|
|
||||||
|
set_path_to_path(state->tmpStr, state->tmpStr2);
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int varSizeSpan(vcd_parser_t* state, const unsigned char* p,
|
||||||
|
const unsigned char* endp) {
|
||||||
|
const int32_t size = strtol((const char*)p, (char**)&endp, 10);
|
||||||
|
state->size = size;
|
||||||
|
#ifndef VCDWASM
|
||||||
|
#else
|
||||||
|
set_property_int("varType", state->type);
|
||||||
|
set_property_int("varSize", size);
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int varIdSpan(vcd_parser_t* state, const unsigned char* p,
|
||||||
|
const unsigned char* endp) {
|
||||||
|
#ifndef VCDWASM
|
||||||
|
napi_env env = state->napi_env;
|
||||||
|
napi_value varId;
|
||||||
|
ASSERT(varId,
|
||||||
|
napi_create_string_latin1(env, (char*)p, (endp - p - 1), &varId))
|
||||||
|
ASSERT(state->info,
|
||||||
|
napi_set_named_property(env, state->info, "varId", varId))
|
||||||
|
#else
|
||||||
|
strcopy(p, endp, state->tmpStr);
|
||||||
|
set_property_string("varId", state->tmpStr);
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int varNameSpan(vcd_parser_t* state, const unsigned char* p,
|
||||||
|
const unsigned char* endp) {
|
||||||
|
#ifndef VCDWASM
|
||||||
|
napi_env env = state->napi_env;
|
||||||
|
// *(endp - 1) = 0; // FIXME NULL termination of ASCII string
|
||||||
|
strcopy(p, endp, state->tmpStr);
|
||||||
|
napi_value stack, top, varId;
|
||||||
|
ASSERT(state->info,
|
||||||
|
napi_get_named_property(env, state->info, "stack", &stack))
|
||||||
|
ASSERT(top, napi_get_element(env, stack, state->stackPointer, &top))
|
||||||
|
ASSERT(state->info,
|
||||||
|
napi_get_named_property(env, state->info, "varId", &varId))
|
||||||
|
ASSERT(state->info, napi_set_named_property(env, top, state->tmpStr, varId))
|
||||||
|
#else
|
||||||
|
strcopy(p, endp, state->tmpStr);
|
||||||
|
// set
|
||||||
|
// info.stack[sp].`tmpStr` = info.varId
|
||||||
|
snprintf(state->tmpStr2, 4096, "stack.%d.%s", state->stackPointer,
|
||||||
|
(char*)state->tmpStr);
|
||||||
|
set_path_to_path(state->tmpStr2, "varType,varSize,varId");
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int idSpan(vcd_parser_t* state, const unsigned char* p,
|
||||||
|
const unsigned char* endp) {
|
||||||
|
strconcat(p, endp, state->idStr);
|
||||||
|
// printf("<idSpan|%s>\n", (char *)state->idStr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int onId(vcd_parser_t* state, const unsigned char* _p,
|
||||||
|
const unsigned char* _endp) {
|
||||||
|
#ifndef VCDWASM
|
||||||
|
napi_env env = state->napi_env;
|
||||||
|
#endif
|
||||||
|
const unsigned char* p = (unsigned char*)state->idStr;
|
||||||
|
const unsigned int plen = strlen((char*)p) - 1;
|
||||||
|
*(char*)(p + plen) = 0; // null instead of space
|
||||||
|
const unsigned char* endp = p + plen - 1;
|
||||||
|
// printf("<onId|%s>\n", (char *)state->idStr);
|
||||||
|
|
||||||
|
const int valueWords = (state->digitCount + 63) >> 6;
|
||||||
|
const int maskWords = (state->maskCount + 63) >> 6;
|
||||||
|
uint64_t* value = state->value;
|
||||||
|
uint64_t* mask = state->mask;
|
||||||
|
if (stringEq((state->trigger), p, endp)) {
|
||||||
|
const uint8_t command = state->command;
|
||||||
|
// printf("{id:'%s',cmd:%d}", (char *)p, command);
|
||||||
|
// if (command == 14) {
|
||||||
|
// value[0] = 0;
|
||||||
|
// mask[0] = 0;
|
||||||
|
// } else
|
||||||
|
// if (command == 15) {
|
||||||
|
// value[0] = 1;
|
||||||
|
// mask[0] = 0;
|
||||||
|
// }
|
||||||
|
#ifndef VCDWASM
|
||||||
|
napi_value undefined, eventName, aTime, aCommand, aValue, aMask,
|
||||||
|
return_val;
|
||||||
|
ASSERT(undefined, napi_get_undefined(env, &undefined))
|
||||||
|
ASSERT(eventName, napi_create_string_latin1(
|
||||||
|
env, (char*)p, NAPI_AUTO_LENGTH, &eventName))
|
||||||
|
ASSERT(aTime, napi_create_int64(env, state->time, &aTime))
|
||||||
|
ASSERT(aCommand, napi_create_int32(env, command, &aCommand))
|
||||||
|
ASSERT(aValue,
|
||||||
|
napi_create_bigint_words(env, 0, valueWords, value, &aValue))
|
||||||
|
ASSERT(aMask, napi_create_bigint_words(env, 0, maskWords, mask, &aMask))
|
||||||
|
napi_value* argv[] = {&eventName, &aTime, &aCommand, &aValue, &aMask};
|
||||||
|
ASSERT(state->triee, napi_call_function(env, undefined, state->triee, 5,
|
||||||
|
*argv, &return_val))
|
||||||
|
// printf("<id='%s'>", (char *)p);
|
||||||
|
#else
|
||||||
|
// strcopy(p, endp, state->tmpStr);
|
||||||
|
emit_triee((char*)p, state->time, command, valueWords, value, maskWords,
|
||||||
|
mask);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
for (int i = 0; i < valueWords; i++) {
|
||||||
|
value[i] = 0;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < maskWords; i++) {
|
||||||
|
mask[i] = 0;
|
||||||
|
}
|
||||||
|
state->digitCount = 0;
|
||||||
|
state->maskCount = 0;
|
||||||
|
*(char*)state->idStr = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 匹配 value id 这样的格式
|
||||||
|
int onDigit(vcd_parser_t* state, const unsigned char* _p,
|
||||||
|
const unsigned char* _endp, int digit) {
|
||||||
|
unsigned int valueCin = (digit & 1);
|
||||||
|
unsigned int maskCin = ((digit >> 1) & 1);
|
||||||
|
|
||||||
|
if ((valueCin != 0) || (state->digitCount != 0)) {
|
||||||
|
unsigned int valueCout;
|
||||||
|
uint64_t* value = state->value;
|
||||||
|
const int valueWordsMinus = (state->digitCount >> 6);
|
||||||
|
for (int i = 0; i <= valueWordsMinus; i++) {
|
||||||
|
valueCout = value[i] >> 63;
|
||||||
|
value[i] = (value[i] << 1) + valueCin;
|
||||||
|
valueCin = valueCout;
|
||||||
|
}
|
||||||
|
state->digitCount += 1;
|
||||||
|
}
|
||||||
|
if ((maskCin != 0) || (state->maskCount != 0)) {
|
||||||
|
unsigned int maskCout;
|
||||||
|
uint64_t* mask = state->mask;
|
||||||
|
const int maskWordsMinus = (state->maskCount >> 6);
|
||||||
|
for (int i = 0; i <= maskWordsMinus; i++) {
|
||||||
|
maskCout = mask[i] >> 63;
|
||||||
|
mask[i] = (mask[i] << 1) + maskCin;
|
||||||
|
maskCin = maskCout;
|
||||||
|
}
|
||||||
|
state->maskCount += 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int onRecover(vcd_parser_t* state, const unsigned char* p,
|
||||||
|
const unsigned char* endp, int digit) {
|
||||||
|
state->digitCount = 0;
|
||||||
|
state->maskCount = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int timeSpan(vcd_parser_t* state, const unsigned char* p,
|
||||||
|
const unsigned char* endp) {
|
||||||
|
strconcat(p, endp, state->timeStampStr);
|
||||||
|
// printf("<timeSpan|%s>\n", (char *)state->timeStampStr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int onTime(vcd_parser_t* state, const unsigned char* _p,
|
||||||
|
const unsigned char* _endp) {
|
||||||
|
char* end;
|
||||||
|
const int64_t time = strtoul(state->timeStampStr, &end, 10);
|
||||||
|
// printf("<onTime|%lu>\n", time);
|
||||||
|
if (state->time == INT64_MAX) {
|
||||||
|
#ifndef VCDWASM
|
||||||
|
napi_env env = state->napi_env;
|
||||||
|
napi_value val;
|
||||||
|
ASSERT(val, napi_create_int64(env, time, &val))
|
||||||
|
ASSERT(state->info,
|
||||||
|
napi_set_named_property(env, state->info, "t0", val))
|
||||||
|
#else
|
||||||
|
set_property_int("t0", time);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
state->time = time;
|
||||||
|
*(char*)state->timeStampStr = 0;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user