完成 的支持 | 优化工具函数
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
|
||||
source $EMCC_HOME/emsdk_env.sh
|
||||
# once only
|
||||
npm install browserify terser -g
|
||||
npm install browserify terser node-gyp -g
|
||||
# once only
|
||||
node bin/build.js
|
||||
npm i
|
||||
# build
|
||||
make -j 12
|
||||
# adjust to browser environment
|
||||
browserify ./bin/vcd.js | terser --compress -o ./out/vcd.js
|
||||
```
|
||||
|
||||
production are :
|
||||
@ -27,6 +25,25 @@ production are :
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable indent */
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
@ -7,89 +8,89 @@ const cp = require('child_process');
|
||||
const llparse = require('llparse');
|
||||
|
||||
const gyp = cb => {
|
||||
console.log('build');
|
||||
const proc = cp.spawn('node-gyp', ['configure', 'build']);
|
||||
proc.stderr.on('data', data => {
|
||||
console.error(data.toString());
|
||||
});
|
||||
proc.on('close', (cb || (() => {
|
||||
console.log('done');
|
||||
})));
|
||||
console.log('build');
|
||||
const proc = cp.spawn('node-gyp', ['configure', 'build']);
|
||||
proc.stderr.on('data', data => {
|
||||
console.error(data.toString());
|
||||
});
|
||||
proc.on('close', (cb || (() => {
|
||||
console.log('done');
|
||||
})));
|
||||
};
|
||||
|
||||
const objection = lut => arg => arg.split(/\s+/).reduce((res, key) => {
|
||||
if (lut[key] === undefined) {
|
||||
throw new Error(key);
|
||||
}
|
||||
res[key] = lut[key];
|
||||
return res;
|
||||
if (lut[key] === undefined) {
|
||||
throw new Error(key);
|
||||
}
|
||||
res[key] = lut[key];
|
||||
return res;
|
||||
}, {});
|
||||
|
||||
const properties = {
|
||||
command: 'i8',
|
||||
type: 'i8',
|
||||
size: 'i32',
|
||||
time: 'i64', // current simulation time
|
||||
trigger: 'ptr',
|
||||
triee: 'ptr', // trigger event emitter
|
||||
lifee: 'ptr', // life cycle event emmiter
|
||||
info: 'ptr',
|
||||
value: 'ptr', // value of the signal on change event
|
||||
mask: 'ptr', // mask (x, z) of the signal on change event
|
||||
digitCount: 'i32',
|
||||
maskCount: 'i32',
|
||||
tmpStr: 'ptr',
|
||||
timeStampStr: 'ptr',
|
||||
idStr: 'ptr',
|
||||
tmpStr2: 'ptr',
|
||||
stackPointer: 'i32',
|
||||
id: 'ptr',
|
||||
napi_env: 'ptr'
|
||||
command: 'i8',
|
||||
type: 'i8',
|
||||
size: 'i32',
|
||||
time: 'i64', // current simulation time
|
||||
trigger: 'ptr',
|
||||
triee: 'ptr', // trigger event emitter
|
||||
lifee: 'ptr', // life cycle event emmiter
|
||||
info: 'ptr',
|
||||
value: 'ptr', // value of the signal on change event
|
||||
mask: 'ptr', // mask (x, z) of the signal on change event
|
||||
digitCount: 'i32',
|
||||
maskCount: 'i32',
|
||||
tmpStr: 'ptr',
|
||||
timeStampStr: 'ptr',
|
||||
idStr: 'ptr',
|
||||
tmpStr2: 'ptr',
|
||||
stackPointer: 'i32',
|
||||
id: 'ptr',
|
||||
napi_env: 'ptr'
|
||||
};
|
||||
|
||||
const spaces = [' ', '\n', '\r', '\t'];
|
||||
const lineSpaces = [' ', '\t'];
|
||||
|
||||
const generate = (cb) => {
|
||||
// const llparseDot = require('llparse-dot');
|
||||
// const llparseDot = require('llparse-dot');
|
||||
|
||||
const prj = 'vcd_parser';
|
||||
const p = new llparse.LLParse(prj);
|
||||
const prj = 'vcd_parser';
|
||||
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 {
|
||||
// scopeIdentifierSpan,
|
||||
varSizeSpan, varIdSpan, varNameSpan,
|
||||
idSpan,
|
||||
commandSpan,
|
||||
timeSpan
|
||||
} = `
|
||||
const {
|
||||
// scopeIdentifierSpan,
|
||||
varSizeSpan, varIdSpan, varNameSpan,
|
||||
idSpan,
|
||||
commandSpan,
|
||||
timeSpan
|
||||
} = `
|
||||
varSizeSpan varIdSpan varNameSpan
|
||||
idSpan
|
||||
commandSpan
|
||||
timeSpan
|
||||
`
|
||||
.trim().split(/\s+/)
|
||||
.reduce((res, n) => Object.assign(res, {[n]: p.span(p.code.span(n))}), {});
|
||||
.trim().split(/\s+/)
|
||||
.reduce((res, n) => Object.assign(res, { [n]: p.span(p.code.span(n)) }), {});
|
||||
|
||||
// scopeIdentifierSpan
|
||||
// scopeIdentifierSpan
|
||||
|
||||
const {
|
||||
declaration,
|
||||
// scopeType, scopeTypeEnd,
|
||||
// scopeIdentifier, scopeIdentifierEnd,
|
||||
varType, varTypeEnd,
|
||||
varSize, varSizeEnd,
|
||||
varId, varIdEnd,
|
||||
varName, varNameEnd,
|
||||
inDeclaration,
|
||||
simulation,
|
||||
inSimulation,
|
||||
simulationTime,
|
||||
simulationVector, simulationVectorEnd, simulationVectorRecovery,
|
||||
simulationId
|
||||
} = `
|
||||
const {
|
||||
declaration,
|
||||
// scopeType, scopeTypeEnd,
|
||||
// scopeIdentifier, scopeIdentifierEnd,
|
||||
varType, varTypeEnd,
|
||||
varSize, varSizeEnd,
|
||||
varId, varIdEnd,
|
||||
varName, varNameEnd,
|
||||
inDeclaration,
|
||||
simulation,
|
||||
inSimulation,
|
||||
simulationTime,
|
||||
simulationVector, simulationVectorEnd, simulationVectorRecovery,
|
||||
simulationId
|
||||
} = `
|
||||
declaration
|
||||
varType varTypeEnd
|
||||
varSize varSizeEnd
|
||||
@ -102,211 +103,178 @@ const generate = (cb) => {
|
||||
simulationVector simulationVectorEnd simulationVectorRecovery
|
||||
simulationId
|
||||
`
|
||||
.trim().split(/\s+/)
|
||||
.reduce((res, n) => Object.assign(res, {[n]: p.node(n)}), {});
|
||||
.trim().split(/\s+/)
|
||||
.reduce((res, n) => Object.assign(res, { [n]: p.node(n) }), {});
|
||||
|
||||
// scopeType scopeTypeEnd
|
||||
// scopeIdentifier scopeIdentifierEnd
|
||||
// scopeType scopeTypeEnd
|
||||
// scopeIdentifier scopeIdentifierEnd
|
||||
|
||||
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
|
||||
});
|
||||
const enddefinitions = p.node('inDeclarationEnd');
|
||||
|
||||
declaration
|
||||
.match(spaces, declaration)
|
||||
// .select(cmd('$scope'),
|
||||
// p.invoke(p.code.store('command'), commandSpan.start(scopeType)))
|
||||
// .select(cmd('$var'),
|
||||
// p.invoke(p.code.store('command'), commandSpan.start(varType)))
|
||||
.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'));
|
||||
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
|
||||
});
|
||||
|
||||
// $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));
|
||||
// scopeIdentifierEnd.match(spaces, scopeIdentifierSpan.end(inDeclaration)).skipTo(scopeIdentifierEnd);
|
||||
// $var reg 3 ( r_reg [2:0] $end
|
||||
// ^
|
||||
|
||||
// $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);
|
||||
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
|
||||
// ^
|
||||
|
||||
// $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));
|
||||
varSizeEnd.match(spaces, varSizeSpan.end(varId)).skipTo(varSizeEnd);
|
||||
// $var reg 3 ( r_reg [2:0] $end
|
||||
// ^^^^^
|
||||
|
||||
// $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));
|
||||
varIdEnd.match(spaces, varIdSpan.end(varName)).skipTo(varIdEnd);
|
||||
// $end
|
||||
|
||||
// $var reg 3 ( r_reg [2:0] $end
|
||||
// ^^^^^
|
||||
inDeclaration
|
||||
.match('$end', commandSpan.end(declaration))
|
||||
.skipTo(inDeclaration);
|
||||
|
||||
varName.match(spaces, varName).otherwise(varNameSpan.start(varNameEnd));
|
||||
varNameEnd.match('$end', commandSpan.end(varNameSpan.end(declaration))).skipTo(varNameEnd);
|
||||
enddefinitions
|
||||
.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
|
||||
.match('$end', commandSpan.end(declaration))
|
||||
.skipTo(inDeclaration);
|
||||
inSimulation
|
||||
.match('$end', commandSpan.end(simulation))
|
||||
.skipTo(inSimulation);
|
||||
|
||||
enddefinitions
|
||||
.match('$end', commandSpan.end(simulation))
|
||||
.skipTo(enddefinitions);
|
||||
simulationTime
|
||||
.match(spaces, timeSpan.end(p.invoke(p.code.span('onTime'), simulation)))
|
||||
.skipTo(simulationTime);
|
||||
|
||||
simulation
|
||||
.match([' ', '\r', '\n', '\t', '$dumpvars', '$end'], simulation)
|
||||
.select(cmd('$dumpall $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'));
|
||||
simulationVector
|
||||
.select(
|
||||
{
|
||||
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);
|
||||
|
||||
inSimulation
|
||||
.match('$end', commandSpan.end(simulation))
|
||||
.skipTo(inSimulation);
|
||||
simulationVectorEnd
|
||||
.match(lineSpaces, idSpan.start(simulationId))
|
||||
.skipTo(simulationVectorRecovery);
|
||||
|
||||
simulationTime
|
||||
.match(spaces, timeSpan.end(p.invoke(p.code.span('onTime'), simulation)))
|
||||
.skipTo(simulationTime);
|
||||
simulationVectorRecovery
|
||||
.select(
|
||||
{
|
||||
'\n': 1, '\r': 1
|
||||
},
|
||||
p.invoke(
|
||||
p.code.value('onRecover'),
|
||||
{ 1: p.error(6, 'recover') },
|
||||
simulation
|
||||
)
|
||||
)
|
||||
.skipTo(simulationVectorRecovery);
|
||||
|
||||
simulationVector
|
||||
.select(
|
||||
{
|
||||
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);
|
||||
simulationId
|
||||
.match(spaces, idSpan.end(p.invoke(p.code.span('onId'), simulation)))
|
||||
.skipTo(simulationId);
|
||||
|
||||
simulationVectorEnd
|
||||
.match(lineSpaces, idSpan.start(simulationId))
|
||||
.skipTo(simulationVectorRecovery);
|
||||
const artifacts = p.build(declaration);
|
||||
|
||||
simulationVectorRecovery
|
||||
.select(
|
||||
{
|
||||
'\n': 1, '\r': 1
|
||||
},
|
||||
p.invoke(
|
||||
p.code.value('onRecover'),
|
||||
{1: p.error(6, 'recover')},
|
||||
simulation
|
||||
)
|
||||
)
|
||||
.skipTo(simulationVectorRecovery);
|
||||
fs.writeFileSync(prj + '.h', artifacts.header);
|
||||
// fs.writeFileSync('verilog_preprocessor.bc', artifacts.bitcode);
|
||||
fs.writeFileSync(prj + '.c', artifacts.c);
|
||||
|
||||
simulationId
|
||||
.match(spaces, idSpan.end(p.invoke(p.code.span('onId'), simulation)))
|
||||
.skipTo(simulationId);
|
||||
// const dot = new llparseDot.Dot();
|
||||
// fs.writeFileSync(prj + '.dot', dot.build(declaration));
|
||||
|
||||
const artifacts = p.build(declaration);
|
||||
|
||||
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();
|
||||
if (cb) {
|
||||
cb();
|
||||
}
|
||||
};
|
||||
|
||||
generate(gyp);
|
||||
// generate();
|
||||
|
||||
/* eslint camelcase: 0 */
|
||||
|
@ -1,5 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable indent */
|
||||
|
||||
const fs = require('fs-extra');
|
||||
const async = require('async');
|
||||
|
@ -1,5 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable indent */
|
||||
|
||||
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 webVcdParser = require('../lib/web-vcd-parser.js');
|
||||
|
||||
async function getVcdStream() {
|
||||
const wasm = await createVCD();
|
||||
const ostream = await webVcdParser(wasm);
|
||||
return ostream;
|
||||
/**
|
||||
* @typedef {{ maxChunkLength: number, useGcd: boolean }} consumeConfig
|
||||
*
|
||||
* @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';
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable indent */
|
||||
|
||||
module.exports = skip => {
|
||||
let start = 0;
|
||||
let stop = 0;
|
||||
let up = 0;
|
||||
let total = 0;
|
||||
return {
|
||||
on: (time, cmd) => {
|
||||
if (time > skip) {
|
||||
if (start == 0) {
|
||||
start = time;
|
||||
} else {
|
||||
stop = time;
|
||||
}
|
||||
}
|
||||
if (cmd === 15) {
|
||||
up = time;
|
||||
} else
|
||||
if (cmd === 14) {
|
||||
total += (time - up); up = time;
|
||||
}
|
||||
},
|
||||
time: () => stop - start,
|
||||
uptime: () => total
|
||||
};
|
||||
let start = 0;
|
||||
let stop = 0;
|
||||
let up = 0;
|
||||
let total = 0;
|
||||
return {
|
||||
on: (time, cmd) => {
|
||||
if (time > skip) {
|
||||
if (start == 0) {
|
||||
start = time;
|
||||
} else {
|
||||
stop = time;
|
||||
}
|
||||
}
|
||||
if (cmd === 15) {
|
||||
up = time;
|
||||
} else
|
||||
if (cmd === 14) {
|
||||
total += (time - up); up = time;
|
||||
}
|
||||
},
|
||||
time: () => stop - start,
|
||||
uptime: () => total
|
||||
};
|
||||
};
|
||||
|
@ -1,4 +1,6 @@
|
||||
'use strict';
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable indent */
|
||||
|
||||
const handleScope = (info, str) => {
|
||||
const [type, name] = str.split(/\s+/);
|
||||
|
@ -1,4 +1,6 @@
|
||||
'use strict';
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable indent */
|
||||
|
||||
const stream = require('stream');
|
||||
const EventEmitter = require('events').EventEmitter;
|
||||
|
@ -1,4 +1,6 @@
|
||||
'use strict';
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable indent */
|
||||
|
||||
const parseTimescale = require('./parse-time-scale.js');
|
||||
|
||||
|
@ -1,4 +1,7 @@
|
||||
'use strict';
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable indent */
|
||||
/* eslint-disable no-unused-vars */
|
||||
|
||||
const stream = require('stream');
|
||||
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_wasm": "nyc -r=text -r=lcov mocha test/wasm_*",
|
||||
"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",
|
||||
"watch": "mocha --watch",
|
||||
"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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "vcd_parser.h"
|
||||
|
||||
#ifndef VCDWASM
|
||||
@ -14,343 +15,364 @@
|
||||
typedef void* napi_env;
|
||||
#endif
|
||||
|
||||
|
||||
// #define LOGSPAN
|
||||
// #define LOGSPAN printf("%s\n", __FUNCTION__);
|
||||
|
||||
|
||||
#define ASSERT(val, expr) \
|
||||
if (expr != napi_ok) { \
|
||||
#define ASSERT(val, expr) \
|
||||
if (expr != napi_ok) { \
|
||||
napi_throw(env, val); \
|
||||
}
|
||||
|
||||
void strcopy(const unsigned char* p, const unsigned char* endp, unsigned char* dst) {
|
||||
const unsigned char* src;
|
||||
src = p;
|
||||
while (src < (endp - 1)) {
|
||||
*dst = *src;
|
||||
src++;
|
||||
dst++;
|
||||
}
|
||||
*dst = 0;
|
||||
void strcopy(const unsigned char* p, const unsigned char* endp,
|
||||
unsigned char* dst) {
|
||||
const unsigned char* src;
|
||||
src = p;
|
||||
while (src < (endp - 1)) {
|
||||
*dst = *src;
|
||||
src++;
|
||||
dst++;
|
||||
}
|
||||
*dst = 0;
|
||||
}
|
||||
|
||||
void strconcat(const unsigned char* p, const unsigned char* endp, unsigned char* dst) {
|
||||
// printf("<len:%d>", endp - p);
|
||||
dst += strlen((char *)dst); // go to the end of string
|
||||
while (p < endp) {
|
||||
*dst = *p;
|
||||
p++;
|
||||
dst++;
|
||||
}
|
||||
*dst = 0;
|
||||
void strconcat(const unsigned char* p, const unsigned char* endp,
|
||||
unsigned char* dst) {
|
||||
// printf("<len:%d>", endp - p);
|
||||
dst += strlen((char*)dst); // go to the end of string
|
||||
while (p < endp) {
|
||||
*dst = *p;
|
||||
p++;
|
||||
dst++;
|
||||
}
|
||||
*dst = 0;
|
||||
}
|
||||
|
||||
// FIXME use a better structure to match strings
|
||||
int stringEq (
|
||||
const unsigned char* i, // search pattern
|
||||
const unsigned char* p,
|
||||
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
|
||||
int stringEq(const unsigned char* i, // search pattern
|
||||
const unsigned char* p, const unsigned char* endp) {
|
||||
if (*i == 0) {
|
||||
return 1;
|
||||
}
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
while (*i != 0) { // skip to the end of pattern word
|
||||
i++;
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
const uint8_t command = state->command;
|
||||
#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)) {
|
||||
int commandSpan(vcd_parser_t* state, const unsigned char* p,
|
||||
const unsigned char* 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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))
|
||||
|
||||
// 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
|
||||
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
|
||||
}
|
||||
state->time = time;
|
||||
*(char *)state->timeStampStr = 0;
|
||||
return 0;
|
||||
|
||||
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;
|
||||
// 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