Last active
September 11, 2025 23:10
-
-
Save Kielan/92dd4676a26d9e853c53d0110d277909 to your computer and use it in GitHub Desktop.
ARMv1 Visual SIM Playground.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| To convert a binary string into its corresponding character(s) in JavaScript, the following steps can be taken: | |
| Split the binary string: If the binary string represents multiple characters (e.g., "01000001 01100010" for "Ab"), it needs to be split into individual binary representations of each character. This is typically done by splitting the string by a delimiter, usually a space. | |
| const binaryString = "01000001 01100010"; // Binary for "Ab" | |
| const binaryArray = binaryString.split(" "); | |
| // binaryArray will be ["01000001", "01100010"] | |
| Convert each binary segment to its decimal (ASCII/Unicode) equivalent: Each binary segment (representing a single character) needs to be converted into its decimal integer value. The parseInt() function with a radix of 2 is used for this purpose. | |
| const decimalValue = parseInt("01000001", 2); | |
| // decimalValue will be 65 (ASCII for 'A') | |
| Convert the decimal value to its character representation: The String.fromCharCode() method is used to convert the decimal (ASCII or Unicode) value into its corresponding character. | |
| const character = String.fromCharCode(65); | |
| // character will be 'A' | |
| Combine the characters: If multiple characters are being converted, the individual characters can be joined together to form a complete string. | |
| const resultString = binaryArray.map(binary => String.fromCharCode(parseInt(binary, 2))).join(""); | |
| // resultString will be "Ab" | |
| Example Function: | |
| JavaScript | |
| function binaryToText(binaryString) { | |
| // Split the binary string into an array of individual binary character representations | |
| const binaryArray = binaryString.split(" "); | |
| // Map each binary string to its corresponding character | |
| const characters = binaryArray.map(binary => { | |
| // Convert the binary string to an integer (base 2) | |
| const decimalValue = parseInt(binary, 2); | |
| // Convert the integer to its corresponding character | |
| return String.fromCharCode(decimalValue); | |
| }); | |
| // Join the array of characters back into a single string | |
| return characters.join(""); | |
| } | |
| const binaryInput = "01001000 01100101 01101100 01101100 01101111"; // "Hello" | |
| const convertedText = binaryToText(binaryInput); | |
| console.log(convertedText); // Output: Hello | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <!-- | |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | |
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | |
| MSFT IE 11.0.9600 says: | |
| Invalid HTML5 DOCTYPE. Consider using the interoperable form "<!DOCTYPE html>". --> | |
| <html> | |
| <head> | |
| <title>ARM1 Gate-level Simulation</title> | |
| <style> | |
| div.ms { | |
| background-color:white; | |
| font-family:monospace; | |
| font-size:medium; | |
| margin-left:10px; | |
| padding-top:10px; | |
| padding-bottom:10px; | |
| } | |
| </style> | |
| <!-- <script type="text/javascript" src="macros.js"></script> --> | |
| <!-- <script type="text/javascript" src="chipsim.js"></script> --> | |
| <script type="text/javascript"> | |
| //webgl-utils.js | |
| /** @fileoverview This file contains functions every webgl program will need | |
| * a version of one way or another. | |
| * | |
| * Instead of setting up a context manually it is recommended to | |
| * use. This will check for success or failure. On failure it | |
| * will attempt to present an approriate message to the user. | |
| * | |
| * gl = WebGLUtils.setupWebGL(canvas); | |
| * | |
| * For animated WebGL apps use of setTimeout or setInterval are | |
| * discouraged. It is recommended you structure your rendering | |
| * loop like this. | |
| * | |
| * function render() { | |
| * window.requestAnimFrame(render, canvas); | |
| * | |
| * // do rendering | |
| * ... | |
| * } | |
| * render(); | |
| * | |
| * This will call your rendering fn up to the refresh rate | |
| * of your display but will stop rndering if your app is not | |
| * visible. **/ | |
| WebGLUtils = function() { | |
| /** Creates the HTML for a failure message | |
| * @param {string} canvasContainerId id of container of th | |
| * canvas. | |
| * @return {string} The html. */ | |
| var makeFailHTML = function(msg) { | |
| return '' + | |
| '<table style="background-color: #8CE; width: 100%; height: 100%;"><tr>' + | |
| '<td align="center">' + | |
| '<div style="display: table-cell; vertical-align: middle;">' + | |
| '<div style="">' + msg + '</div>' + | |
| '</div>' + | |
| '</td></tr></table>'; | |
| }; | |
| /** Message for getting a webgl browser | |
| * @type {string} */ | |
| var GET_A_WEBGL_BROWSER = '' + | |
| 'This page requires a browser that supports WebGL.<br/>' + | |
| '<a href="http://get.webgl.org">Click here to upgrade your browser.</a>'; | |
| /** Message for need better hardware | |
| * @type {string} **/ | |
| var OTHER_PROBLEM = '' + | |
| "It doesn't appear your computer can support WebGL.<br/>" + | |
| '<a href="http://get.webgl.org/troubleshooting/">Click here for more information.</a>'; | |
| /** Creates a webgl context. If creation fails it will | |
| * change the contents of the container of the <canvas> | |
| * tag to an error message with the correct links for WebGL. | |
| * @param {Element} canvas. The canvas element to create a | |
| * context from. | |
| * @param {WebGLContextCreationAttirbutes} opt_attribs Any | |
| * creation attributes you want to pass in. | |
| * @return {WebGLRenderingContext} The created context. **/ | |
| var setupWebGL = function(canvas, opt_attribs) { | |
| function showLink(str) { | |
| var container = canvas.parentNode; | |
| if (container) { | |
| container.innerHTML = makeFailHTML(str); | |
| } | |
| }; | |
| if (!window.WebGLRenderingContext) { | |
| showLink(GET_A_WEBGL_BROWSER); | |
| return null; | |
| } | |
| var context = create3DContext(canvas, opt_attribs); | |
| if (!context) { | |
| showLink(OTHER_PROBLEM); | |
| } | |
| return context; | |
| }; | |
| /** Creates a webgl context. | |
| * @param {!Canvas} canvas The canvas tag to get context | |
| * from. If one is not passed in one will be created. | |
| * @return {!WebGLContext} The created context. **/ | |
| var create3DContext = function(canvas, opt_attribs) { | |
| var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"]; | |
| var context = null; | |
| for (var ii = 0; ii < names.length; ++ii) { | |
| try { | |
| context = canvas.getContext(names[ii], opt_attribs); | |
| } catch(e) {} | |
| if (context) { | |
| break; | |
| } | |
| } | |
| return context; | |
| } | |
| return { | |
| create3DContext: create3DContext, | |
| setupWebGL: setupWebGL | |
| }; | |
| }(); | |
| /** Provides requestAnimationFrame in a cross browser way. **/ | |
| /** callback is... **/ | |
| window.requestAnimFrame = (function() { | |
| return window.requestAnimationFrame || | |
| window.webkitRequestAnimationFrame || | |
| window.mozRequestAnimationFrame || | |
| window.oRequestAnimationFrame || | |
| window.msRequestAnimationFrame || | |
| function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) { | |
| window.setTimeout(callback, 1000/60); | |
| }; | |
| })(); | |
| //Macros | |
| function readNodeValueAsString(n){ | |
| if (typeof nodes[n] == 'undefined') | |
| return 'x'; | |
| var v=nodes[n].state; | |
| if ((typeof v == 'undefined') || (v==-1)) | |
| return 'x'; | |
| return v?'1':'0' | |
| } | |
| //FFDEFS | |
| var ffdefs = [ | |
| 6819,6820, | |
| 5992,6020, | |
| 1138,1177, | |
| 944,982, | |
| ]; | |
| //TRANSDEFS | |
| var transdefs = [ | |
| 10001,2,0,0,0, | |
| 10001,3,0,0,0, | |
| 10001,8371,0,0,0, | |
| 10001,8372,0,0,0, | |
| ]; | |
| //NODENAMES | |
| var nodenames = { | |
| 0: 'vss', | |
| 1: 'vdd', | |
| 2: 'phi1_pad', | |
| 3: 'phi2_pad', | |
| 4: 'aen_internal', | |
| 5: 'ale', | |
| }; | |
| //Chipsim | |
| var nodes = new Array(), transistors = new Array(); | |
| var nvss=0, nvdd=1; | |
| var ctrace = false; | |
| var traceTheseNodes = []; | |
| var traceTheseTransistors = []; | |
| var loglevel = 0; | |
| var recalclist = new Array(); | |
| var recalcHash = new Array(); | |
| var group = new Array(); | |
| var pads = []; | |
| var dbgMaxIndexConst = 5; | |
| function setupNodes(){ | |
| for (var i = 0; i < 8760; i++) { | |
| nodes[i] = {num: i, state: -1, gates: [], c1c2s: [], | |
| plotted: 0, touched:0, switched:0, flipFlop: false}; | |
| } | |
| for(var i = 0; i < ffdefs.length; ++i) { | |
| nodes[ffdefs[i]].flipFlop = true; | |
| } | |
| } | |
| function setupTransistors(){ | |
| for(i=0;i<transdefs.length && i<dbgMaxIndexConst;i+=5){ | |
| var trans = {}; | |
| var num = i/5; | |
| transistors[num] = trans; | |
| console.log('dbglog.transistors: ', transistors); | |
| console.log('dbglog.transdefs[i]: ', transdefs[i]); | |
| trans.touched = 0; | |
| trans.switched = 0; | |
| trans.gate = Math.abs(transdefs[i]); | |
| trans.num = num; | |
| trans.active = (transdefs[i]>=0); | |
| trans.x = transdefs[i+3]; | |
| trans.y = transdefs[i+4]; | |
| trans.c1 = transdefs[i+1]; | |
| nodes[trans.c1].c1c2s.push(trans); | |
| trans.on = false; | |
| switch(trans.gate){ | |
| // output pad | |
| case 10000:{ | |
| pads[nodenames[trans.c1]] = trans; | |
| break;} | |
| // input pad | |
| case 10001: { | |
| trans.c2 = nvss; | |
| pads[nodenames[trans.c1]] = trans; | |
| trans.on = true; | |
| break;} | |
| // io pad | |
| case 10002: { | |
| trans.c2 = nvss; | |
| pads[nodenames[trans.c1]] = trans; | |
| break;} | |
| // gate is vss | |
| case 10003:{ | |
| trans.gate = nvss; | |
| trans.c2 = transdefs[i+2]; | |
| nodes[trans.c2].c1c2s.push(trans); | |
| if (!trans.active) | |
| trans.on = true; | |
| break;} | |
| // gates is vdd | |
| case 10004:{ | |
| trans.gate = nvdd; | |
| trans.c2 = transdefs[i+2]; | |
| nodes[trans.c2].c1c2s.push(trans); | |
| if (trans.active) | |
| trans.on = true; | |
| break;} | |
| default: { | |
| trans.c2 = transdefs[i+2]; | |
| nodes[trans.gate].gates.push(trans); | |
| nodes[trans.c2].c1c2s.push(trans); | |
| break;} | |
| } | |
| } | |
| }; | |
| //GEOM | |
| var version = '019'; | |
| //var urlDir = ''; | |
| // XYZ UV | |
| var numPosPerVert = 3; | |
| var numCoordPerVert = 3 + 2; | |
| var loaded = false; | |
| var gl; | |
| var csp = {}; // chip state program | |
| var stp = {}; // stipple program | |
| var trianglesIb; | |
| var linesIb; | |
| var startLayer, numLayersToDraw; | |
| // For details about reading the .bin data files, see the offline: | |
| // makeGeomFromPatterns_Web.py | |
| // | |
| var coordReqs = {}; | |
| var coordReqArray = []; | |
| var raStart; | |
| // l0-l7.bin | |
| var layerReqs = []; | |
| var layerGeoms = []; | |
| var numActiveDownloads = 0; | |
| var numDownloads = 0; | |
| // l0: 'ntransistor' | |
| // l1: 'metal1' | |
| // l2: 'ndiffusion' | |
| // l3: 'polysilicon' | |
| // l4: 'metal2' | |
| // l5: 'pdiffusion' | |
| // l6: 'metal3' | |
| // l7: 'ptransistor' | |
| var onColsVARM = | |
| [224, 255, 0, 255, // ntran | |
| 240, 240, 240, 128, // metal 1 | |
| 153, 0, 0, 255, // ndiff | |
| 0, 224, 96, 255, // poly | |
| 200, 220, 200, 128, // metal 2 | |
| 0, 0, 153, 255, // pdiff | |
| 50, 50, 50, 255, // metal 3 | |
| 112, 128, 0, 255]; // ptran | |
| var offColsVARM = | |
| [112, 128, 0, 255, // ntran | |
| 120, 100, 100, 70, // metal 1 | |
| 112, 0, 0, 255, // ndiff | |
| 0, 112, 48, 255, // poly | |
| 100, 120, 100, 102, // metal 2 | |
| 0, 0, 112, 255, // pdiff | |
| 25, 25, 25, 255, // metal 3 | |
| 224, 255, 0, 255]; // ptran | |
| var hiColsVARM = | |
| [255, 255, 160, 255, // ntran | |
| 255, 0, 0, 220, // metal 1 | |
| 255, 0, 0, 255, // ndiff | |
| 0, 255, 112, 255, // poly | |
| 255, 0, 0, 220, // metal 2 | |
| 0, 0, 255, 255, // pdiff | |
| 25, 25, 25, 255, // metal 3 | |
| 255, 255, 160, 255]; // ptran | |
| var hiOffColsVARM = | |
| [112, 128, 0, 255, // ntran | |
| 0, 255, 0, 220, // metal 1 | |
| 112, 0, 0, 255, // ndiff | |
| 0, 112, 48, 255, // poly | |
| 0, 255, 0, 220, // metal 2 | |
| 0, 0, 112, 255, // pdiff | |
| 25, 25, 25, 255, // metal 3 | |
| 224, 255, 0, 255]; // ptran | |
| var clearColorVARM = [0,0,0,1]; | |
| var grayLevel = 0.96; | |
| var clearColorCDA = [grayLevel, grayLevel, grayLevel, 1.0]; | |
| var colorTextureDirty = true; | |
| var useCdaColors = false; | |
| var clearColor = clearColorVARM; | |
| var onColors = onColsVARM; | |
| var offColors = offColsVARM; | |
| var hiOffColors = hiOffColsVARM; | |
| var hiColors = hiColsVARM; | |
| var texSizeU = 128; | |
| var texSizeV = 128; | |
| var chipStateTexels = new Uint8Array(texSizeU * texSizeV * 1); | |
| var chipStateTexelsDirty = true; | |
| var chipStateTexture = -1; | |
| var colorTexels = new Uint8Array(8 * 8 * 4); | |
| var colorTexture = -1; | |
| // 4 floats for camera orientation quaternion | |
| var camQuat = [0, 0, 0, 1]; | |
| var eyeVec3 = [0, 0, 1.6]; // 1.6 * 0.025 to start zoomed in | |
| var modVec3 = [-0.09, 0.08, 0]; | |
| // perspective or orthogonal projection matrix | |
| // TODO: get canvasAspectWoH from armgpu namespace object | |
| var canvasAspectWoH = 1.0; | |
| var farZ = 50.0; | |
| var projMat = perspectiveMat4(60.0, canvasAspectWoH, 0.001, farZ); | |
| var modelMat = new Float32Array(16); | |
| var tmpMat = new Float32Array(16); | |
| // model-view matrix | |
| var mvMat = new Float32Array(16); | |
| // model-view-project matrix | |
| var mvpMat = new Float32Array(16); | |
| var mvpMatDirty = true; | |
| var keyFlags = 0; // Object.create(null); | |
| var KF_A = 1 << 0; | |
| var KF_S = 1 << 1; | |
| var KF_D = 1 << 2; | |
| var KF_W = 1 << 3; | |
| var KF_Z = 1 << 4; | |
| var KF_X = 1 << 5; | |
| var KF_RR = 1 << 6; | |
| //window.onload = init; | |
| function init() { | |
| var canvas = document.getElementById("gl-canvas"); | |
| gl = WebGLUtils.setupWebGL(canvas); | |
| if (!gl) { | |
| alert("WebGL isn't available"); | |
| } | |
| gl.viewport(0,0,canvas.width,canvas.height); | |
| gl.clearColor(clearColor[0],clearColor[1],clearColor[2],clearColor[3]); | |
| gl.disable(gl.DEPTH_TEST); | |
| gl.disable(gl.CULL_FACE); | |
| gl.enable(gl.BLEND); | |
| gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); | |
| csp.id = initShaders(gl, "vsh_chip_state", "fsh_chip_state"); | |
| var prg = csp; | |
| var id = prg.id; | |
| prg.va_position = gl.getAttribLocation(id, "va_position"); | |
| prg.va_texCoord0 = gl.getAttribLocation(id, "va_texCoord0"); | |
| prg.vu_mvp = gl.getUniformLocation(id, "vu_mvp"); | |
| prg.stateSamp = gl.getUniformLocation(id, "t_state"); | |
| prg.colorSamp = gl.getUniformLocation(id, "t_layerColors"); | |
| stp.id = initShaders(gl, "vsh_chip_state_stipple", "fsh_chip_state_stipple"); | |
| prg = stp; | |
| id = prg.id; | |
| prg.va_position = gl.getAttribLocation(id, "va_position"); | |
| prg.va_texCoord0 = gl.getAttribLocation(id, "va_texCoord0"); | |
| prg.vu_mvp = gl.getUniformLocation(id, "vu_mvp"); | |
| prg.stateSamp = gl.getUniformLocation(id, "t_state"); | |
| prg.colorSamp = gl.getUniformLocation(id, "t_layerColors"); | |
| prg.fu_stippleOffset = gl.getUniformLocation(id, "fu_stippleOffset"); | |
| prg.fu_stippleFac = gl.getUniformLocation(id, "fu_stippleFac"); | |
| if (urlHas("cdaColors")) { | |
| useCdaColors = false; | |
| toggleColor(); | |
| } | |
| loadBinaryData(); | |
| } | |
| function clamp(val, min, max) { | |
| return Math.min(max, Math.max(min, val)); | |
| } | |
| /** requestAnimFrame is located in Common/webgl-utils.js as window.requestAnimFrame iife **/ | |
| function guardedRequestAnimFrame() { | |
| if (!(keyFlags & KF_RR)) { | |
| requestAnimFrame(render); | |
| keyFlags |= KF_RR; | |
| } | |
| } | |
| function setVizNodeValues(nodes) { | |
| //replaceInner('nodes-dbg', nodeValues.toString().slice(0,40)); | |
| // TODO: tmp - no hilighting | |
| var hiliteNodeIndex = -1; | |
| var len = nodes.length; | |
| for (var i = 0; i < len; ++i) { | |
| var nodeValue = 0; | |
| if (nodes[i].state) { | |
| if (i == hiliteNodeIndex && i > 0) { | |
| nodeValue = 160; | |
| } | |
| else { | |
| nodeValue = 128; | |
| } | |
| } | |
| else if (i == hiliteNodeIndex && i > 0) { | |
| nodeValue = 32; | |
| } | |
| chipStateTexels[i] = nodeValue; | |
| } | |
| chipStateTexelsDirty = true; | |
| guardedRequestAnimFrame(render); | |
| } | |
| function loadBinaryData() { | |
| var urlDir = '/sim/' | |
| //var layerFileNames = ['l0.bin', 'l1.bin', 'l2.bin', 'l3.bin', | |
| // 'l4.bin', 'l5.bin', 'l6.bin', 'l7.bin']; | |
| var layerFileNames = ['10.bin']; | |
| for (var i = 0; i < layerFileNames.length; ++i) { | |
| var urlStr = urlDir + layerFileNames[i]; | |
| layerReqs[i] = new Uint16Request(urlStr); | |
| } | |
| coordReqs.tdReq = new Uint16Request('/sim/' + 'td.bin'); | |
| //coordReqs.rlReq = new Uint16Request('/sim/' + 'rl.bin'); | |
| //coordReqs.rwReq = new Uint16Request('/sim/' + 'rw.bin'); | |
| //coordReqs.rhReq = new Uint16Request('/sim/' + 'rh.bin'); | |
| //coordReqs.rtReq = new Uint16Request('/sim/' + 'rt.bin'); | |
| //coordReqs.llReq = new Uint16Request('/sim/' + 'll.bin'); | |
| //coordReqs.ilReq = new Uint32Request('/sim/' + 'il.bin'); | |
| //coordReqs.neReq = new Uint32Request('/sim/' + 'ne.bin'); | |
| coordReqArray = [coordReqs.tdReq]; | |
| } | |
| function prepRender() { | |
| } | |
| function render() { | |
| if (gl == null || gl == undefined) { | |
| init(); | |
| } | |
| if (!loaded) { | |
| var coordReqDoneCount = 0; | |
| for (var i = 0; i < coordReqArray.length; ++i) { | |
| if (coordReqArray[i].success) { | |
| ++coordReqDoneCount; | |
| } | |
| } | |
| var layerDoneCount = 0; | |
| for (var i = 0; i < layerReqs.length; ++i) { | |
| if (layerReqs[i].success) { | |
| ++layerDoneCount; | |
| } | |
| } | |
| if (layerDoneCount == layerReqs.length && | |
| layerReqs.length > 0 && // thank you MSFT IE | |
| coordReqDoneCount == coordReqArray.length) { | |
| loaded = true; | |
| // Make array of start locations | |
| // ll.bin is list of index list lengths for each pattern | |
| // il.bin is all index lists packed together. Each value is the | |
| // 32-bit index of a rectangle. | |
| var ll = coordReqs.llReq.u16Array; | |
| raStart = new Uint32Array(ll.length); | |
| var pos = 0; | |
| var lllen = ll.length; | |
| for (var i = 0; i < lllen; ++i) { | |
| raStart[i] = pos; | |
| pos += ll[i]; | |
| } | |
| // One index buffer for all plain triangles made of consecutive | |
| // vertices in a vertex buffer of rectangles | |
| var numInds = (0x10000 - 64) * 6; | |
| var tris = new Uint16Array(numInds); | |
| var vInd = 0; | |
| for (var i = 0; i < numInds; vInd += 4) { | |
| tris[i] = vInd + 0; ++i; | |
| tris[i] = vInd + 1; ++i; | |
| tris[i] = vInd + 2; ++i; | |
| tris[i] = vInd + 0; ++i; | |
| tris[i] = vInd + 2; ++i; | |
| tris[i] = vInd + 3; ++i; | |
| } | |
| trianglesIb = gl.createBuffer(); | |
| gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, trianglesIb); | |
| gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, tris, gl.STATIC_DRAW); | |
| gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); | |
| // Another index buffer for drawing lines around each rectangle, to mimick | |
| // the look of Compass Design Automation's layout editor. | |
| var numLineInds = (0x10000 - 64) * 8; | |
| var lines = new Uint16Array(numLineInds); | |
| vInd = 0; | |
| for (var i = 0; i < numLineInds; vInd += 4) { | |
| lines[i] = vInd + 0; ++i; | |
| lines[i] = vInd + 1; ++i; | |
| lines[i] = vInd + 1; ++i; | |
| lines[i] = vInd + 2; ++i; | |
| lines[i] = vInd + 2; ++i; | |
| lines[i] = vInd + 3; ++i; | |
| lines[i] = vInd + 3; ++i; | |
| lines[i] = vInd + 0; ++i; | |
| } | |
| linesIb = gl.createBuffer(); | |
| gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, linesIb); | |
| gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, lines, gl.STATIC_DRAW); | |
| gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); | |
| // Decode geometry from the binary files | |
| for (var i = 0; i < layerReqs.length; ++i) { | |
| decodeGeom(i, layerReqs[i]); | |
| } | |
| //addInner('msg2', 'Created ' + layerGeoms.length + ' layerGeoms<br>'); | |
| startLayer = clamp(urlInt('ls'), 0, layerGeoms.length); | |
| numLayersToDraw = clamp(urlInt('nl'), 0, layerGeoms.length); | |
| if (numLayersToDraw == 0) numLayersToDraw = layerGeoms.length; | |
| } | |
| } | |
| if (gl != null) { | |
| gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); | |
| } | |
| if (loaded) { | |
| prepRender(); | |
| var prg = csp; | |
| if (useCdaColors) { | |
| var prg = stp; | |
| } | |
| gl.useProgram(prg.id); | |
| gl.uniformMatrix4fv(prg.vu_mvp, false, mvpMat); | |
| gl.uniform1i(prg.stateSamp, 0); | |
| gl.uniform1i(prg.colorSamp, 1); | |
| gl.activeTexture(gl.TEXTURE0); | |
| gl.bindTexture(gl.TEXTURE_2D, chipStateTexture); | |
| gl.activeTexture(gl.TEXTURE1); | |
| gl.bindTexture(gl.TEXTURE_2D, colorTexture); | |
| for (var i = startLayer; | |
| i < layerGeoms.length && i < startLayer + numLayersToDraw; | |
| ++i) { | |
| gl.bindBuffer(gl.ARRAY_BUFFER, layerGeoms[i].vb); | |
| gl.enableVertexAttribArray(prg.va_position); | |
| gl.vertexAttribPointer(prg.va_position, numPosPerVert, gl.FLOAT, | |
| false, numCoordPerVert*4, 0); | |
| gl.enableVertexAttribArray(prg.va_texCoord0); | |
| gl.vertexAttribPointer(prg.va_texCoord0, 2, gl.FLOAT, | |
| false, numCoordPerVert*4, numPosPerVert*4); | |
| if (useCdaColors) { | |
| gl.uniform1f(prg.fu_stippleOffset, layerGeoms[i].stippleOffset); | |
| gl.uniform1f(prg.fu_stippleFac, 1.0); | |
| } | |
| if (layerGeoms[i].ib != null) { | |
| gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, layerGeoms[i].ib); | |
| gl.drawElements(gl.TRIANGLES, layerGeoms[i].numIndices, | |
| gl.UNSIGNED_SHORT, 0); | |
| } | |
| else { | |
| gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, trianglesIb); | |
| gl.drawElements(gl.TRIANGLES, layerGeoms[i].numIndices, | |
| gl.UNSIGNED_SHORT, 0); | |
| } | |
| if (useCdaColors) { | |
| // outline the stipple graphics, no stipple pattern | |
| if (eyeVec3[2] < 1.6 * 0.085) { | |
| gl.uniform1f(prg.fu_stippleOffset, 1); | |
| gl.uniform1f(prg.fu_stippleFac, 0.0); | |
| gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, linesIb); | |
| gl.drawElements(gl.LINES, (layerGeoms[i].numIndices/6)*8, | |
| gl.UNSIGNED_SHORT, 0); | |
| } | |
| } | |
| } | |
| /* | |
| // Disable alpha blend while we draw layer ID data | |
| glDisable(GL_BLEND); | |
| glUseProgram(shader_nodeId_); | |
| glUniformMatrix4fv(vshl_nodeId_mvp_, 1, GL_FALSE, mvp_matrix_); | |
| glUniform4f(vshl_nodeId_scale_, scale_, scale_, scale_, scale_); | |
| glBindTexture(GL_TEXTURE_2D, 0); | |
| // TODO: enable this to draw node ID values, but first, we need code | |
| // to switch to offscreen render target. | |
| //drawBuffers(vshl_nodeId_pos_, vshl_nodeId_tc0_, vshl_nodeId_offset_); | |
| glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer_); | |
| glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); | |
| drawBuffers(vshl_nodeId_pos_, vshl_nodeId_tc0_, vshl_nodeId_offset_); | |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); | |
| */ | |
| gl.disableVertexAttribArray(prg.va_position); | |
| gl.disableVertexAttribArray(prg.va_texCoord0); | |
| gl.bindBuffer(gl.ARRAY_BUFFER, null); | |
| gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); | |
| gl.bindTexture(gl.TEXTURE_2D, null); | |
| } | |
| keyFlags &= ~KF_RR; | |
| updateFromKeyFlags(); | |
| } | |
| function setupViz() { | |
| armgpu.setVizNodeValues = setVizNodeValues; | |
| armgpu.setCameraOrientation = setCameraOrientation; | |
| } | |
| function Uint16Request (urlStr) { | |
| this.urlStr = urlStr; | |
| this.success = false; | |
| this.u16Array = null; | |
| var obj = this; | |
| var req = new XMLHttpRequest(); | |
| req.onload = function(e) { | |
| var arrayBuffer = req.response; | |
| var data = new DataView(arrayBuffer); | |
| var bpe = Uint16Array.BYTES_PER_ELEMENT; | |
| obj.u16Array = new Uint16Array(data.byteLength / bpe); | |
| var len = obj.u16Array.length; | |
| for (var i = 0; i < len; ++i) { | |
| obj.u16Array[i] = data.getUint16(i * bpe, true); | |
| } | |
| obj.success = true; | |
| guardedRequestAnimFrame(render); | |
| downloadMsg(-1); | |
| // Option to print success msg | |
| //addInner('msg2', 'Read ' + obj.urlStr + ' ' + obj.u16Array.length + ' bytes<br>'); | |
| }; | |
| req.open("GET", urlStr); | |
| req.responseType = "arraybuffer"; | |
| req.send(); | |
| downloadMsg(1); | |
| } | |
| /* | |
| function Uint32Request (urlStr) { | |
| this.urlStr = urlStr; | |
| this.success = false; | |
| this.u32Array = null; | |
| var obj = this; | |
| var req = new XMLHttpRequest(); | |
| req.onload = function(e) { | |
| var arrayBuffer = req.response; | |
| var data = new DataView(arrayBuffer); | |
| var bpe = Uint32Array.BYTES_PER_ELEMENT; | |
| obj.u32Array = new Uint32Array(data.byteLength / bpe); | |
| var len = obj.u32Array.length; | |
| for (var i = 0; i < len; ++i) { | |
| obj.u32Array[i] = data.getUint32(i * bpe, true); | |
| } | |
| obj.success = true; | |
| guardedRequestAnimFrame(render); | |
| downloadMsg(-1); | |
| // Option to print success msg | |
| //addInner('msg2', 'Read ' + obj.urlStr + ' ' + obj.u32Array.length + ' bytes<br>'); | |
| }; | |
| req.open("GET", urlStr); | |
| req.responseType = "arraybuffer"; | |
| req.send(); | |
| downloadMsg(1); | |
| }*/ | |
| /*function fileName(urlStr) { | |
| return urlStr.slice(urlStr.lastIndexOf('/') + 1) | |
| }*/ | |
| function GeomBuffers(layerId, vb, ib, numIndices) { | |
| this.layerId = layerId; | |
| this.vb = vb; | |
| this.ib = ib; | |
| this.numIndices = numIndices; | |
| } | |
| function decodeGeom(layerId, u16Req) { | |
| var td = coordReqs.tdReq.u16Array; | |
| var rl = coordReqs.rlReq.u16Array; | |
| var rt = coordReqs.rtReq.u16Array; | |
| var rw = coordReqs.rwReq.u16Array; | |
| var rh = coordReqs.rhReq.u16Array; | |
| var ll = coordReqs.llReq.u16Array; | |
| var il = coordReqs.ilReq.u32Array; | |
| var ne = coordReqs.neReq.u32Array; | |
| // TODO: z levels for thick geom | |
| var patArray = u16Req.u16Array; | |
| var len = patArray.length; | |
| var z_min = 0.0; | |
| var numRects = 0; | |
| for (var i = 0; i < len; i+=5) { | |
| var rectArrayInd = patArray[i+3]; | |
| numRects += ll[rectArrayInd]; | |
| } | |
| var vertexXYZs = new Float32Array(numRects * 4 * numCoordPerVert); | |
| var vpos = 0; | |
| /* | |
| switch (layerId) | |
| { | |
| case 1: | |
| threeD = 0; | |
| z_min = 0.015f; z_max = 0.03f; | |
| break; | |
| case 4: | |
| threeD = 0; | |
| z_min = 0.03f; z_max = 0.04f; | |
| break; | |
| case 6: | |
| threeD = 0; | |
| z_min = 0.00f; z_max = 0.045f; | |
| break; | |
| } | |
| */ | |
| var min_x = 9e9; | |
| var min_y = 9e9; | |
| var max_x = -9e9; | |
| var max_y = -9e9; | |
| var qtru = 0.25 / texSizeU; | |
| var qtrv = 0.25 / texSizeV; | |
| for (var i = 0; i < len;) { | |
| var x = patArray[i]; ++i; | |
| var y = patArray[i]; ++i; | |
| var node = patArray[i]; ++i; | |
| var rectArrayInd = patArray[i]; ++i; | |
| var triArrayInd = patArray[i]; ++i; | |
| var rectIndArrayStartPos = raStart[rectArrayInd]; | |
| //var numRects = ll[rectArrayInd]; | |
| var numPatRects = ll[rectArrayInd]; | |
| var rectIndArrayEndPos = rectIndArrayStartPos + numPatRects; | |
| // LayerId is an integer on top of the node id coordinate | |
| // It has no effect on the node texel used, bc the state | |
| // texture wraps around in the U axis. | |
| var u = qtru + (node % texSizeU) / texSizeU + layerId; | |
| var v = qtrv + Math.floor(node / texSizeU) / texSizeV; | |
| //if (i < 10) addInner('msg2', 'u ' + u + ' v ' + v + '<br>'); | |
| // make two triangles for every rectangle | |
| for (var riPos = rectIndArrayStartPos; | |
| riPos < rectIndArrayEndPos; | |
| ++riPos) { | |
| var ri = il[riPos]; | |
| var top = rt[ri] + y; | |
| var left = rl[ri] + x; | |
| var bot = top + rh[ri]; | |
| var right = left + rw[ri]; | |
| // l,r,t,b in [-1,1] | |
| var t = 1 - 2 * top / 32768.0; | |
| var l = -1 + 2 * left / 32768.0; | |
| var b = 1 - 2 * bot / 32768.0; | |
| var r = -1 + 2 * right / 32768.0; | |
| min_x = l < min_x ? l : min_x; | |
| max_x = r > max_x ? r : max_x; | |
| min_y = t < min_y ? t : min_y; | |
| max_y = b > max_y ? b : max_y; | |
| // l,t = 1,0,0 | |
| // r,t = 0,1,0 | |
| // l,b = 0,0,1 | |
| // r,b = 1,0,0 | |
| vertexXYZs[vpos] = l; ++vpos; // x | |
| vertexXYZs[vpos] = t; ++vpos; // y | |
| vertexXYZs[vpos] = z_min; ++vpos; // z | |
| vertexXYZs[vpos] = u; ++vpos; // u | |
| vertexXYZs[vpos] = v; ++vpos; // v | |
| //---- | |
| vertexXYZs[vpos] = r; ++vpos; | |
| vertexXYZs[vpos] = t; ++vpos; | |
| vertexXYZs[vpos] = z_min; ++vpos; | |
| vertexXYZs[vpos] = u; ++vpos; // u | |
| vertexXYZs[vpos] = v; ++vpos; // v | |
| //---- | |
| vertexXYZs[vpos] = r; ++vpos; | |
| vertexXYZs[vpos] = b; ++vpos; | |
| vertexXYZs[vpos] = z_min; ++vpos; | |
| vertexXYZs[vpos] = u; ++vpos; // u | |
| vertexXYZs[vpos] = v; ++vpos; // v | |
| //---- | |
| vertexXYZs[vpos] = l; ++vpos; | |
| vertexXYZs[vpos] = b; ++vpos; | |
| vertexXYZs[vpos] = z_min; ++vpos; | |
| vertexXYZs[vpos] = u; ++vpos; // u | |
| vertexXYZs[vpos] = v; ++vpos; // v | |
| } | |
| } | |
| // Create vertex buffer with a max of 'vertsPerBuffer' vertices, | |
| // since we are limited by 16-bit indices | |
| var numVerts = numRects * 4; | |
| // -64 so wont overflow for a single rect when making cuboid | |
| // Number should be divisible by 4 so we always have a complete | |
| // rectangle. | |
| var vertsPerBuffer = 0x10000 - 64; | |
| var numBuffers = Math.floor(numVerts / vertsPerBuffer) + 1; | |
| var start = 0; | |
| for (var bufInd = 0; | |
| bufInd < numBuffers && start < numVerts; | |
| ++bufInd) { | |
| var numBufVerts = Math.min(numVerts-start, vertsPerBuffer); | |
| // end is exclusive, num = end - start | |
| var slice = vertexXYZs.subarray(start * numCoordPerVert, | |
| (start + numBufVerts) * numCoordPerVert); | |
| var vb = gl.createBuffer(); | |
| gl.bindBuffer(gl.ARRAY_BUFFER, vb); | |
| gl.bufferData(gl.ARRAY_BUFFER, slice, gl.STATIC_DRAW); | |
| // layerId is written in the GeomBuffers function | |
| var lind = layerGeoms.length; | |
| layerGeoms[lind] = new GeomBuffers(layerId, vb, null, 6 * numBufVerts / 4); | |
| layerGeoms[lind].fileName = fileName(u16Req.urlStr); | |
| layerGeoms[lind].u16PatArray = patArray; | |
| layerGeoms[lind].stippleOffset = layerStippleOffset[layerId]; | |
| start = start + numBufVerts; | |
| } | |
| gl.bindBuffer(gl.ARRAY_BUFFER, null); | |
| } | |
| //SUPPORT | |
| //https://github.com/Kielan/visual-arm1-highres/blob/master/sim/varm/support.js | |
| // chip-specific support including user interface | |
| var chipname='ARM1'; | |
| var chipsize=30000; | |
| var ChipWindow = null; | |
| var MemoryTable; | |
| var FrontPanelWindow; | |
| var ChipPinTable; | |
| var RegisterTable; | |
| var FrontPanelDiv; | |
| var PopoutFrontPanelDiv; | |
| var Popoutstatbox; | |
| var selected; // for the memory editor | |
| var logThese=[]; | |
| var logstream = Array(); | |
| var presetLogLists=[ | |
| ['cycle'], | |
| ['phi1', 'phi2', 'address', 'databus', 'rw'], | |
| ['opc', 'pc', 'r14', 'psr'], | |
| ['a_bus', 'b_bus', 'shout'], | |
| ['ireg'], | |
| ['r3', 'r2', 'r1', 'r0'], | |
| ['mreq', 'seq'], | |
| ]; | |
| function initPopout(doc, content){ | |
| doc.open(); | |
| doc.write(content); | |
| doc.close(); | |
| } | |
| function popoutFrontPanel() { | |
| // we can't open a popout from a non-blank URL because we could | |
| // not then access the DOM | |
| FrontPanelWindow = open("","FrontPanel","width=600,height=400"); | |
| initPopout( | |
| FrontPanelWindow.document, | |
| '<html><head><title>Front Panel</title></head><body>' + | |
| chipname + ' Front Panel:'+ | |
| '<div id=frontpaneldiv>'+ | |
| '</div>' + | |
| '</body></html>' | |
| ); | |
| setupFrontPanel(); | |
| updateFrontPanel(); | |
| FrontPanelWindow.focus(); | |
| } | |
| /* | |
| We could have one or two front panels to set up. | |
| The idea of the popout front panel is to allow an uncluttered fully | |
| graphical view and allow for a two-monitor setup. (Also allowed by | |
| the popout layout view) | |
| */ | |
| function setupFrontPanel(){ | |
| var fpd = document.getElementById("frontpaneldiv"); | |
| var fpdcontent= '<div class="ms" id="status" >' + | |
| '</div>' + | |
| '<div class="ms" >' + | |
| '<table style="border-collapse:collapse;" id=pins></table></div>' + | |
| '<div class="ms" >' + | |
| '<table style="border-collapse:collapse;" id=registers></table></div>'; | |
| fpd.innerHTML = fpdcontent; | |
| fpd.setAttribute('style','font-size:small;'); | |
| FrontPanelDiv = fpd; | |
| ChipPinTable = document.getElementById("pins"); | |
| RegisterTable = document.getElementById("registers"); | |
| statbox = document.getElementById('status'); | |
| if ((typeof FrontPanelWindow != 'undefined') && | |
| (FrontPanelWindow.parent != null)) { | |
| PopoutFrontPanelDiv = FrontPanelWindow.document.getElementById("frontpaneldiv"); | |
| PopoutFrontPanelDiv.innerHTML = fpd.innerHTML; | |
| Popoutstatbox = FrontPanelWindow.document.getElementById('status'); | |
| } | |
| } | |
| /* we could have one or two front panels to update */ | |
| function updateFrontPanel(){ | |
| updateChipPins(); | |
| updateRegisters(); | |
| if (logThese.length>0) { | |
| updateLogbox(logThese); | |
| } | |
| // update the status | |
| var ab = readAddressBus(); | |
| var machine1 = | |
| ' cycle:' + (cycle>>1) + | |
| ' phi2:' + (isPadHigh('phi2')?1:0) + | |
| ' A:' + hex(readAddressBus()) + | |
| ' D:' + hex(readDataBus()) + | |
| ' ' + (isPadHigh('rw')?'r':'w'); | |
| var machine2 = | |
| ' r15(pc):' + readRegHex('r15') + | |
| ' ' + CPUModeAsString() + | |
| ' ' + StatusByteAsString() + | |
| // ' r14(link):' + readRegHex('r14') + | |
| // ' r13(sp):' + readRegHex('r13') + | |
| // ' r1:' + readRegHex('r1') + | |
| ' r0:' + readRegHex('r0'); | |
| var machine3 = | |
| 'Hz: ' + estimatedHz().toFixed(1); | |
| setStatus(machine1, machine2, machine3); | |
| // selectCell(ab>>2); | |
| // finally, replicate to the popped-out front panel, if it exists | |
| if ((typeof FrontPanelWindow != 'undefined') && | |
| (FrontPanelWindow.parent != null)) { | |
| PopoutFrontPanelDiv.innerHTML = FrontPanelDiv.innerHTML; | |
| } | |
| } | |
| var prevHzTimeStamp=0; | |
| var prevHzCycleCount=0; | |
| var prevHzEstimate1=1; | |
| var prevHzEstimate2=1; | |
| var HzSamplingRate=10; | |
| // return an averaged speed: called periodically during normal running | |
| function estimatedHz(){ | |
| if(cycle%HzSamplingRate!=3) | |
| return prevHzEstimate1; | |
| var HzTimeStamp = now(); | |
| var HzEstimate = (cycle-prevHzCycleCount+.01)/(HzTimeStamp-prevHzTimeStamp+.01); | |
| HzEstimate=HzEstimate*1000/2; // convert from phases per millisecond to Hz | |
| if(HzEstimate<5) | |
| HzSamplingRate=5; // quicker | |
| if(HzEstimate>10) | |
| HzSamplingRate=10; // smoother | |
| prevHzEstimate2=prevHzEstimate1; | |
| prevHzEstimate1=(HzEstimate+prevHzEstimate1+prevHzEstimate2)/3; // wrong way to average speeds | |
| prevHzTimeStamp=HzTimeStamp; | |
| prevHzCycleCount=cycle; | |
| return prevHzEstimate1 | |
| } | |
| function formatTT(s){ | |
| return '<tt>' + s + '</tt>'; | |
| } | |
| function updateChipPins(){ | |
| var padlist1 = ['phi1', 'phi2', 'ale', 'abe', 'dbe', 'abrt', 'irq', 'firq']; | |
| var padlist2 = ['reset', 'seq', 'm0', 'm1', 'bw', 'rw', 'opc', 'mreq', 'tran']; | |
| var rowborder='style="border-top:thin solid white;"'; | |
| var border='style="border-right:thin solid white;"'; | |
| var mono='style="font-family:monospace;"'; | |
| if (ChipPinTable == null) { | |
| setupFrontPanel(); | |
| } | |
| ChipPinTable.innerHTML = | |
| list2zebraTableRow(1, padlist1, rowborder, border) + | |
| list2zebraTableRow(1, padlist1.map(function(x){return isPadHigh(x)?1:0}), mono, border) + | |
| list2zebraTableRow(2, padlist2, rowborder, border) + | |
| list2zebraTableRow(2, padlist2.map(function(x){return isPadHigh(x)?1:0}), mono, border); | |
| } | |
| function updateRegisters(){ | |
| var reglists = [ | |
| ['r15 (pc)', 'r14 (link)','r13','r12'], ['r11','r10','r9','r8'], | |
| ['r7','r6','r5','r4',], ['r3','r2','r1','r0'], | |
| ['r14_svc', 'r13_svc','',''], | |
| ['r14_irq', 'r13_irq','','r10_fiq'], | |
| ['r14_fiq','r13_fiq','r12_fiq','r11_fiq'], | |
| ]; | |
| var row = []; | |
| var i=1; | |
| var rowborder='style="border-top:thin solid white;"'; | |
| var border='style="border-right:thin solid white;"'; | |
| var mono='style="font-family:monospace;"'; | |
| for(var rl = 0; rl < reglists.length; rl++){ | |
| row.push(list2zebraTableRow(i, reglists[rl], rowborder, border)); | |
| row.push(list2zebraTableRow(i, reglists[rl].map(readRegHex), mono, border)); | |
| i++; | |
| } | |
| RegisterTable.innerHTML = row.join(""); | |
| } | |
| function StatusByteAsString(){ | |
| return (nodes[psrBits['psr_n']].state ? 'N':'n') + | |
| (nodes[psrBits['psr_z']].state ? 'Z':'z') + | |
| (nodes[psrBits['psr_c']].state ? 'C':'c') + | |
| (nodes[psrBits['psr_v']].state ? 'V':'v') + | |
| (nodes[psrBits['psr_irq']].state ? 'I':'i') + | |
| (nodes[psrBits['psr_fiq']].state ? 'F':'f') + | |
| (nodes[psrBits['psr_s1']].state ? 'S':'s') + | |
| (nodes[psrBits['psr_s0']].state ? 'S':'s'); | |
| } | |
| function CPUModeAsString(){ | |
| var m = (nodes[psrBits['psr_s1']].state ? 1:0)*2 + (nodes[psrBits['psr_s0']].state ? 1:0); | |
| var s = ['USR', 'FIQ', 'IRQ', 'SVC'] | |
| return '(' + s[m] + ')'; | |
| } | |
| function popoutChip(){ | |
| // construct the undocked chip layout | |
| var fl; | |
| var frame; | |
| var chip; | |
| if (ChipWindow != null){ | |
| teardown(); | |
| return; | |
| } | |
| window.document.getElementById('monitor').value = "Pop in"; | |
| frame = window.document.getElementById('armgpu_view'); | |
| ChipWindow = open("","ARM V1","width=600,height=600"); | |
| initPopout(ChipWindow.document, '<head></head><body><div id="float"><div></body>'); | |
| ChipWindow.onbeforeunload = function(e){teardown();} | |
| fl = ChipWindow.document.getElementById('float'); | |
| fl.appendChild(frame); | |
| // window.document.getElementById('staticframe').style.visibility = ''; | |
| ChipWindow.onresize = function(e){handleChipResize(e);} | |
| armgpu.appInstance.module_ = ChipWindow.document.getElementById('armgpu'); | |
| handleChipResize(); | |
| ChipWindow.focus(); | |
| } | |
| function popinChip(){ | |
| // redock chip layout | |
| var fl; | |
| var frame; | |
| var chip; | |
| window.document.getElementById('monitor').value = "Pop out"; | |
| // window.document.getElementById('staticframe').style.visibility = 'hidden'; | |
| frame = ChipWindow.document.getElementById('armgpu_view'); | |
| fl = window.document.getElementById('mainlefthalf'); | |
| fl.appendChild(frame); | |
| armgpu.appInstance.module_ = window.document.getElementById('armgpu'); | |
| } | |
| function handleResize(e){ | |
| // size the 'frame' element according to the browser window size | |
| // make bottom margin equal to left margin | |
| var doc = window.document; | |
| layoutsize = window.innerHeight - 20; | |
| doc.getElementById('armgpu_view').style.height = layoutsize + 'px'; | |
| doc.getElementById('armgpu').height = layoutsize + 'px'; | |
| doc.getElementById('armgpu_view').style.width = '1100px'; | |
| doc.getElementById('armgpu').width = '1100px'; | |
| } | |
| function handleChipResize(e){ | |
| // size the 'frame' element according to the browser window size | |
| // make bottom margin equal to left margin | |
| var doc = ChipWindow.document; | |
| layoutsize = ChipWindow.innerHeight - 20; | |
| doc.getElementById('armgpu_view').style.height = layoutsize + 'px'; | |
| doc.getElementById('armgpu').height = layoutsize + 'px'; | |
| doc.getElementById('armgpu_view').style.width = (ChipWindow.innerWidth - 20) + 'px'; | |
| doc.getElementById('armgpu').width = (ChipWindow.innerWidth - 20) + 'px'; | |
| } | |
| function setupMemoryTable(){ | |
| // initially we direct ourselves to the docked-in memory table | |
| MemoryTable = document.getElementById('memtablepanel'); | |
| // create and display the memory table | |
| updateMemoryTable(); | |
| } | |
| var memoryTableWidth=4; | |
| function updateMemoryTable(){ | |
| var memrow = []; | |
| var base = 0; | |
| var width = memoryTableWidth; | |
| var height = 8; | |
| for(var y = 0; y < height; y++){ | |
| memrow.push(list2tableRow(["0x" + hex(base*4)+":"].concat(memory.slice(base, base + width).map(hex)))); | |
| base = base+width; | |
| } | |
| MemoryTable.innerHTML = memrow.join(""); | |
| var rows = MemoryTable.childNodes[0].childNodes; | |
| for(var i = 0; i < rows.length; i++){ | |
| var row = rows[i].childNodes; | |
| rows[i].style.fontFamily="monospace"; | |
| if ((typeof row != "undefined") && row.length > 1){ | |
| for(var j = 1; j < row.length; j++){ | |
| var cell = row[j]; | |
| // we allow editting by attaching a handler to each memory cell | |
| cell.addr = i*memoryTableWidth+j-1 | |
| cell.onmousedown = function(e){handleCellClick(e);}; | |
| } | |
| } | |
| } | |
| } | |
| // each memory cell is sensitive to a mouse click, which then directs | |
| // keypresses to this cell | |
| function handleCellClick(e){ | |
| var c = e.target; | |
| selectCell(c.addr); | |
| MemoryTable.focus(); // this is not working | |
| } | |
| // memory edit will get key events if a memory panel is visible | |
| function isMemoryEditActive(){ | |
| if (typeof selected == "undefined"){ | |
| return false; | |
| } | |
| var memorytabindex = 0; | |
| var activetabindex = $('#paneltabs').tabs().tabs('option', 'selected'); | |
| // not yet dealing with case of popout or kiosk mode | |
| if (activetabindex == memorytabindex){ | |
| return true; | |
| } else { | |
| return false; | |
| } | |
| } | |
| // react to hex and navigation keypresses for memory cell edits | |
| function cellKeydown(e){ | |
| var c = e.keyCode; | |
| if(c==13) unselectCell(); | |
| // space to step forward one cell | |
| else if(c==32) selectCell((selected+1) % 0x200); | |
| // backspace to step backward one cell (FIXME: we don't see this unless the memtable element has focus) | |
| else if(c==8) selectCell((selected-1+0x200) % 0x200); | |
| // cursor (arrow) keys (FIXME: also afflicted by the mysterious event stealer) | |
| else if(c==37) selectCell((selected-1+0x200) % 0x200); | |
| else if(c==38) selectCell((selected-memoryTableWidth+0x200) % 0x200); | |
| else if(c==39) selectCell((selected+1) % 0x200); | |
| else if(c==40) selectCell((selected+memoryTableWidth) % 0x200); | |
| // hex inputs | |
| else if((c>=48) && (c<58)) setCellValue(selected, (getCellValue(selected)<<4) + c - 48); | |
| else if((c>=65) && (c<71)) setCellValue(selected, (getCellValue(selected)<<4) + c - 55); | |
| mWrite(4*selected, getCellValue(selected)); | |
| } | |
| function setCellValue(n, val){ | |
| if(val==undefined) | |
| val=0x00; | |
| cellEl(n).innerHTML=hex(val); | |
| } | |
| function getCellValue(n){ | |
| var cell=cellEl(n); | |
| if(cell == undefined) | |
| return 0 | |
| return ~~("0x" + cellEl(n).innerHTML); | |
| } | |
| function selectCell(n){ | |
| unselectCell(); | |
| if(n>=0x200) return; | |
| if(typeof cellEl(n) == 'undefined'){ | |
| console.log('selectCell bad call with '+n); | |
| return; | |
| } | |
| if(typeof cellEl(n).style == 'undefined'){ | |
| console.log('selectCell bad style call with '+n); | |
| return; | |
| } | |
| cellEl(n).style.background = '#ff8'; // yellow | |
| selected = n; | |
| } | |
| function unselectCell(){ | |
| if(typeof selected == "undefined") return; | |
| cellEl(selected).style.background = '#fff'; // white | |
| selected = undefined; | |
| // window.onkeydown = undefined; | |
| } | |
| function cellEl(n){ | |
| var rows = MemoryTable.childNodes[0].childNodes; | |
| var r = ~~(n/memoryTableWidth); | |
| var c = n % memoryTableWidth; | |
| if (r >= rows.length) return 0; | |
| if (c > rows[r].childNodes.length) return 0; | |
| var e = rows[r].childNodes[c+1]; | |
| return e; | |
| } | |
| var helpBox; | |
| function createHelpBox(){ | |
| if (typeof helpBox != "undefined"){ | |
| helpBoxVisible(''); | |
| return; | |
| } | |
| helpBox=document.createElement("div"); | |
| helpBox.style.position="absolute"; | |
| helpBox.style.left="5%"; | |
| helpBox.style.top="5%"; | |
| helpBox.style.width="90%"; | |
| helpBox.style.borderRadius='10px'; | |
| helpBox.style.color='white'; | |
| helpBox.style.backgroundColor='black'; | |
| helpBox.innerHTML="<div style=padding:1em>" + | |
| "Help window content <span style=float:right id=helpBoxClose><u>Close</u></span>" + | |
| "<p>" + | |
| "<p>Needs a table for two columns" + | |
| "<p>" + | |
| "<p>Explain keycodes for layout zoom/pan, also for run/step (if we have them)" + | |
| "<p>" + | |
| "<p>Thanks to ARM etc." + | |
| "</div>"; | |
| helpBox.style.zIndex=200; | |
| helpBox.style.opacity=0.85; | |
| helpBox.style.visibility='hidden'; | |
| helpBox.style.visibility=''; | |
| document.body.appendChild(helpBox); | |
| document.getElementById('helpBoxClose').onmouseup = function() { | |
| helpBoxVisible("hidden"); | |
| }; | |
| } | |
| function helpBoxVisible(v){ | |
| helpBox.style.visibility=v; | |
| } | |
| function signalSet(n){ | |
| var signals=[]; | |
| for (var i=0; (i<=n)&&(i<presetLogLists.length) ; i++){ | |
| for (var j=0; j<presetLogLists[i].length; j++){ | |
| signals.push(presetLogLists[i][j]); | |
| } | |
| } | |
| return signals; | |
| } | |
| // called direct from UI element | |
| function updateLogList(names){ | |
| // user supplied a list of signals, which we append to the set defined by loglevel | |
| logThese = signalSet(loglevel); | |
| if(typeof names == "undefined") | |
| // this is a UI call - read the text input | |
| names = document.getElementById('LogThese').value; | |
| else | |
| // this is an URL call - update the text input box | |
| document.getElementById('LogThese').value = names; | |
| names = names.split(/[\s,]+/); | |
| for(var i=0;i<names.length;i++){ | |
| // could be a signal name, a node number, or a special name | |
| if(typeof busToString(names[i]) != "undefined") | |
| logThese.push(names[i]); | |
| } | |
| initLogbox(logThese); | |
| } | |
| // called direct from UI element | |
| function updateLoglevel(value){ | |
| loglevel = value; | |
| logThese = signalSet(loglevel); | |
| initLogbox(logThese); | |
| } | |
| var logbox; | |
| function initLogbox(names){ | |
| logbox=document.getElementById('logstream'); | |
| if(logbox==null)return; | |
| names=names.map(function(x){return x.replace(/^-/,'')}); | |
| logStream = []; | |
| logStream.push("<td class=header>" + names.join("</td><td class=header>") + "</td>"); | |
| logbox.innerHTML = "<tr>"+logStream.join("</tr><tr>")+"</tr>"; | |
| } | |
| var logboxAppend=true; | |
| // can append or prepend new states to the log table | |
| // when we reverse direction we need to reorder the log stream | |
| function updateLogDirection(){ | |
| var loglines=[]; | |
| logboxAppend=!logboxAppend; | |
| if(logboxAppend) | |
| document.getElementById('LogUpDown').value='Log Up'; | |
| else | |
| document.getElementById('LogUpDown').value='Log Down'; | |
| // the first element is the header so we can't reverse() | |
| for (var i=1;i<logStream.length;i++) { | |
| loglines.unshift(logStream[i]); | |
| } | |
| loglines.unshift(logStream[0]); | |
| logStream=loglines; | |
| logbox.innerHTML = "<tr>"+logStream.join("</tr><tr>")+"</tr>"; | |
| } | |
| // update the table of signal values, by prepending or appending | |
| function updateLogbox(names){ | |
| var signals=[]; | |
| var odd=true; | |
| var bg; | |
| var row; | |
| for(var i in names){ | |
| if(cycle % 4 < 2){ | |
| bg = odd ? " class=oddcol":""; | |
| } else { | |
| bg = odd ? " class=oddrow":" class=oddrowcol"; | |
| } | |
| signals.push("<td" + bg + ">" + busToString(names[i]) + "</td>"); | |
| odd =! odd; | |
| } | |
| row = "<tr style='font-family:monospace'>" + signals.join("") + "</tr>"; | |
| if(logboxAppend) | |
| logStream.push(row); | |
| else | |
| logStream.splice(1,0,row); | |
| logbox.innerHTML = logStream.join(""); | |
| } | |
| function nodenumber(x){ | |
| // not efficient, but we run it rarely | |
| // an assumption here about nodedefs being a partner to nodenames | |
| for(var i=0;i<nodedefs.length;i++){ | |
| if(nodenames[i] == x){ | |
| return i; | |
| } | |
| } | |
| return undefined; | |
| } | |
| function busToString(busname){ | |
| // takes a signal name or prefix | |
| // returns an appropriate string representation | |
| // some 'signal names' are CPU-specific aliases to user-friendly string output | |
| if(busname=='cycle') | |
| return cycle>>1; | |
| if(busname in regDisplayMap) | |
| return readRegHex(busname); | |
| if(busname=='psr') | |
| return StatusByteAsString(); | |
| if(busname=='a_bus') | |
| return busToString('-na'); | |
| if(busname=='b_bus') | |
| return busToString('-nb'); | |
| if(typeof nodenumber(busname+'_pad') != 'undefined'){ | |
| return isPadHigh(busname)?1:0; | |
| } | |
| if(busname[0]=="-"){ | |
| // invert the value of the bus for display | |
| var value=busToString(busname.slice(1)) | |
| if(typeof value == "undefined") return undefined; | |
| return hex(~('0x'+value)) | |
| } | |
| return busToHex(busname); | |
| } | |
| function busToHex(busname){ | |
| // may be passed a bus or a signal: could be a pinname, nodename, nodenumber or a displayname | |
| // or even a bus of pads, which we must specialcase | |
| if(busname=='a' || busname=='address' || busname=='addressbus'){ | |
| return hex(readAddressBus()); | |
| } | |
| if(busname=='d' || busname=='data' || busname=='databus'){ | |
| return hex(readDataBus()); | |
| } | |
| if(typeof internalBusses[busname] != 'undefined'){ | |
| return hex(readBus(busname)); | |
| } | |
| if(typeof internalBusses[busname+'_bus'] != 'undefined'){ | |
| return hex(readBus(busname+'_bus')); | |
| } | |
| } | |
| function teardown(){ | |
| if(ChipWindow != null) { | |
| popinChip(); | |
| ChipWindow.close(); | |
| ChipWindow = null; | |
| window.onresize = function(e){handleResize(e);} | |
| handleResize(); | |
| window.focus(); | |
| } | |
| if(typeof(FrontPanelWindow) != "undefined") FrontPanelWindow.close(); | |
| } | |
| /* shifter demo program | |
| @ for coding reference see http://www.bravegnu.org/gnu-eprog/asm-directives.html | |
| @ and http://www.peter-cockerell.net/aalp/ | |
| @ | |
| @ to build use | |
| @ as -o shifter.o shifter.s | |
| @ objdump -d shifter.o | |
| .text | |
| mov r1, pc @ inspect status and mode | |
| mov r2, #12 | |
| movs pc, r2 | |
| nop | |
| nop | |
| mov r2, #1 @ initial distance to shift | |
| mov r1, #15 @ constant value to shift | |
| ldr r3, pointer | |
| loop: | |
| ror r0, r1, r2 | |
| add r2, r2, #1 | |
| str r0, [r3], #4 @ write to results array | |
| b loop | |
| pointer: | |
| .word results | |
| results: | |
| .word 0xaa55aa55 | |
| */ | |
| var userCode = []; | |
| var memory = Array( | |
| 0xE1A0100F,0xE3A0200C,0xE1B0F002,0xE1A00000,0xE1A00000,0xE3A02001,0xE3A0100F,0xE59F300C,0xE1A00271,0xE2822001,0xE4830004,0xEAFFFFFB,0x00000034,0xAA55AA55); | |
| //var memory = Array( | |
| //0xE1A0100F,0xE3A0200C,0xE1B0F002,0xE1A00000,0xE1A00000,0xE59F3018,0xE3A00000,0xE3A01001,0xE0802001,0xE1A00001,0xE1A01002,0xE4C31001,0xEAFFFFFA,0x00000038,0xAA55AA55); | |
| // ensure all the displayed memory cells are initialised | |
| for(var i=memory.length; i<32; i++)memory[i] = 0; | |
| // End File Imports | |
| // Provide the armgpu namespace | |
| armgpu = {}; | |
| armgpu.Application = function() { | |
| setupNodes(); | |
| setupTransistors(); | |
| setupParamsFromURL(); | |
| } | |
| armgpu.Application.prototype.onLoad = function() {} | |
| armgpu.Application.prototype.setNodes = function() { | |
| armgpu.setVizNodeValues(nodes); | |
| } | |
| armgpu.Application.prototype.assert = function(cond, message) { | |
| if (!cond) { | |
| message = "Assertion failed: " + message; | |
| alert(message); | |
| throw new Error(message); | |
| } | |
| } | |
| function onLoadArm() { | |
| armgpu.appInstance = new armgpu.Application(); | |
| armgpu.appInstance.onLoad(); | |
| } | |
| function setupParamsFromURL(){ | |
| if(location.search=="") | |
| return | |
| var queryParts=location.search.slice(1).split('&'); | |
| var userAddress = 0; | |
| for(var i = 0; i < queryParts.length; ++i) { | |
| var params = queryParts[i].split("="); | |
| if (params.length != 2) { | |
| break; | |
| } | |
| var name = params[0]; | |
| // chrome sometimes adds trailing slash | |
| var value = params[1].replace(/\/$/,""); | |
| // be (relatively) forgiving in what we accept | |
| // developer quick and dirty startup | |
| // load a test program: Address, Data and Reset | |
| if (name == "a" && parseInt(value,16) != NaN) { | |
| userAddress = parseInt(value,16); | |
| } | |
| else if (name == "d" && | |
| value.match(/[0-9a-fA-F]*/)[0].length == value.length) { | |
| // data is in 32-bit words, as hex values, so groups of 8 digits | |
| for (var j = 0; j < value.length; j+=8) { | |
| userCode[userAddress] = parseInt(value.slice(j, j+8), 16); | |
| userAddress += 4; // a byte address | |
| } | |
| } | |
| } | |
| } | |
| function handleMessage(event){ | |
| var message = event.data.split(':'); | |
| if (message[0] == 'HILITE') { | |
| var node = parseInt(message[1], 10); | |
| var x = parseInt(message[2], 10); | |
| var y = parseInt(message[3], 10); | |
| if (node == 0) { | |
| setStatus('location x:' + Math.round(x) + ' y:'+ Math.round(y)); | |
| } | |
| else { | |
| setStatus('node:' + node + | |
| ' (' + fixNodeName(nodenames[node]) + ') ' + | |
| 'state: ' + readNodeValueAsString(node), | |
| 'location x:' + Math.round(x) + | |
| ' y:'+ Math.round(y)); | |
| } | |
| } | |
| } | |
| function fixNodeName(name){ | |
| if (name.substr(0,4) == 'core') { | |
| var list = name.split('_'); | |
| var str = list[list.length-1]; | |
| if (str=='1' || str == '0') { | |
| str = list[list.length-2] + '_' + str; | |
| } | |
| return(str); | |
| } | |
| return name; | |
| } | |
| </script> | |
| </head> | |
| <body id="bodyId" onload="onLoadArm()" onunload="teardown()"> | |
| <div id="mainlefthalf"> | |
| <div id="armgpu_view" | |
| style=" | |
| background: gray; | |
| position: absolute; | |
| border: 2px solid gray; | |
| width: 800px; | |
| height:800px; | |
| overflow: hidden;"> | |
| <canvas id="gl-canvas" width="1600" height="1600" style="width: 800px; height: 800px;"> | |
| Sorry, your browser doesn't support the HTML5 canvas element | |
| </canvas> | |
| </div> | |
| </div> | |
| </body> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <iostream> | |
| #include <fstream> // Required for file stream operations | |
| #include <string> // Required for using std::string | |
| int main() { | |
| std::ifstream inputFile("il.bin"); // Open the file "example.txt" for reading | |
| // std::ifstream inputFile("filename.bin", std::ios::binary); | |
| // Check if the file was opened successfully | |
| if (!inputFile.is_open()) { | |
| std::cerr << "Error: Could not open the file." << std::endl; | |
| return 1; // Indicate an error | |
| } | |
| //int value; | |
| //inputFile.read(reinterpret_cast<char*>(&value), sizeof(value)) | |
| // Example: Reading a block of data into a vector of bytes | |
| // Determine file size first if reading the whole file | |
| //inputFile.seekg(0, std::ios::end); // Move to end of file | |
| //std::streamsize fileSize = inputFile.tellg(); // Get current position (file size) | |
| //inputFile.seekg(0, std::ios::beg); // Move back to beginning | |
| //std::vector<char> buffer(fileSize); | |
| //inputFile.read(buffer.data(), fileSize); | |
| std::string line; | |
| // Read the file line by line | |
| while (std::getline(inputFile, line)) { | |
| std::cout << line << std::endl; // Print each line to the console | |
| } | |
| inputFile.close(); // Close the file when done | |
| return 0; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| What’s Going On With c1c2s in nodes? | |
| In your debug logs, nodes appears as an array of objects where one of the properties is c1c2s, and it's currently an empty array (Array(0)). While I couldn’t load the exact file content, based on naming conventions in these transistor-level simulation projects, c1c2s almost certainly refers to the two "clock phases" or control lines used in CMOS transistor circuits—commonly known as C1 and C2. | |
| Context in Visual-ULA / Visual-ARM Systems: | |
| The original Visual 6502 project reconstructs transistor-level behavior from silicon imagery to simulate how the 6502 chip functions visualizing every transistor, gate, and clock phase controlling them | |
| visual6502.org | |
| visual6502.org | |
| . | |
| The Visual ARM1 simulation (ARM1 Gate-level Simulation) follows a similar approach applied to the ARM1 architecture—mapping out transistor definitions (transdefs.js), wiring them into gates and nodes, and simulating their behavior under toggling clock phases and input signals | |
| retrocomputingforum.com | |
| visual6502.org | |
| . | |
| In CMOS design, gates often require two-phase non-overlapping clock signals labeled "C1" and "C2" (often used in dynamic logic or transmission-gate circuits). These dictate the timing for when inputs are latched or when precharge and evaluation occur. | |
| So, in transdefs.js, each transistor definition (transdefs[i]) likely includes its role in the clocking phases (C1, C2), sourcing that data into the property's c1c2s array for each node. When you see c1c2s: Array(0) in nodes, it simply means that for those particular nodes (groupings of transistors forming logic gates or nets), no clock-phase information was assigned—they’re probably static logic paths not gated by C1 or C2. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment