diff --git a/src/cells/base.mjs b/src/cells/base.mjs index 70e0880..1ad53ab 100644 --- a/src/cells/base.mjs +++ b/src/cells/base.mjs @@ -114,6 +114,18 @@ export const Gate = joint.shapes.basic.Generic.define('Gate', { this.attr(attr, this.get(prop)); this.on('change:' + prop, (_, val) => this.attr(attr, val)); }, + setAttrs(attrs, path) { + path = path ?? []; + + for (const [attrName, val] of Object.entries(attrs)) { + const attrPath = path.concat(attrName); + if (typeof val === 'object') { + this.setAttrs(val, attrPath); + } else { + this.attr(attrPath.join('/'), val); + } + } + }, /* * Private methods. diff --git a/src/circuit.mjs b/src/circuit.mjs index 1d5525d..381e70f 100644 --- a/src/circuit.mjs +++ b/src/circuit.mjs @@ -12,68 +12,73 @@ import * as transform from './transform.mjs'; import { SynchEngine } from './engines/synch.mjs'; export { cells, tools, engines, transform }; - + +const CELL_TYPES = { + '$not': 'Not', + '$and': 'And', + '$nand': 'Nand', + '$or': 'Or', + '$nor': 'Nor', + '$xor': 'Xor', + '$xnor': 'Xnor', + '$reduce_and': 'AndReduce', + '$reduce_nand': 'NandReduce', + '$reduce_or': 'OrReduce', + '$reduce_nor': 'NorReduce', + '$reduce_xor': 'XorReduce', + '$reduce_xnor': 'XnorReduce', + '$reduce_bool': 'OrReduce', + '$logic_not': 'NorReduce', + '$repeater': 'Repeater', + '$shl': 'ShiftLeft', + '$shr': 'ShiftRight', + '$lt': 'Lt', + '$le': 'Le', + '$eq': 'Eq', + '$ne': 'Ne', + '$gt': 'Gt', + '$ge': 'Ge', + '$constant': 'Constant', + '$neg': 'Negation', + '$pos': 'UnaryPlus', + '$add': 'Addition', + '$sub': 'Subtraction', + '$mul': 'Multiplication', + '$div': 'Division', + '$mod': 'Modulo', + '$pow': 'Power', + '$mux': 'Mux', + '$pmux': 'Mux1Hot', + '$dff': 'Dff', + '$mem': 'Memory', + '$fsm': 'FSM', + '$clock': 'Clock', + '$button': 'Button', + '$lamp': 'Lamp', + '$numdisplay': 'NumDisplay', + '$numentry': 'NumEntry', + '$input': 'Input', + '$output': 'Output', + '$busgroup': 'BusGroup', + '$busungroup': 'BusUngroup', + '$busslice': 'BusSlice', + '$zeroextend': 'ZeroExtend', + '$signextend': 'SignExtend', + '$display7': 'Display7', +}; + +export function getCellTypeStr(tp) { + return CELL_TYPES[tp] ?? null; +} + export function getCellType(tp) { - const types = { - '$not': cells.Not, - '$and': cells.And, - '$nand': cells.Nand, - '$or': cells.Or, - '$nor': cells.Nor, - '$xor': cells.Xor, - '$xnor': cells.Xnor, - '$reduce_and': cells.AndReduce, - '$reduce_nand': cells.NandReduce, - '$reduce_or': cells.OrReduce, - '$reduce_nor': cells.NorReduce, - '$reduce_xor': cells.XorReduce, - '$reduce_xnor': cells.XnorReduce, - '$reduce_bool': cells.OrReduce, - '$logic_not': cells.NorReduce, - '$repeater': cells.Repeater, - '$shl': cells.ShiftLeft, - '$shr': cells.ShiftRight, - '$lt': cells.Lt, - '$le': cells.Le, - '$eq': cells.Eq, - '$ne': cells.Ne, - '$gt': cells.Gt, - '$ge': cells.Ge, - '$constant': cells.Constant, - '$neg': cells.Negation, - '$pos': cells.UnaryPlus, - '$add': cells.Addition, - '$sub': cells.Subtraction, - '$mul': cells.Multiplication, - '$div': cells.Division, - '$mod': cells.Modulo, - '$pow': cells.Power, - '$mux': cells.Mux, - '$pmux': cells.Mux1Hot, - '$dff': cells.Dff, - '$mem': cells.Memory, - '$fsm': cells.FSM, - '$clock': cells.Clock, - '$button': cells.Button, - '$lamp': cells.Lamp, - '$numdisplay': cells.NumDisplay, - '$numentry': cells.NumEntry, - '$input': cells.Input, - '$output': cells.Output, - '$busgroup': cells.BusGroup, - '$busungroup': cells.BusUngroup, - '$busslice': cells.BusSlice, - '$zeroextend': cells.ZeroExtend, - '$signextend': cells.SignExtend, - '$display7': cells.Display7, - }; - if (tp in types) return types[tp]; - else return cells.Subcircuit; + return cells[getCellTypeStr(tp)] ?? cells.Subcircuit; } - + export class HeadlessCircuit { - constructor(data, {cellsNamespace = {}, engine = SynchEngine, engineOptions = {}} = {}) { + constructor(data, {cellsNamespace = {}, engine = SynchEngine, engineOptions = {}, cellAttributes = {}} = {}) { this._cells = Object.assign(cells, cellsNamespace); + this._cellAttributes = cellAttributes; this._display3vl = new Display3vl(); this._display3vl.addDisplay(new help.Display3vlASCII()); this._graph = this._makeGraph(data, data.subcircuits); @@ -164,6 +169,14 @@ export class HeadlessCircuit { if (cellType == this._cells.Subcircuit) cellArgs.graph = this._makeGraph(subcircuits[dev.celltype], subcircuits, { nested: true }); const cell = new cellType(cellArgs); + const cellAttrs = _.merge( + {}, + this._cellAttributes[cell.get('type')], + this._cellAttributes[cell.get('celltype')] + ); + if (cellAttrs) { + cell.setAttrs(cellAttrs); + } graph.addCell(cell); } for (const conn of data.connectors) { diff --git a/src/index.mjs b/src/index.mjs index a4015fa..427bd3d 100644 --- a/src/index.mjs +++ b/src/index.mjs @@ -14,7 +14,7 @@ import * as cells from './cells.mjs'; import * as engines from './engines.mjs'; import * as tools from './tools.mjs'; import * as transform from './transform.mjs'; -import { HeadlessCircuit, getCellType } from './circuit.mjs'; +import { HeadlessCircuit, getCellTypeStr, getCellType } from './circuit.mjs'; import { BrowserSynchEngine } from './engines/browsersynch.mjs'; import { MonitorView, Monitor } from './monitor.mjs'; import { IOPanelView } from './iopanel.mjs'; @@ -26,7 +26,7 @@ import './style.css'; // see https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver#Browser_compatibility import ResizeObserver from 'resize-observer-polyfill'; -export { HeadlessCircuit, getCellType, cells, tools, engines, transform, MonitorView, Monitor, IOPanelView }; +export { HeadlessCircuit, getCellTypeStr, getCellType, cells, tools, engines, transform, MonitorView, Monitor, IOPanelView }; export const paperOptions = { async: true,