Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16,943 changes: 16,883 additions & 60 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"3vl": "^1.0.0",
"babel-polyfill": "^6.26.0",
"dagre": "^0.8.5",
"elkjs": "^0.7.1",
"elkjs": "^0.7.3-dev",
"fastpriorityqueue": "^0.6.4",
"graphlib": "^2.1.8",
"jointjs": "^3.4.4",
Expand Down
10 changes: 5 additions & 5 deletions src/cells/base.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,10 @@ export const Wire = joint.shapes.standard.Link.define('Wire', {
},
wrapper: {
stroke: 'red'
},
wirelabel: {
fill: 'black',
fontSize: '8pt'
}
},

Expand All @@ -396,11 +400,7 @@ export const Wire = joint.shapes.standard.Link.define('Wire', {
}
],
attrs: {
label: {
text: this.get('netname'),
fill: 'black',
fontSize: '8pt'
}
label: _.merge({ text: this.get('netname') }, this.get('attrs').wirelabel)
},
position: {
distance: 0.5
Expand Down
44 changes: 24 additions & 20 deletions src/cells/fsm.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -178,27 +178,12 @@ export const FSM = Box.define('FSM', {
}
return { out: next_output() };
},
markup: Box.prototype.markup.concat(Box.prototype.markupZoom),
_gateParams: Box.prototype._gateParams.concat(['bits', 'polarity', 'states', 'init_state', 'trans_table']),
_unsupportedPropChanges: Box.prototype._unsupportedPropChanges.concat(['bits', 'polarity', 'states', 'init_state', 'trans_table']),
_presentationParams: Box.prototype._presentationParams.concat(['current_state', 'next_trans'])
});

export const FSMView = BoxView.extend({
_autoResizeBox: true,
events: {
"click foreignObject.tooltip": "stopprop",
"mousedown foreignObject.tooltip": "stopprop",
"touchstart foreignObject.tooltip": "stopprop", // make sure the input receives focus
"click a.zoom": "_displayEditor"
},
_displayEditor(evt) {
evt.stopPropagation();
createEditor() {
const div = $('<div>', {
title: "FSM: " + this.model.get('label')
title: "FSM: " + this.get('label')
}).appendTo('html > body');
const pdiv = $('<div>').appendTo(div);
const graph = this.model.fsmgraph;
const graph = this.fsmgraph;
const paper = new joint.dia.Paper({
el: pdiv,
model: graph
Expand All @@ -218,10 +203,29 @@ export const FSMView = BoxView.extend({
paper.fitToContent({ padding: 30, allowNewOrigin: 'any' });
});
paper.fitToContent({ padding: 30, allowNewOrigin: 'any' });
this.paper.trigger('open:fsm', div, () => {
return { div, close: () => {
paper.remove();
div.remove();
});
}};
},
markup: Box.prototype.markup.concat(Box.prototype.markupZoom),
_gateParams: Box.prototype._gateParams.concat(['bits', 'polarity', 'states', 'init_state', 'trans_table']),
_unsupportedPropChanges: Box.prototype._unsupportedPropChanges.concat(['bits', 'polarity', 'states', 'init_state', 'trans_table']),
_presentationParams: Box.prototype._presentationParams.concat(['current_state', 'next_trans'])
});

export const FSMView = BoxView.extend({
_autoResizeBox: true,
events: {
"click foreignObject.tooltip": "stopprop",
"mousedown foreignObject.tooltip": "stopprop",
"touchstart foreignObject.tooltip": "stopprop", // make sure the input receives focus
"click a.zoom": "_displayEditor"
},
_displayEditor(evt) {
evt.stopPropagation();
const editor = this.model.createEditor();
this.paper.trigger('open:fsm', editor.div, editor.close, { model: this.model });
return false;
}
});
Expand Down
93 changes: 48 additions & 45 deletions src/cells/memory.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -257,44 +257,30 @@ export const Memory = Box.define('Memory', {
params.memdata = this.memdata.toJSON();
return params;
},
_gateParams: Box.prototype._gateParams.concat(['bits', 'abits', 'rdports', 'wrports', 'words', 'offset']),
_unsupportedPropChanges: Box.prototype._unsupportedPropChanges.concat(['bits', 'abits', 'rdports', 'wrports', 'words', 'offset']),
_operationHelpers: Box.prototype._operationHelpers.concat(['_memrdports', '_memwrports', '_memports', '_calcaddr'])
});
export const MemoryView = BoxView.extend({
_autoResizeBox: true,
events: {
"click foreignObject.tooltip": "stopprop",
"mousedown foreignObject.tooltip": "stopprop",
"touchstart foreignObject.tooltip": "stopprop", // make sure the input receives focus
"click a.zoom": "_displayEditor"
},
_displayEditor(evt) {
evt.stopPropagation();
const model = this.model;
const display3vl = model.graph._display3vl;
createEditor() {
const display3vl = this.graph._display3vl;
const div = $('<div>', {
title: "Memory contents: " + model.get('label')
title: "Memory contents: " + this.get('label')
}).appendTo('html > body');
div.append($(
'<div class="btn-toolbar" role="toolbar">' +
'<div class="btn-group mr-2" role="group">' +
'<button name="prev" type="button" class="btn btn-secondary" title="Previous page">←</button>' +
'<button name="next" type="button" class="btn btn-secondary" title="Next page">→</button>' +
'</div>' +
'</div>' +
// '<div class="btn-group mr-2" role="group">' +
// '<button type="button" class="btn btn-secondary" title="Load contents">Load</button>' +
// '<button type="button" class="btn btn-secondary" title="Save contents">Save</button>' +
// '</div>' +
// '</div>' +
'<div class="input-group">' +
help.baseSelectMarkupHTML(display3vl, model.get('bits'), 'hex') +
help.baseSelectMarkupHTML(display3vl, this.get('bits'), 'hex') +
'</div>' +
'</div>' +
'<table class="memeditor">' +
'</table>'));
const words = model.get('words');
const memdata = model.memdata;
const ahex = Math.ceil(model.get('abits')/4);
const words = this.get('words');
const memdata = this.memdata;
const ahex = Math.ceil(this.get('abits')/4);
const rows = 8;
let columns, address = 0;
const get_numbase = () => div.find('select[name=base]').val();
Expand All @@ -304,27 +290,27 @@ export const MemoryView = BoxView.extend({
return div.find('table tr:nth-child('+(r+1)+') td:nth-child('+(c+2)+') input');
}
const clearMarkings = (sigs) => {
for (const [portname, port] of model._memrdports()) {
getCell(model._calcaddr(sigs[portname + 'addr'])).removeClass('isread');
for (const [portname, port] of this._memrdports()) {
getCell(this._calcaddr(sigs[portname + 'addr'])).removeClass('isread');
}
for (const [portname, port] of model._memwrports()) {
getCell(model._calcaddr(sigs[portname + 'addr'])).removeClass('iswrite');
for (const [portname, port] of this._memwrports()) {
getCell(this._calcaddr(sigs[portname + 'addr'])).removeClass('iswrite');
}
}
const displayMarkings = (sigs) => {
for (const [portname, port] of model._memrdports()) {
getCell(model._calcaddr(sigs[portname + 'addr'])).addClass('isread');
for (const [portname, port] of this._memrdports()) {
getCell(this._calcaddr(sigs[portname + 'addr'])).addClass('isread');
}
for (const [portname, port] of model._memwrports()) {
getCell(model._calcaddr(sigs[portname + 'addr'])).addClass('iswrite');
for (const [portname, port] of this._memwrports()) {
getCell(this._calcaddr(sigs[portname + 'addr'])).addClass('iswrite');
}
}
const updateStuff = () => {
const numbase = get_numbase();
div.find('button[name=prev]').prop('disabled', address <= 0);
div.find('button[name=next]').prop('disabled', address + rows * columns >= words);
let row = div.find('table tr:first-child');
const memdata = model.memdata;
const memdata = this.memdata;
for (let r = 0; r < rows; r++, row = row.next()) {
if (address + r * columns >= words) break;
const addrs = (address + r * columns).toString(16);
Expand All @@ -337,12 +323,12 @@ export const MemoryView = BoxView.extend({
.removeClass('invalid');
}
}
displayMarkings(model.get('inputSignals'));
displayMarkings(this.get('inputSignals'));
};
const redraw = () => {
const numbase = get_numbase();
const ptrn = display3vl.pattern(numbase);
const ds = display3vl.size(numbase, model.get('bits'));
const ds = display3vl.size(numbase, this.get('bits'));
columns = Math.min(words, 16, Math.ceil(32/ds));
address = Math.max(0, Math.min(words - rows * columns, address));
const table = div.find('table');
Expand All @@ -368,12 +354,12 @@ export const MemoryView = BoxView.extend({
redraw();
div.find("select[name=base]").on('change', redraw);
div.find("button[name=prev]").on('click', () => {
clearMarkings(model.get('inputSignals'));
clearMarkings(this.get('inputSignals'));
address = Math.max(0, address - rows * columns);
updateStuff();
});
div.find("button[name=next]").on('click', () => {
clearMarkings(model.get('inputSignals'));
clearMarkings(this.get('inputSignals'));
address = Math.min(words - rows * columns, address + rows * columns);
updateStuff();
});
Expand All @@ -383,11 +369,11 @@ export const MemoryView = BoxView.extend({
const c = target.closest('td').index() - 1;
const r = target.closest('tr').index();
const addr = address + r * columns + c;
const bits = model.get('bits');
const bits = this.get('bits');
if (display3vl.validate(numbase, evt.target.value, bits)) {
const val = display3vl.read(numbase, evt.target.value, bits);
memdata.set(addr, val);
model.trigger('manualMemChange', model, addr, val);
this.trigger('manualMemChange', this, addr, val);
target.removeClass('invalid');
} else {
target.addClass('invalid');
Expand All @@ -403,16 +389,33 @@ export const MemoryView = BoxView.extend({
setTimeout(() => { z.addClass('flash') }, 10);
};
const input_change_cb = (gate, sigs) => {
clearMarkings(model.previous('inputSignals'));
clearMarkings(this.previous('inputSignals'));
displayMarkings(sigs);
};
model.on("memChange", mem_change_cb);
model.on("change:inputSignals", input_change_cb);
this.paper.trigger('open:memorycontent', div, () => {
this.on("memChange", mem_change_cb);
this.on("change:inputSignals", input_change_cb);
return { div, close: () => {
div.remove();
model.off("memChange", mem_change_cb);
model.off("change:inputSignals", input_change_cb);
});
this.off("memChange", mem_change_cb);
this.off("change:inputSignals", input_change_cb);
}};
},
_gateParams: Box.prototype._gateParams.concat(['bits', 'abits', 'rdports', 'wrports', 'words', 'offset']),
_unsupportedPropChanges: Box.prototype._unsupportedPropChanges.concat(['bits', 'abits', 'rdports', 'wrports', 'words', 'offset']),
_operationHelpers: Box.prototype._operationHelpers.concat(['_memrdports', '_memwrports', '_memports', '_calcaddr'])
});
export const MemoryView = BoxView.extend({
_autoResizeBox: true,
events: {
"click foreignObject.tooltip": "stopprop",
"mousedown foreignObject.tooltip": "stopprop",
"touchstart foreignObject.tooltip": "stopprop", // make sure the input receives focus
"click a.zoom": "_displayEditor"
},
_displayEditor(evt) {
evt.stopPropagation();
const editor = this.model.createEditor();
this.paper.trigger('open:memorycontent', editor.div, editor.close, { model: this.model });
return false;
}
});
Expand Down
6 changes: 4 additions & 2 deletions src/cells/subcircuit.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ export const Subcircuit = Box.define('Subcircuit', {
}
}, {
initialize() {
this.bindAttrToProp('text.type/text', 'celltype');
if (!this.get('disp_celltype'))
this.set('disp_celltype', this.get('celltype'))
this.bindAttrToProp('text.type/text', 'disp_celltype');

const graph = this.get('graph');
console.assert(graph instanceof joint.dia.Graph);
Expand Down Expand Up @@ -102,7 +104,7 @@ export const Subcircuit = Box.define('Subcircuit', {
selector: 'type'
}
], Box.prototype.markupZoom),
_gateParams: Box.prototype._gateParams.concat(['celltype']),
_gateParams: Box.prototype._gateParams.concat(['celltype', 'disp_celltype']),
_unsupportedPropChanges: Box.prototype._unsupportedPropChanges.concat(['celltype'])
});

Expand Down
53 changes: 50 additions & 3 deletions src/circuit.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,19 @@ export class HeadlessCircuit {
for (const elem of graph.getElements()) {
const args = ret.devices[elem.get('id')] = elem.getGateParams(layout);
if (!laid_out) delete args.position;
if (elem instanceof this._cells.Subcircuit && !subcircuits[elem.get('celltype')]) {
subcircuits[elem.get('celltype')] = fromGraph(elem.get('graph'));
if (elem instanceof this._cells.Subcircuit) {
const celltype = elem.get('celltype');
const subcircuit = {
dev: args,
graph: fromGraph(elem.get('graph'))
};
const prev_sub = subcircuits[celltype];
if (!prev_sub) {
subcircuits[celltype] = [subcircuit];
}
else {
prev_sub.push(subcircuit);
}
}
}
for (const elem of graph.getLinks()) {
Expand All @@ -307,7 +318,43 @@ export class HeadlessCircuit {
return ret;
}
const ret = fromGraph(this._graph);
ret.subcircuits = subcircuits;
ret.subcircuits = {};
for (const celltype in subcircuits) {
const subs = subcircuits[celltype];
const nsubs = subs.length;
if (nsubs == 1) {
// We check for conflict of generated names with
// both the original names and the new names
// so it's guaranteed that none of the original names conflict
// with the generated names
console.assert(!(celltype in ret.subcircuits));
ret.subcircuits[celltype] = subs[0].graph;
continue;
}
let cnt = -1;
const gen_name = () => {
while (true) {
const id = cnt++;
// Use the original name for the first one to keep the file closer
// to the old one.
if (id == -1)
return celltype;
const name = `${celltype}$${id}`;
if (name in subcircuits || name in ret.subcircuits)
continue;
return name;
}
};
for (let i = 0; i < nsubs; i++) {
const sub = subs[i];
// Rename, assign to return value, and fix the reference (celltype)
// in the device tree.
sub.dev.celltype = gen_name();
if (!sub.dev.disp_celltype && sub.dev.celltype !== celltype)
sub.dev.disp_celltype = celltype;
ret.subcircuits[sub.dev.celltype] = sub.graph;
}
}
return ret;
}
waitForWire(wire, trigger) {
Expand Down
4 changes: 2 additions & 2 deletions src/engines/synch.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import * as help from '../help.mjs';
import { BaseEngine } from './base.mjs';

export class SynchEngine extends BaseEngine {
constructor(graph, {cells}) {
constructor(graph, {cells, initTick}) {
super(graph);
this._queue = new Map();
this._pq = new FastPriorityQueue();
this._tick = 0;
this._tick = initTick | 0;
this._cells = cells;
this._monitorChecks = new Map();
this._alarms = new Map();
Expand Down
3 changes: 3 additions & 0 deletions src/engines/worker-worker.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@ class WorkerEngineWorker {
}, 25);
this._updater = null;
}
setTick(tick) {
this._tick = tick | 0;
}
interval(ms) {
this._interval = ms;
}
Expand Down
Loading