UNPKG

cirsim

Version:

Cirsim Circuit Simulator

276 lines (224 loc) 7.41 kB
import {Component} from '../Component'; import {Connector} from '../Connector'; import {Util} from '../Utility/Util'; import {ComponentPropertiesDlg} from '../Dlg/ComponentPropertiesDlg'; import {Sanitize} from '../Utility/Sanitize'; import {PaletteImage} from "../Graphics/PaletteImage"; /** * Component: 16-bit memory * @constructor * @deprecated Use Memory instead */ export const Memory16 = function() { Component.call(this); this.height = 132; this.width = 64; const w2 = this.width / 2; const h2 = this.height / 2; this.lastClk = false; this.data = []; this.lastAddress = 0; this.lastData = 0; this.write = 0; this.addIn(-w2, -32, 16, "A").bus=true; this.addIn(-w2, 32, 16, "W").bus=true; const clk = this.addIn(0, -h2, 14); clk.orientation = 'n'; clk.clock = true; this.addOut(w2, -32, 16, "R").bus=true; }; Memory16.prototype = Object.create(Component.prototype); Memory16.prototype.constructor = Memory16; Memory16.prototype.prefix = "M"; Memory16.type = "Memory16"; ///< Name to use in files Memory16.label = "Memory"; ///< Label for the palette Memory16.desc = "16-bit Memory"; ///< Description for the palette Memory16.img = null; ///< Image to use for the palette Memory16.description = `<h2>16-bit Memory Bank</h2><p>The Memory component implements a simple 16-bit Memory Bank. Memory is an array of bytes. The A (address) input selects a memory location that is output on the R output. The component implements 16-bit memory, so all accesses are considered to be multiples of two and retrieve two bytes. Memory is retrieved in little-endian mode (first byte is the least significant byte).</p> <p>A clock cycle on the clock input writes the memory component with the value on the W (write) input.</p>`; Memory16.order = 704; Memory16.help = 'memory16'; /** * Compute the gate result * @param state */ Memory16.prototype.compute = function(state) { // What is the address? var a = Connector.busValueToDecimal(state[0]); if(a === null) { this.outs[0].set(undefined); } else { if(state[2] && !this.lastClk) { // Leading edge this.write = Connector.busValueToDecimal(state[1]); if(this.write !== null) { // Ensure the address exists... while(this.data.length < (a+2)) { this.data.push(0); } var hi = this.write >> 8; var lo = this.write & 0xff; this.data[a] = lo; this.data[a+1] = hi; } } if(a < (this.data.length - 1)) { var o = this.data[a] + (this.data[a+1] << 8); } else { var o = 0; } this.lastAddress = a; this.lastData = o; var data = []; for(var i=0; i<16; i++) { data.push((o & 1) == 1); o >>= 1; } this.outs[0].set(data); } this.lastClk = state[2]; }; Memory16.prototype.setAsString = function(value, set) { value = Sanitize.sanitize(value); if(set === undefined) { set = true; } if(set) { this.data = []; } var values = value.split(/\s+/); var a = 0; for(var i in values) { var d = values[i]; if(d.indexOf(":") >= 0) { a = parseInt(d, 16); if(isNaN(a)) { return "invalid input address"; } continue; } if(d !== '') { var d = parseInt(d, 16); if(isNaN(d)) { return "invalid input data"; } if(set) { while(this.data.length < a) { this.data.push(0); } this.data[a] = d; a++; } } } if(set) { this.pending(); } return null; } /** * Clone this component object. * @returns {Memory16} */ Memory16.prototype.clone = function() { var copy = new Memory16(); copy.data = this.data.slice(); copy.copyFrom(this); return copy; }; /** * Load this object from an object converted from JSON * @param obj Object from JSON */ Memory16.prototype.load = function(obj) { this.data = obj['data']; Component.prototype.load.call(this, obj); }; /** * Create a save object suitable for conversion to JSON for export. * @returns {*} Object */ Memory16.prototype.save = function() { var obj = Component.prototype.save.call(this); obj.data = this.data; return obj; }; /** * Draw component object. * @param context Display context * @param view View object */ Memory16.prototype.draw = function(context, view) { this.selectStyle(context, view); this.drawBox(context); context.font = "12px Times"; context.textAlign = "center"; context.fillText(Util.toHex(this.lastAddress, 4) + ":" + Util.toHex(this.lastData, 4), this.x, this.y + this.height/2 - 18); context.fillText("memory", this.x, this.y + this.height/2 - 5); this.drawName(context, 0, 3); this.drawIO(context, view); }; Memory16.prototype.properties = function(main) { // // Generate the hex representation of the memory // let data = ''; for(let a=0; a<this.data.length; a++) { if((a % 8) === 0) { if(data.length > 0) { data += "\n"; } data += Util.toHex(a, 4) + ":"; } data += " " + Util.toHex(this.data[a], 2); } let dlg = new ComponentPropertiesDlg(this, main); let id = dlg.uniqueId(); let html = `<div class="control"><label for="${id}">Contents:</label> <textarea class="code1" type="text" rows="9" name="${id}" id="${id}" spellcheck="false">${data}</textarea> </div>`; dlg.extra(html, () => { let value = document.getElementById(id).value; return this.setAsString(value, false); }, () => { let value = document.getElementById(id).value; return this.setAsString(value); }, 85); dlg.open(); }; /** * Create a PaletteImage object for memory component */ Memory16.paletteImage = function() { const paletteImage = new PaletteImage(120, 120); const context = paletteImage.context; context.lineWidth = 1.5; paletteImage.box(40, 80); const w = paletteImage.width; const h = paletteImage.height; const ioY = 18; paletteImage.io(0, -40, 'n'); const lw = paletteImage.lineWidth(2); paletteImage.io(20, -ioY, 'e'); paletteImage.io(-20, -ioY, 'w'); paletteImage.io(-20, ioY, 'w'); paletteImage.lineWidth(lw); const font = '20px Times'; paletteImage.drawText('R', 10, -ioY + 5, font); paletteImage.drawText('A', -12, -ioY + 5, font); paletteImage.drawText('W', -12, ioY + 5, font); const sz = 7; context.beginPath(); context.moveTo(-sz + w/2, -40 + h/2); context.lineTo(w/2, -40 + sz + h/2); context.lineTo(sz + w/2, -40 + h/2); context.stroke(); paletteImage.drawText("memory", 0, 38, "8px Times"); paletteImage.drawText("0000:0000", 0, 32, "8px Times"); return paletteImage; }