fixed issues with cross chunk Spans, chunk string->array, and better tests

This commit is contained in:
Aliaksei Chapyzhenka 2022-05-25 22:15:31 -07:00
parent afbee0d083
commit 1d920a3e08
14 changed files with 424 additions and 285 deletions

View File

@ -37,6 +37,8 @@ const properties = {
mask: 'ptr', // mask (x, z) of the signal on change event mask: 'ptr', // mask (x, z) of the signal on change event
digitCount: 'i32', digitCount: 'i32',
tmpStr: 'ptr', tmpStr: 'ptr',
timeStampStr: 'ptr',
idStr: 'ptr',
tmpStr2: 'ptr', tmpStr2: 'ptr',
stackPointer: 'i32', stackPointer: 'i32',
id: 'ptr', id: 'ptr',
@ -255,7 +257,7 @@ const generate = (cb) => {
.skipTo(inSimulation); .skipTo(inSimulation);
simulationTime simulationTime
.match(spaces, timeSpan.end(simulation)) .match(spaces, timeSpan.end(p.invoke(p.code.span('onTime'), simulation)))
.skipTo(simulationTime); .skipTo(simulationTime);
simulationVector simulationVector
@ -298,7 +300,7 @@ const generate = (cb) => {
.skipTo(simulationVectorRecovery); .skipTo(simulationVectorRecovery);
simulationId simulationId
.match(spaces, idSpan.end(simulation)) .match(spaces, idSpan.end(p.invoke(p.code.span('onId'), simulation)))
.skipTo(simulationId); .skipTo(simulationId);
const artifacts = p.build(declaration); const artifacts = p.build(declaration);

35
lib/chopper.js Normal file
View File

@ -0,0 +1,35 @@
'use strict';
function xoshiro128ss(a, b, c, d) {
return function() {
var t = b << 9, r = a * 5; r = (r << 7 | r >>> 25) * 9;
c ^= a; d ^= b;
b ^= c; a ^= d; c ^= t;
d = d << 11 | d >>> 21;
return (r >>> 0) / 4294967296;
};
}
function * chopper (src, step) {
const chunker = len => {
const chunk = src.slice(0, len);
src = src.slice(chunk.length);
return chunk;
};
const random = xoshiro128ss(1134534345, 2145245245624, 313442566456, 4245642456456);
// const random = Math.random;
// const random = () => 0;
// yield(chunker(395));
// yield(chunker(145));
while(true) {
if (src.length === 0) {
return;
}
yield(chunker(random() * step + step));
}
}
module.exports = chopper;

View File

@ -31,15 +31,21 @@ module.exports = () => {
const cxt = lib.init(lifemit, triemit, info); const cxt = lib.init(lifemit, triemit, info);
s._write = function (chunk, encoding, callback) { s._write = function (chunk, encoding, callback) {
lib.execute(cxt, lifemit, triemit2, info, chunk); const err = lib.execute(cxt, lifemit, triemit2, info, chunk);
if (err) {
// console.log(info);
console.log(err);
// throw new Error(err);
}
callback(); callback();
}; };
s.change = { s.change = {
on: (id, fn) => { on: (id, fn) => {
// console.log(id);
triemit2 = triemit; triemit2 = triemit;
triee.on(id, fn); triee.on(id, fn);
const triggerString = triee.eventNames().join(' ') + ' '; const triggerString = triee.eventNames().join('\0') + '\0\0';
lib.setTrigger(cxt, triggerString); lib.setTrigger(cxt, triggerString);
}, },
any: fn => { any: fn => {

View File

@ -11,26 +11,36 @@ const dotProp = require('dot-prop');
// }); // });
// } // }
function u8ToBn(u8) { // function u8ToBn(u8) {
var hex = []; // let str = '';
// let u8 = Uint8Array.from(buf); // for (let i = 0; i < u8.length; i++) {
// const val = u8[i];
// str = val.toString(16) + str;
// if (val < 16) {
// str = '0' + str;
// }
// }
// return BigInt('0x' + str);
// }
u8.forEach(function (i) { function h8ToBn(HEAPU8, start, len) {
var h = i.toString(16); let str = '';
if (h.length % 2) { h = '0' + h; } const fin = start + len;
hex.push(h); for (let i = start; i < fin; i++) {
}); const val = HEAPU8[i];
str = val.toString(16) + str;
hex.reverse(); if (val < 16) {
str = '0' + str;
return BigInt('0x' + hex.join('')); }
}
return BigInt('0x' + str);
} }
// let startCalled = 0; // let startCalled = 0;
const bindCWrap = (c, wasm) => { const bindCWrap = (c, wasm) => {
const w = wasm.cwrap; const w = wasm.cwrap;
c.execute = w('execute', 'number', ['number', 'number', 'number', 'number', 'number', 'string']); c.execute = w('execute', 'number', ['number', 'number', 'number', 'number', 'number', 'array', 'number']);
c.init = w('init', 'number', ['number', 'number', 'number', 'number']); c.init = w('init', 'number', ['number', 'number', 'number', 'number']);
c.getTime = w('getTime', 'number', ['number']); c.getTime = w('getTime', 'number', ['number']);
c.setTrigger = w('setTrigger', 'number', ['number', 'string']); c.setTrigger = w('setTrigger', 'number', ['number', 'string']);
@ -57,13 +67,21 @@ const getWrapper = wasm => {
// gets a string from a c heap pointer and length // gets a string from a c heap pointer and length
const getString = (name, len) => { const getString = (name, len) => {
const view = wasm.HEAPU8.subarray(name, name+len);
// const view = wasm.HEAPU8.subarray(name, name+len);
// let string = '';
// for (let i = 0; i < len; i++) {
// string += String.fromCharCode(view[i]);
// }
// return string;
let string = ''; let string = '';
for (let i = 0; i < len; i++) { const end = name + len;
string += String.fromCharCode(view[i]); for (let i = name; i < end; i++) {
string += String.fromCharCode(wasm.HEAPU8[i]);
} }
return string; return string;
}; };
let boundInfo; let boundInfo;
@ -137,16 +155,19 @@ const getWrapper = wasm => {
boundEE1 = wasm.addFunction(function(eventName, l0, time, command, valueWords, value, mask) { boundEE1 = wasm.addFunction(function(eventName, l0, time, command, valueWords, value, mask) {
const name = getString(eventName, l0); const name = getString(eventName, l0);
// console.log(`event name`); // console.log(`event name`);
// console.log(`event ${name} time ${time} cmd ${command} wrds ${valueWords}`); // console.log({name, time, command, valueWords});
const view0 = wasm.HEAPU8.subarray(value, value+(valueWords*8)); // const view0 = wasm.HEAPU8.subarray(value, value+(valueWords*8));
const view1 = wasm.HEAPU8.subarray(mask, mask+(valueWords*8)); // const view1 = wasm.HEAPU8.subarray(mask, mask+(valueWords*8));
let bigValue = u8ToBn(view0); // let bigValue = u8ToBn(view0);
let bigMask = u8ToBn(view1); // let bigMask = u8ToBn(view1);
// let bigValue = 0n;
// console.log(bigValue.toString(16)); // console.log(bigValue.toString(16));
const bigValue = h8ToBn(wasm.HEAPU8, value, valueWords * 8);
const bigMask = h8ToBn(wasm.HEAPU8, mask, valueWords * 8);
ee[1](name, time, command, bigValue, bigMask); ee[1](name, time, command, bigValue, bigMask);
}, 'viijiiii'); }, 'viijiiii');
@ -167,7 +188,7 @@ const getWrapper = wasm => {
boundInfo = info; boundInfo = info;
ee[0] = cb0; ee[0] = cb0;
ee[1] = cb1; ee[1] = cb1;
c.execute(ctx, boundEE0, boundEE1, boundSet, boundGet, chunk.toString()); return c.execute(ctx, boundEE0, boundEE1, boundSet, boundGet, chunk, chunk.length);
}, },
setTrigger: (ctx, triggerString) => { setTrigger: (ctx, triggerString) => {
return c.setTrigger(ctx, triggerString); return c.setTrigger(ctx, triggerString);
@ -208,8 +229,11 @@ module.exports = async wasm => {
const cxt = lib.init(lifemit, triemit, info); const cxt = lib.init(lifemit, triemit, info);
s._write = function (chunk, encoding, callback) { s._write = function (chunk, encoding, callback) {
// console.log('about to write', chunk); // console.log(cxt, info);
lib.execute(cxt, lifemit, triemit2, info, chunk); const err = lib.execute(cxt, lifemit, triemit2, info, chunk);
if (err) {
console.log(err);
}
// console.log(util.inspect(info, {showHidden: true, depth : null, colorize: true})); // console.log(util.inspect(info, {showHidden: true, depth : null, colorize: true}));
// console.log(info.stack[0].top); // console.log(info.stack[0].top);
// console.log(info.stack[1]); // console.log(info.stack[1]);
@ -220,9 +244,9 @@ module.exports = async wasm => {
s.change = { s.change = {
on: (id, fn) => { on: (id, fn) => {
triemit2 = triemit; triemit2 = triemit;
// console.log(id, fn);
triee.on(id, fn); triee.on(id, fn);
const triggerString = triee.eventNames().join(' ') + ' '; const triggerString = triee.eventNames().join(' ') + ' ';
// console.log(id, Buffer.from(triggerString));
lib.setTrigger(cxt, triggerString); lib.setTrigger(cxt, triggerString);
}, },
any: fn => { any: fn => {
@ -239,5 +263,3 @@ module.exports = async wasm => {
return s; return s;
}; };
/* global BigInt */

View File

@ -1,7 +1,5 @@
'use strict'; 'use strict';
/* global BigInt */
const dotProp = require('dot-prop'); const dotProp = require('dot-prop');
function _waitForStart(mod) { function _waitForStart(mod) {

File diff suppressed because one or more lines are too long

Binary file not shown.

72
test/dump.vcd Normal file
View File

@ -0,0 +1,72 @@
$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
#100
0"}G
#200
1"}G
bzzzzxxxx11110000ZZZZXXXX11110000zzzzxxxx11110000zzzzxxxx11110000 {u
#300
0"}G
b1111000000000000000000000000000000000000000000000000000000000000 {u
b0000 u)
#301
b0000111100000000000000000000000000000000000000000000000000000000 {u
b0001 u)
#302
b0000000011110000000000000000000000000000000000000000000000000000 {u
b0010 u)
#303
b0000000000001111000000000000000000000000000000000000000000000000 {u
b0011 u)
#304
b0000000000000000111100000000000000000000000000000000000000000000 {u
b0100 u)
#305
b0000000000000000000011110000000000000000000000000000000000000000 {u
b0101 u)
#306
b0000000000000000000000001111000000000000000000000000000000000000 {u
b0110 u)
#307
b0000000000000000000000000000111100000000000000000000000000000000 {u
b0111 u)
#308
B0000000000000000000000000000000011110000000000000000000000000000 {u
b1000 u)
#309
b0000000000000000000000000000000000001111000000000000000000000000 {u
b1001 u)
#310
b0000000000000000000000000000000000000000111100000000000000000000 {u
b1010 u)
#311
b0000000000000000000000000000000000000000000011110000000000000000 {u
b1011 u)
#312
b0000000000000000000000000000000000000000000000001111000000000000 {u
b1100 u)
#313
b0000000000000000000000000000000000000000000000000000111100000000 {u
b1101 u)
#314
b0000000000000000000000000000000000000000000000000000000011110000 {u
b1110 u)
#315
b0000000000000000000000000000000000000000000000000000000000001111 {u
b1111 u)
#316
1"}G

View File

@ -17,7 +17,9 @@ describe('basic', () => {
it('fail: foo bar', done => { it('fail: foo bar', done => {
const inst = parser(); const inst = parser();
expect(inst.write(Buffer.from(' foo bar ???'))).to.eq(true); expect(() => {
inst.write(Buffer.from(' foo bar ???'));
}).not.to.throw();
expect(inst.info).to.deep.eq({ expect(inst.info).to.deep.eq({
stack: [{}], stack: [{}],
status: 'declaration', status: 'declaration',
@ -26,11 +28,13 @@ describe('basic', () => {
done(); done();
}); });
it('$comment', done => { it('fail: $comment', done => {
const inst = parser(); const inst = parser();
expect(inst.write(Buffer.from( expect(() => {
' \n $comment some text $end $comment more text $end ???' inst.write(Buffer.from(
))).to.eq(true); ' \n $comment some text $end $comment more text $end ???'
));
}).not.to.throw();
expect(inst.info).to.deep.eq({ expect(inst.info).to.deep.eq({
comment: ' more text ', comment: ' more text ',
stack: [{}], stack: [{}],

View File

@ -1,118 +1,87 @@
'use strict'; 'use strict';
const fs = require('fs');
const path = require('path');
const expect = require('chai').expect; const expect = require('chai').expect;
const parser = require('../lib/parser.js'); const parser = require('../lib/parser.js');
const chopper = require('../lib/chopper.js');
describe('dump', () => { const expectaitions = [
{ id: '"}G', time: 100n, cmd: 14, value: 0n, mask: 0n },
{ id: '"}G', time: 200n, cmd: 15, value: 1n, 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: 1n, mask: 0n }
];
it('simple', done => { describe('napi dump', function () {
const inst = parser(); it('simple napi', done => {
const dump = []; fs.readFile(path.join(__dirname, 'dump.vcd'), function (err, src) {
['"}G', '{u', 'u)'] // array of all signal ids if (err) {
.map(id => throw new Error(err);
inst.change.on(id, (time, cmd, value, mask) => { }
dump.push({ const inst = parser();
id, const dump = [];
time, ['"}G', '{u', 'u)'] // array of all signal ids
cmd, .map(id =>
value, inst.change.on(id, (time, cmd, value, mask) => {
mask const row = {
}); id,
}) time: BigInt(time),
); cmd,
value,
mask
};
dump.push(row);
// console.log(row);
})
);
inst.on('finish', () => { inst.on('finish', () => {
expect(inst.getTime()).to.eq(316n); expect(inst.getTime()).to.eq(316n);
expect(dump).to.deep.eq([ expect(dump).to.deep.eq(expectaitions);
{ id: '"}G', time: 100, cmd: 14, value: 0n, mask: 0n }, done();
{ id: '"}G', time: 200, cmd: 15, value: 1n, mask: 0n }, });
{ id: '{u', time: 200, cmd: 30, value: 0xf0f0f0f0f0f0f0f0n, mask: 0xff00ff00ff00ff00n },
{ id: '"}G', time: 300, cmd: 14, value: 0n, mask: 0n }, for (const chunk of chopper(src, 100)) {
{ id: '{u', time: 300, cmd: 30, value: 0xf000000000000000n, mask: 0n }, // console.log('\u001b[31m[\u001b[0m' + chunk.toString() + '\u001b[31m]\u001b[0m');
{ id: '{u', time: 301, cmd: 30, value: 0x0f00000000000000n, mask: 0n }, inst.write(chunk);
{ id: '{u', time: 302, cmd: 30, value: 0x00f0000000000000n, mask: 0n }, }
{ id: '{u', time: 303, cmd: 30, value: 0x000f000000000000n, mask: 0n }, inst.end();
{ id: '{u', time: 304, cmd: 30, value: 0x0000f00000000000n, mask: 0n },
{ id: '{u', time: 305, cmd: 30, value: 0x00000f0000000000n, mask: 0n },
{ id: '{u', time: 306, cmd: 30, value: 0x000000f000000000n, mask: 0n },
{ id: '{u', time: 307, cmd: 30, value: 0x0000000f00000000n, mask: 0n },
{ id: '{u', time: 308, cmd: 31, value: 0x00000000f0000000n, mask: 0n },
{ id: '{u', time: 309, cmd: 30, value: 0x000000000f000000n, mask: 0n },
{ id: '{u', time: 310, cmd: 30, value: 0x0000000000f00000n, mask: 0n },
{ id: '{u', time: 311, cmd: 30, value: 0x00000000000f0000n, mask: 0n },
{ id: '{u', time: 312, cmd: 30, value: 0x000000000000f000n, mask: 0n },
{ id: '{u', time: 313, cmd: 30, value: 0x0000000000000f00n, mask: 0n },
{ id: '{u', time: 314, cmd: 30, value: 0x00000000000000f0n, mask: 0n },
{ id: '{u', time: 315, cmd: 30, value: 0x000000000000000fn, mask: 0n },
{ id: '"}G', time: 316, cmd: 15, value: 1n, mask: 0n }
]);
// console.log(dump);
done();
}); });
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
#100
0"}G
#200
1"}G
bzzzzxxxx11110000ZZZZXXXX11110000zzzzxxx`);
// break in the middle of the number scan
inst.write(`x11110000zzzzxxxx11110000 {u
#300
0"}G
b1111000000000000000000000000000000000000000000000000000000000000 {u
#301
b0000111100000000000000000000000000000000000000000000000000000000 {u
#302
b0000000011110000000000000000000000000000000000000000000000000000 {u
#303
b0000000000001111000000000000000000000000000000000000000000000000 {u
#304
b0000000000000000111100000000000000000000000000000000000000000000 {u
#305
b0000000000000000000011110000000000000000000000000000000000000000 {u
#306
b0000000000000000000000001111000000000000000000000000000000000000 {u
#307
b0000000000000000000000000000111100000000000000000000000000000000 {u
#308
B0000000000000000000000000000000011110000000000000000000000000000 {u
#309
b0000000000000000000000000000000000001111000000000000000000000000 {u
#310
b0000000000000000000000000000000000000000111100000000000000000000 {u
#311
b0000000000000000000000000000000000000000000011110000000000000000 {u
#312
b0000000000000000000000000000000000000000000000001111000000000000 {u
#313
b0000000000000000000000000000000000000000000000000000111100000000 {u
#314
b0000000000000000000000000000000000000000000000000000000011110000 {u
#315
b0000000000000000000000000000000000000000000000000000000000001111 {u
#316
1"}G
`);
inst.end();
}); });
}); });

View File

@ -1,120 +1,92 @@
'use strict'; 'use strict';
const fs = require('fs');
const path = require('path');
const expect = require('chai').expect; const expect = require('chai').expect;
const createVCD = require('../out/vcd.js'); const createVCD = require('../out/vcd.js');
const webVcdParser = require('../lib/web-vcd-parser.js'); const webVcdParser = require('../lib/web-vcd-parser.js');
const chopper = require('../lib/chopper.js');
describe('wasm dump', function () { const expectaitions = [
{ id: '"}G', time: 100n, cmd: 14, value: 0n, mask: 0n },
{ id: '"}G', time: 200n, cmd: 15, value: 1n, 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: 1n, mask: 0n }
];
it('simple wasm', function (done) { describe('wasm dump', () => {
createVCD().then(function (mod) { it('simple wasm', done => {
webVcdParser(mod).then(function (inst) { fs.readFile(path.join(__dirname, 'dump.vcd'), function (err, src) {
const dump = []; if (err) {
['"}G', '{u', 'u)'] // array of all signal ids throw new Error(err);
.map(id => }
inst.change.on(id, (time, cmd, value, mask) => { createVCD().then((mod) => {
dump.push({ webVcdParser(mod).then((inst) => {
id, const dump = [];
time, ['"}G', '{u', 'u)'] // array of all signal ids
cmd, .map(id =>
value, inst.change.on(id, (time, cmd, value, mask) => {
mask const row = {
}); id,
}) time,
); cmd,
value,
mask
};
dump.push(row);
// console.log(row);
})
);
inst.on('finish', () => { inst.on('finish', () => {
// expect(inst.getTime()).to.eq(316n); expect(inst.getTime()).to.eq(316n);
expect(dump).to.deep.eq([ // console.log(dump);
{ id: '"}G', time: 100n, cmd: 14, value: 0n, mask: 0n }, // expect(dump.length).to.eq(expectaitions.length);
{ id: '"}G', time: 200n, cmd: 15, value: 1n, mask: 0n }, expect(dump).to.deep.eq(expectaitions);
{ id: '{u', time: 200n, cmd: 30, value: 0xf0f0f0f0f0f0f0f0n, mask: 0xff00ff00ff00ff00n }, done();
{ id: '"}G', time: 300n, cmd: 14, value: 0n, mask: 0n }, });
{ id: '{u', time: 300n, cmd: 30, value: 0xf000000000000000n, mask: 0n }, const step = (Math.random() * 500) |0;
{ id: '{u', time: 301n, cmd: 30, value: 0x0f00000000000000n, mask: 0n }, for (const chunk of chopper(src, step)) {
{ id: '{u', time: 302n, cmd: 30, value: 0x00f0000000000000n, mask: 0n }, // console.log('\n\u001b[31m[\u001b[0m' + chunk.toString() + '\u001b[31m](\u001b[0m\n' + chunk.length + '\u001b[31m)\u001b[0m\n');
{ id: '{u', time: 303n, cmd: 30, value: 0x000f000000000000n, mask: 0n }, inst.write(chunk);
{ id: '{u', time: 304n, cmd: 30, value: 0x0000f00000000000n, mask: 0n }, }
{ id: '{u', time: 305n, cmd: 30, value: 0x00000f0000000000n, mask: 0n }, inst.end();
{ id: '{u', time: 306n, cmd: 30, value: 0x000000f000000000n, mask: 0n }, // console.log(step);
{ id: '{u', time: 307n, cmd: 30, value: 0x0000000f00000000n, mask: 0n },
{ id: '{u', time: 308n, cmd: 31, value: 0x00000000f0000000n, mask: 0n },
{ id: '{u', time: 309n, cmd: 30, value: 0x000000000f000000n, mask: 0n },
{ id: '{u', time: 310n, cmd: 30, value: 0x0000000000f00000n, mask: 0n },
{ id: '{u', time: 311n, cmd: 30, value: 0x00000000000f0000n, mask: 0n },
{ id: '{u', time: 312n, cmd: 30, value: 0x000000000000f000n, mask: 0n },
{ id: '{u', time: 313n, cmd: 30, value: 0x0000000000000f00n, mask: 0n },
{ id: '{u', time: 314n, cmd: 30, value: 0x00000000000000f0n, mask: 0n },
{ id: '{u', time: 315n, cmd: 30, value: 0x000000000000000fn, mask: 0n },
{ id: '"}G', time: 316n, cmd: 15, value: 1n, mask: 0n }
]);
done();
}); });
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
#100
0"}G
#200
1"}G
bzzzzxxxx11110000ZZZZXXXX11110000zzzzxxx`);
// break in the middle of the number scan
inst.write(`x11110000zzzzxxxx11110000 {u
#300
0"}G
b1111000000000000000000000000000000000000000000000000000000000000 {u
#301
b0000111100000000000000000000000000000000000000000000000000000000 {u
#302
b0000000011110000000000000000000000000000000000000000000000000000 {u
#303
b0000000000001111000000000000000000000000000000000000000000000000 {u
#304
b0000000000000000111100000000000000000000000000000000000000000000 {u
#305
b0000000000000000000011110000000000000000000000000000000000000000 {u
#306
b0000000000000000000000001111000000000000000000000000000000000000 {u
#307
b0000000000000000000000000000111100000000000000000000000000000000 {u
#308
B0000000000000000000000000000000011110000000000000000000000000000 {u
#309
b0000000000000000000000000000000000001111000000000000000000000000 {u
#310
b0000000000000000000000000000000000000000111100000000000000000000 {u
#311
b0000000000000000000000000000000000000000000011110000000000000000 {u
#312
b0000000000000000000000000000000000000000000000001111000000000000 {u
#313
b0000000000000000000000000000000000000000000000000000111100000000 {u
#314
b0000000000000000000000000000000000000000000000000000000011110000 {u
#315
b0000000000000000000000000000000000000000000000000000000000001111 {u
#316
1"}G
`);
inst.end();
}); });
}); });
}); });

10
vcd.c
View File

@ -123,9 +123,11 @@ METHOD(init) {
ASSERT_FUNCTION(args[1], state->triee) ASSERT_FUNCTION(args[1], state->triee)
ASSERT_OBJECT(args[2], state->info) ASSERT_OBJECT(args[2], state->info)
static char triggerString [4096] = " "; static char triggerString [4096] = {0};
static char tmpStr [4096] = " "; static char tmpStr [4096] = {0};
static char tmpStr2 [4096] = " "; static char tmpStr2 [4096] = {0};
static char timeStampStr [4096] = {0};
static char idStr [4096] = {0};
static uint64_t valueBuf [4096] = {}; static uint64_t valueBuf [4096] = {};
static uint64_t maskBuf [4096] = {}; static uint64_t maskBuf [4096] = {};
@ -134,6 +136,8 @@ METHOD(init) {
state->napi_env = env; state->napi_env = env;
state->tmpStr = tmpStr; state->tmpStr = tmpStr;
state->tmpStr2 = tmpStr2; state->tmpStr2 = tmpStr2;
state->timeStampStr = timeStampStr;
state->idStr = idStr;
state->value = valueBuf; state->value = valueBuf;
state->mask = maskBuf; state->mask = maskBuf;
state->time = INT64_MAX; state->time = INT64_MAX;

View File

@ -25,7 +25,7 @@ typedef void* napi_env;
} }
void strcopy(const unsigned char* p, const unsigned char* endp, unsigned char* dst) { void strcopy(const unsigned char* p, const unsigned char* endp, unsigned char* dst) {
unsigned char* src; const unsigned char* src;
src = p; src = p;
while (src < (endp - 1)) { while (src < (endp - 1)) {
*dst = *src; *dst = *src;
@ -35,40 +35,52 @@ void strcopy(const unsigned char* p, const unsigned char* endp, unsigned char* d
*dst = 0; *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 // FIXME use a better structure to match strings
int stringEq ( int stringEq (
const unsigned char* gold, // search pattern const unsigned char* i, // search pattern
const unsigned char* p, const unsigned char* p,
const unsigned char* endp const unsigned char* endp
) { ) {
if (gold[0] == 0) { if (*i == 0) {
return 1; return 1;
} }
unsigned char* i; const unsigned char* j;
unsigned char* j;
i = gold;
j = p;
while (1) { while (1) {
if (*i == ' ') { // end of search pattern j = p;
// printf("(%s|%s)", (char *)i, (char *)j);
if (*i == 0) { // end of search pattern
return 0; return 0;
} }
while (*i == *j) { // follow matching trail while (*i == *j) { // follow matching trail
if (*i == 0 && *j == 0) { // match zeros
return 1;
}
i++; i++;
j++; j++;
} }
if ((*i == ' ') && (j == (endp - 1))) { // exact match while (*i != 0) { // skip to the end of pattern word
return 1;
}
while (*i != ' ') { // skip to the end of pattern word
i++; i++;
} }
i++; i++;
j = p; // try another word
} }
} }
int commandSpan(vcd_parser_t* state, const unsigned char* p, const unsigned char* endp) { int commandSpan(vcd_parser_t* state, const unsigned char* p, const unsigned char* endp) {
#ifndef VCDWASM
napi_env env = state->napi_env; napi_env env = state->napi_env;
#endif
if (state->command == 5) { // $upscope if (state->command == 5) { // $upscope
state->stackPointer -= 1; state->stackPointer -= 1;
@ -100,6 +112,8 @@ int commandSpan(vcd_parser_t* state, const unsigned char* p, const unsigned char
} }
if (state->command == 8) { // $enddefinitions if (state->command == 8) { // $enddefinitions
*(char *)state->idStr = 0;
*(char *)state->timeStampStr = 0;
#ifndef VCDWASM #ifndef VCDWASM
napi_value status, undefined, eventName, eventPayload, return_val; napi_value status, undefined, eventName, eventPayload, return_val;
ASSERT(status, napi_create_string_latin1(env, "simulation", NAPI_AUTO_LENGTH, &status)) ASSERT(status, napi_create_string_latin1(env, "simulation", NAPI_AUTO_LENGTH, &status))
@ -191,15 +205,27 @@ int varNameSpan(vcd_parser_t* state, const unsigned char* p, const unsigned char
} }
int idSpan(vcd_parser_t* state, const unsigned char* p, const unsigned char* endp) { 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 #ifndef VCDWASM
napi_env env = state->napi_env; napi_env env = state->napi_env;
#endif #endif
const unsigned char* p = (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 >> 6) + 1; const int valueWords = (state->digitCount >> 6) + 1;
uint64_t* value = state->value; uint64_t* value = state->value;
uint64_t* mask = state->mask; uint64_t* mask = state->mask;
if (stringEq((state->trigger), p, endp)) { if (stringEq((state->trigger), p, endp)) {
const uint8_t command = state->command; const uint8_t command = state->command;
// printf("{id:'%s',cmd:%d}", (char *)p, command);
if (command == 14) { if (command == 14) {
value[0] = 0; value[0] = 0;
mask[0] = 0; mask[0] = 0;
@ -211,17 +237,17 @@ int idSpan(vcd_parser_t* state, const unsigned char* p, const unsigned char* end
#ifndef VCDWASM #ifndef VCDWASM
napi_value undefined, eventName, aTime, aCommand, aValue, aMask, return_val; napi_value undefined, eventName, aTime, aCommand, aValue, aMask, return_val;
ASSERT(undefined, napi_get_undefined(env, &undefined)) ASSERT(undefined, napi_get_undefined(env, &undefined))
ASSERT(eventName, napi_create_string_latin1(env, (char*)p, (endp - p - 1), &eventName)) ASSERT(eventName, napi_create_string_latin1(env, (char*)p, NAPI_AUTO_LENGTH, &eventName))
ASSERT(aTime, napi_create_int64(env, state->time, &aTime)) ASSERT(aTime, napi_create_int64(env, state->time, &aTime))
ASSERT(aCommand, napi_create_int32(env, command, &aCommand)) ASSERT(aCommand, napi_create_int32(env, command, &aCommand))
ASSERT(aValue, napi_create_bigint_words(env, 0, valueWords, value, &aValue)) ASSERT(aValue, napi_create_bigint_words(env, 0, valueWords, value, &aValue))
ASSERT(aMask, napi_create_bigint_words(env, 0, valueWords, mask, &aMask)) ASSERT(aMask, napi_create_bigint_words(env, 0, valueWords, mask, &aMask))
napi_value* argv[] = {&eventName, &aTime, &aCommand, &aValue, &aMask}; napi_value* argv[] = {&eventName, &aTime, &aCommand, &aValue, &aMask};
ASSERT(state->triee, napi_call_function(env, undefined, state->triee, 5, *argv, &return_val)) ASSERT(state->triee, napi_call_function(env, undefined, state->triee, 5, *argv, &return_val))
// printf("<id='%s'>", (char *)p);
#else #else
strcopy(p, endp, state->tmpStr); // strcopy(p, endp, state->tmpStr);
emit_triee(state->tmpStr, state->time, command, valueWords, value, mask); emit_triee((char *)p, state->time, command, valueWords, value, mask);
#endif #endif
} }
for (int i = 0; i < valueWords; i++) { for (int i = 0; i < valueWords; i++) {
@ -229,9 +255,12 @@ int idSpan(vcd_parser_t* state, const unsigned char* p, const unsigned char* end
mask[i] = 0; mask[i] = 0;
} }
state->digitCount = 0; state->digitCount = 0;
*(char *)state->idStr = 0;
return 0; return 0;
} }
int onDigit( int onDigit(
vcd_parser_t* state, vcd_parser_t* state,
const unsigned char* p, const unsigned char* p,
@ -270,8 +299,17 @@ int onRecover(
return 0; return 0;
} }
int timeSpan(vcd_parser_t* state, const unsigned char* p, const unsigned char* endp) { int timeSpan(vcd_parser_t* state, const unsigned char* p, const unsigned char* endp) {
int64_t time = strtoul((const char *)p, (char **)&endp, 10); 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) { if (state->time == INT64_MAX) {
#ifndef VCDWASM #ifndef VCDWASM
napi_env env = state->napi_env; napi_env env = state->napi_env;
@ -283,5 +321,6 @@ int timeSpan(vcd_parser_t* state, const unsigned char* p, const unsigned char* e
#endif #endif
} }
state->time = time; state->time = time;
*(char *)state->timeStampStr = 0;
return 0; return 0;
} }

View File

@ -123,9 +123,11 @@ int init(
state->lifee = 0; state->lifee = 0;
state->triee = 0; state->triee = 0;
static char triggerString [4096] = " "; static char triggerString [4096] = {0};
static char tmpStr [4096] = " "; static char tmpStr [4096] = {0};
static char tmpStr2 [4096] = " "; static char tmpStr2 [4096] = {0};
static char timeStampStr [4096] = {0};
static char idStr [4096] = {0};
static uint64_t valueBuf [4096] = {}; static uint64_t valueBuf [4096] = {};
static uint64_t maskBuf [4096] = {}; static uint64_t maskBuf [4096] = {};
@ -134,10 +136,12 @@ int init(
state->napi_env = 0; state->napi_env = 0;
state->tmpStr = tmpStr; state->tmpStr = tmpStr;
state->tmpStr2 = tmpStr2; state->tmpStr2 = tmpStr2;
state->timeStampStr = timeStampStr;
state->idStr = idStr;
state->value = valueBuf; state->value = valueBuf;
state->mask = maskBuf; state->mask = maskBuf;
state->digitCount = 0;
state->time = INT64_MAX; state->time = INT64_MAX;
state->digitCount = 0;
set_property_string("status", "declaration"); set_property_string("status", "declaration");
@ -157,7 +161,8 @@ int32_t execute(
externalJsMethodOne* f1, externalJsMethodOne* f1,
externalJsSetProperty* sfn, externalJsSetProperty* sfn,
externalJsGetProperty* gfn, externalJsGetProperty* gfn,
char* p char* p,
const int plen
) { ) {
// cout << "execute got " << p << "\n"; // cout << "execute got " << p << "\n";
@ -167,7 +172,9 @@ int32_t execute(
externalZero = f0; externalZero = f0;
externalOne = f1; externalOne = f1;
const size_t plen = strlen(p); // const size_t plen = strlen(p);
// printf("<chunk len|%d>\n", plen);
const int32_t error = vcd_parser_execute(state, p, p + plen); const int32_t error = vcd_parser_execute(state, p, p + plen);
@ -175,9 +182,18 @@ int32_t execute(
} }
int setTrigger(const int context, char* triggerString) { int setTrigger(const int context, char* triggerString) {
state->trigger = malloc(strlen(triggerString)); int triggerStringLen = strlen((char *)triggerString) - 1;
strcpy((char*)state->trigger, triggerString); // state->trigger = malloc(strlen(triggerString));
// cout << "setTrigger() got " << triggerString << "\n"; char* p = (char *)state->tmpStr;
for (int i = 0; i < triggerStringLen; i++) {
char c = *(triggerString + i);
if (c == 32) {
c = 0;
}
*(p + i) = c;
}
// strcpy((char*)state->trigger, triggerString);
// cout << "[" << triggerString << "|" << p << "\n";
return 0; return 0;
} }