UNPKG

cirsim

Version:

Cirsim Circuit Simulator

271 lines (229 loc) 7.5 kB
import {Component} from '../Component'; import {ComponentPropertiesDlg} from '../Dlg/ComponentPropertiesDlg'; import {PaletteImage} from "../Graphics/PaletteImage"; /** * Component: Extend * The Extend component extends an input bus to * a larger output size. * * A common use is extending a 12 bit immediate value to * 16 or 32 bits. * * @constructor * @property {number} height Component height * @property {number} width Component width * @property {number} outputSize Number of output bits * @property {boolean} arithmetic Sign extend expansion */ export const Extend = function() { Component.call(this); // // Object properties // Object.defineProperties(this, { // Component height height: { value: 32 }, /** Component width */ width: { value: 96 }, outputSize: { value: 16, writable: true }, arithmetic: { value: false, writable: true }, shift: { value: 0, writable: true } }); // One input this.addIn(-48, 8, 16).bus=true; // One output this.addOut(48, 0, 16).bus=true; }; Extend.prototype = Object.create(Component.prototype); Extend.prototype.constructor = Extend; Extend.prototype.prefix = null; Extend.type = "Extend"; ///< Name to use in files Extend.label = "Extend"; ///< Label for the palette Extend.desc = "Bus Extend"; ///< Description for the palette Extend.description = `<h2>Extend</h2><p>The Extend component extends a bus to a larger size. A common use is to extend an immediate value from an instruction to 16 or 32 bits.</p> <p>The output can be optionally shifted left by a fixed number of bits.</p>`; Extend.order = 311; Extend.help = 'extend'; /** * Clone this component object. * @returns {Extend} */ Extend.prototype.clone = function() { const copy = new Extend(); copy.copyFrom(this); copy.outputSize = this.outputSize; copy.arithmetic = this.arithmetic; copy.shift = this.shift; return copy; }; /** * Compute. * * Force the output to the current set value. * Since there are no inputs, state is ignored. * @param state */ Extend.prototype.compute = function(state) { // Test for the state undefined if(state[0] === undefined) { this.outs[0].set(undefined); return; } // Bus output const value = []; let i=0; // Shift amount for( ; i<this.shift; i++) { value.push(0); } // Move the bits let inBit = 0; let lastBit = 0; for( ; inBit < state[0].length && i<this.outputSize; inBit++, i++) { value.push(state[0][inBit]); lastBit = state[0][inBit]; } // Expand for( ; i<this.outputSize; i++) { value.push(this.arithmetic ? lastBit : 0); } this.outs[0].set(value); }; /** * Draw the component. * @param context Display context * @param view View object */ Extend.prototype.draw = function(context, view) { // Component background this.outlinePath(context); context.fillStyle = "#ffffff"; context.fill(); // Select the style to draw the rest this.selectStyle(context, view); // Box for the component //this.outlinePath(context); context.stroke(); context.font = "14px Times"; context.textAlign = "center"; context.fillText("Extend", this.x, this.y + 10); this.drawIO(context, view); }; Extend.prototype.outlinePath = function(context) { const leftX = this.x - this.width/2 - 0.5; const rightX = this.x + this.width/2 + 0.5; const topY = this.y - this.height/2 - 0.5; const leftTopY = this.y - 0.5; const botY = this.y + this.height/2 + 0.5; context.beginPath(); context.moveTo(leftX, leftTopY); context.lineTo(leftX, botY); context.lineTo(rightX, botY); context.lineTo(rightX, topY); context.lineTo(leftX, leftTopY); }; /** * Create a save object suitable for conversion to JSON for export. * @returns {*} */ Extend.prototype.save = function() { const obj = Component.prototype.save.call(this); obj.outputSize = this.outputSize; obj.arithmetic = this.arithmetic; obj.shift = this.shift; return obj; }; /** * Load this object from an object converted from JSON * @param obj Object from JSON */ Extend.prototype.load = function(obj) { this.outputSize = obj['outputSize']; this.arithmetic = obj['arithmetic']; this.shift = obj['shift']; Component.prototype.load.call(this, obj); }; Extend.prototype.properties = function(main) { const dlg = new ComponentPropertiesDlg(this, main); const outputId = dlg.uniqueId(); const arithId = dlg.uniqueId(); const shiftId = dlg.uniqueId(); var html = `<div class="control1 center gap"> <label>Output size (bits): <input class="number" type="text" name="${outputId}" id="${outputId}" value="${this.outputSize}" spellcheck="false" onfocus="this.select()"> </label> </div> <div class="control1 center gap"> <label>Output shift (bits): <input class="number" type="text" name="${shiftId}" id="${shiftId}" value="${this.shift}" spellcheck="false" onfocus="this.select()"> </label> </div> <div class="control1 center gap"> <label for="${arithId}"><input type="checkbox" id="${arithId}" name="${arithId}"${this.arithmetic ? " checked" : ""}> Arithmetic extend</label> </div>`; dlg.extra(html, () => { const outputStr = document.getElementById(outputId).value; const output = parseInt(outputStr); if(isNaN(output) || output < 1 || output > 32) { document.getElementById(outputId).select(); return "Invalid output size, must be 1 to 32"; } const shiftStr = document.getElementById(shiftId).value; const shift = parseInt(outputStr); if(isNaN(shift) || shift < 0 || shift > output) { document.getElementById(shiftId).select(); return "Invalid shift size, must be 0 to the bit size."; } return null; }, () => { this.arithmetic = document.getElementById(arithId).checked; const outputStr = document.getElementById(outputId).value; this.outputSize = parseInt(outputStr); const shiftStr = document.getElementById(shiftId).value; this.shift = parseInt(shiftStr); this.pending(); }); dlg.open(); document.getElementById(outputId).select(); }; /** * Create a PaletteImage object for a the component */ Extend.paletteImage = function() { const pi = new PaletteImage(60, 44); const wid = 40; const hit = 16; const x = pi.width/2; const y = pi.height/2; const leftX = x - wid/2 - 0.5; const rightX = x + wid/2 + 0.5; const topY = y - hit/2 - 0.5; const leftTopY = y; const botY = y + hit/2 + 0.5; pi.context.beginPath(); pi.context.moveTo(leftX, leftTopY); pi.context.lineTo(rightX, topY); pi.context.lineTo(rightX, botY); pi.context.lineTo(leftX, botY); pi.context.lineTo(leftX, leftTopY); pi.fillStroke(); pi.io(20, 0, 'e'); pi.io(-20, 4, 'w'); pi.drawText("Extend", 0, 7, "8px Times"); return pi; }