UNPKG

cirsim

Version:

Cirsim Circuit Simulator

204 lines (160 loc) 5.15 kB
import {Util} from '../Utility/Util'; import {Component} from '../Component'; import {ComponentPropertiesDlg} from "../Dlg/ComponentPropertiesDlg"; import {PaletteImage} from '../Graphics/PaletteImage'; /** * Component: Simple arbitrary bit size counter. */ export const Counter = function() { Component.call(this); this.height = 98; this.width = 48; const w2 = this.width / 2; const h2 = this.height / 2; this.value = 0; this.size = 16; this.lastClk = false; const clk = this.addIn(0, -h2, 8); clk.orientation = 'n'; clk.clock = true; this.addIn(-w2, -24, 8, "UP"); const res = this.addIn(0, h2, 8, "R"); res.orientation = 's'; this.addOut(w2, -24, 8, "C").bus = true; this.set(0); }; Counter.prototype = Object.create(Component.prototype); Counter.prototype.constructor = Counter; Counter.prototype.prefix = "C"; Counter.type = "Counter"; ///< Name to use in files Counter.label = "Counter"; ///< Label for the palette Counter.desc = "Simple Counter"; ///< Description for the palette Counter.description = `<h2>Simple Counter</h2><p>Supports up and down counting for arbitrary bit sizes. C is the count output. The optional UP input controls the counting direction. True means up counting. If not connected, the counter counts up. R is an asynchronous reset. The counter increments or decrements on the clock leading edge.</p>`; Counter.order = 406; Counter.help = 'Counter'; /** * Compute the gate result * @param state */ Counter.prototype.compute = function(state) { if(state[2]) { // Reset! this.set(0); } else { if(state[0] && !this.lastClk) { // Clock leading edge if(state[1] !== false) { this.set(this.value + 1); } else { this.set(this.value - 1); } } } this.lastClk = state[0]; }; Counter.prototype.set = function(value) { this.value = value; let and = 0; for(let i=0; i<this.size; i++) { and = (and << 1) | 1; } this.value &= and; let o = this.value; let data = []; for(let i=0; i<this.size; i++) { data.push((o & 1) == 1); o >>= 1; } this.outs[0].set(data); } /** * Clone this component object. * @returns {Counter} */ Counter.prototype.clone = function() { const copy = new Counter(); copy.size = this.size; copy.copyFrom(this); return copy; }; /** * Load this object from an object converted from JSON * @param obj Object from JSON */ Counter.prototype.load = function(obj) { this.size = obj["size"]; Component.prototype.load.call(this, obj); this.set(0); }; /** * Create a save object suitable for conversion to JSON for export. * @returns {*} */ Counter.prototype.save = function() { const obj = Component.prototype.save.call(this); obj.size = this.size; return obj; }; /** * Draw component object. * @param context Display context * @param view View object */ Counter.prototype.draw = function(context, view) { this.selectStyle(context, view); this.drawBox(context); let y = this.y; context.font = '14px "Lucida Console", Monaco, monospace'; context.textAlign = "center"; // Where does the text start? if(this.size > 12) { context.fillText(Util.toHex(this.value, 4), this.x, y); } else if(this.size > 8) { context.fillText(Util.toHex(this.value, 3), this.x, y); } else if(this.size > 4) { context.fillText(Util.toHex(this.value, 2), this.x, y); } else { context.fillText(Util.toBinary(this.value, this.size), this.x, y); } y += 25; context.font = "14px Times"; context.fillText("counter", this.x, y); this.drawIO(context, view); }; Counter.prototype.properties = function(main) { const dlg = new ComponentPropertiesDlg(this, main); const id = dlg.uniqueId(); let html = `<div class="control1 center gap"><label for="${id}">Size in bits: </label> <input class="number" type="text" name="${id}" id="${id}" value="${this.size}"></div>`; dlg.extra(html, () => { const size = parseInt(document.getElementById(id).value); if(isNaN(size) || size < 2 || size > 16) { document.getElementById(id).select(); return "Must be an integer from 2 to 16"; } return null; }, () => { this.size = parseInt(document.getElementById(id).value); this.set(this.value); }); dlg.open(); }; /** * Create a PaletteImage object for a the component */ Counter.paletteImage = function() { const pi = new PaletteImage(60, 44); pi.box(16, 32); pi.io(8, -8, 'e'); pi.io(-8, -8, 'w'); // Reset pi.io(0, 16, 's'); // Clock pi.clock(0, -16, 'n'); pi.drawText("0000", 0, 2, "6px Times"); pi.drawText("Counter", 0, 10, "4px Times"); return pi; }