function clockTick() { if(!simulationArea.clockEnabled)return; if (errorDetected) return; updateCanvas = true; globalScope.clockTick(); play(); scheduleUpdate(0,20); } function changeClockEnable(val){ simulationArea.clockEnabled = val } function runTest(n=10){ var t=new Date().getTime(); for(var i=0;i 10) return; if (this.rows == size) return; var obj = new window[this.objectType](this.x, this.y, this.scope, size, this.cols); this.delete(); simulationArea.lastSelected = obj; return obj; } TTY.prototype.changeColSize = function(size) { if (size == undefined || size < 20 || size > 100) return; if (this.cols == size) return; var obj = new window[this.objectType](this.x, this.y, this.scope, this.rows, size); this.delete(); simulationArea.lastSelected = obj; return obj; } TTY.prototype.mutableProperties = { "cols": { name: "Columns", type: "number", max: "100", min: "20", func: "changeColSize", }, "rows": { name: "Rows", type: "number", max: "10", min: "1", func: "changeRowSize", } } TTY.prototype.isResolvable = function() { if (this.reset.value == 1) return true; else if (this.en.value == 0||(this.en.connections.length&&this.en.value==undefined)) return false; else if (this.clockInp.value == undefined) return false; else if (this.asciiInp.value == undefined) return false; return true; } TTY.prototype.resolve = function() { if (this.reset.value == 1) { this.data = ""; return; } if (this.en.value == 0) { this.buffer = ""; return; } if (this.clockInp.value == this.prevClockState) { if (this.clockInp.value == 0) { this.buffer = String.fromCharCode(this.asciiInp.value); } } else if (this.clockInp.value != undefined) { if (this.clockInp.value == 1) { this.data = this.data + this.buffer; if (this.data.length > this.cols * this.rows) this.data = this.data.slice(1); } else if (this.clockInp.value == 0) { this.buffer = String.fromCharCode(this.asciiInp.value); } this.prevClockState = this.clockInp.value; } } TTY.prototype.customSave = function() { var data = { nodes: { clockInp: findNode(this.clockInp), asciiInp: findNode(this.asciiInp), reset: findNode(this.reset), en: findNode(this.en) }, constructorParamaters: [this.rows, this.cols], } return data; } TTY.prototype.customDraw = function() { ctx = simulationArea.context; ctx.beginPath(); ctx.strokeStyle = ("rgba(0,0,0,1)"); ctx.fillStyle = "white"; ctx.lineWidth = correctWidth(3); var xx = this.x; var yy = this.y; // rect(ctx, xx - this.elementWidth/2, yy - this.elementHeight/2, this.elementWidth, this.elementHeight); moveTo(ctx, -this.elementWidth / 2, this.elementHeight / 2 - 15, xx, yy, this.direction); lineTo(ctx, 5 - this.elementWidth / 2, this.elementHeight / 2 - 10, xx, yy, this.direction); lineTo(ctx, -this.elementWidth / 2, this.elementHeight / 2 - 5, xx, yy, this.direction); // if ((this.b.hover&&!simulationArea.shiftDown)|| simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) // ctx.fillStyle = "rgba(255, 255, 32,0.8)"; // ctx.fill(); ctx.stroke(); ctx.beginPath(); ctx.fillStyle = "green"; ctx.textAlign = "center"; var startY = -7.5 * this.rows + 3; for (var i = 0; i < this.data.length; i += this.cols) { var lineData = this.data.slice(i, i + this.cols); lineData += ' '.repeat(this.cols - lineData.length); fillText3(ctx, lineData, 0, startY + (i / this.cols) * 15 + 9, xx, yy, fontSize = 15, font = "Courier New", textAlign = "center"); } ctx.fill(); } function Keyboard(x, y, scope = globalScope, bufferSize = 32) { CircuitElement.call(this, x, y, scope, "RIGHT", 1); this.directionFixed = true; this.fixedBitWidth = true; this.bufferSize = bufferSize || parseInt(prompt("Enter buffer size:")); this.elementWidth = Math.max(80, Math.ceil(this.bufferSize / 2) * 20); this.elementHeight = 40; //Math.max(40,Math.ceil(this.rows*15/20)*20); this.setWidth(this.elementWidth / 2); this.setHeight(this.elementHeight / 2); this.clockInp = new Node(-this.elementWidth / 2, this.elementHeight / 2 - 10, 0, this, 1,"Clock"); this.asciiOutput = new Node(30, this.elementHeight / 2, 1, this, 7,"Ascii Output"); this.available = new Node(10, this.elementHeight / 2, 1, this, 1,"Available"); this.reset = new Node(-10, this.elementHeight / 2, 0, this, 1,"Reset"); this.en = new Node(-30, this.elementHeight / 2, 0, this, 1,"Enable"); this.prevClockState = 0; this.buffer = ""; this.bufferOutValue = undefined; } Keyboard.prototype = Object.create(CircuitElement.prototype); Keyboard.prototype.constructor = Keyboard; Keyboard.prototype.tooltipText = "Keyboard"; Keyboard.prototype.helplink = "https://docs.circuitverse.org/#/Sequential?id=keyboard"; Keyboard.prototype.changeBufferSize = function(size) { if (size == undefined || size < 20 || size > 100) return; if (this.bufferSize == size) return; var obj = new window[this.objectType](this.x, this.y, this.scope, size); this.delete(); simulationArea.lastSelected = obj; return obj; } Keyboard.prototype.mutableProperties = { "bufferSize": { name: "Buffer Size", type: "number", max: "100", min: "20", func: "changeBufferSize", } } Keyboard.prototype.keyDown = function(key) { if (key.length != 1) return; this.buffer += key; if (this.buffer.length > this.bufferSize) this.buffer = this.buffer.slice(1); //console.log(key) } Keyboard.prototype.isResolvable = function() { if (this.reset.value == 1) return true; else if (this.en.value == 0||(this.en.connections.length&&this.en.value==undefined)) return false; else if (this.clockInp.value == undefined) return false; return true; } Keyboard.prototype.resolve = function() { if (this.reset.value == 1) { this.buffer = ""; return; } if (this.en.value == 0) { return; } if (this.available.value != 0) { this.available.value = 0; //this.bufferOutValue; simulationArea.simulationQueue.add(this.available); } if (this.clockInp.value == this.prevClockState) { if (this.clockInp.value == 0) { if (this.buffer.length) { this.bufferOutValue = this.buffer[0].charCodeAt(0); } else { this.bufferOutValue = undefined; } } } else if (this.clockInp.value != undefined) { if (this.clockInp.value == 1 && this.buffer.length) { if (this.bufferOutValue == this.buffer[0].charCodeAt(0)) { // WHY IS THIS REQUIRED ?? this.buffer = this.buffer.slice(1); } } else { if (this.buffer.length) { this.bufferOutValue = this.buffer[0].charCodeAt(0); } else { this.bufferOutValue = undefined; } } this.prevClockState = this.clockInp.value; } if (this.asciiOutput.value != this.bufferOutValue) { this.asciiOutput.value = this.bufferOutValue; simulationArea.simulationQueue.add(this.asciiOutput); } if (this.bufferOutValue !== undefined && this.available.value != 1) { this.available.value = 1; //this.bufferOutValue; simulationArea.simulationQueue.add(this.available); } } Keyboard.prototype.customSave = function() { var data = { nodes: { clockInp: findNode(this.clockInp), asciiOutput: findNode(this.asciiOutput), available: findNode(this.available), reset: findNode(this.reset), en: findNode(this.en) }, constructorParamaters: [this.bufferSize] } return data; } Keyboard.prototype.customDraw = function() { ctx = simulationArea.context; ctx.beginPath(); ctx.strokeStyle = ("rgba(0,0,0,1)"); ctx.fillStyle = "white"; ctx.lineWidth = correctWidth(3); var xx = this.x; var yy = this.y; moveTo(ctx, -this.elementWidth / 2, this.elementHeight / 2 - 15, xx, yy, this.direction); lineTo(ctx, 5 - this.elementWidth / 2, this.elementHeight / 2 - 10, xx, yy, this.direction); lineTo(ctx, -this.elementWidth / 2, this.elementHeight / 2 - 5, xx, yy, this.direction); ctx.stroke(); ctx.beginPath(); ctx.fillStyle = "green"; ctx.textAlign = "center"; var lineData = this.buffer + ' '.repeat(this.bufferSize - this.buffer.length); fillText3(ctx, lineData, 0, +5, xx, yy, fontSize = 15, font = "Courier New", textAlign = "center"); ctx.fill(); } function Clock(x, y, scope = globalScope, dir = "RIGHT") { CircuitElement.call(this, x, y, scope, dir, 1); this.fixedBitWidth = true; this.output1 = new Node(10, 0, 1, this, 1); this.state = 0; this.output1.value = this.state; this.wasClicked = false; this.interval = null; } Clock.prototype = Object.create(CircuitElement.prototype); Clock.prototype.constructor = Clock; Clock.prototype.tooltipText = "Clock"; Clock.prototype.customSave = function() { var data = { nodes: { output1: findNode(this.output1) }, constructorParamaters: [this.direction], } return data; } Clock.prototype.resolve = function() { this.output1.value = this.state; simulationArea.simulationQueue.add(this.output1); } Clock.prototype.toggleState = function() { //toggleState this.state = (this.state + 1) % 2; this.output1.value = this.state; } Clock.prototype.click = Clock.prototype.toggleState; Clock.prototype.customDraw = function() { ctx = simulationArea.context; ctx.strokeStyle = ("rgba(0,0,0,1)"); ctx.fillStyle = "white"; ctx.lineWidth = correctWidth(3); var xx = this.x; var yy = this.y; ctx.beginPath(); ctx.strokeStyle = ["DarkGreen", "Lime"][this.state]; ctx.lineWidth = correctWidth(2); if (this.state == 0) { moveTo(ctx, -6, 0, xx, yy, "RIGHT"); lineTo(ctx, -6, 5, xx, yy, "RIGHT"); lineTo(ctx, 0, 5, xx, yy, "RIGHT"); lineTo(ctx, 0, -5, xx, yy, "RIGHT"); lineTo(ctx, 6, -5, xx, yy, "RIGHT"); lineTo(ctx, 6, 0, xx, yy, "RIGHT"); } else { moveTo(ctx, -6, 0, xx, yy, "RIGHT"); lineTo(ctx, -6, -5, xx, yy, "RIGHT"); lineTo(ctx, 0, -5, xx, yy, "RIGHT"); lineTo(ctx, 0, 5, xx, yy, "RIGHT"); lineTo(ctx, 6, 5, xx, yy, "RIGHT"); lineTo(ctx, 6, 0, xx, yy, "RIGHT"); } ctx.stroke(); } Clock.verilogInstructions = function() { return "Clock - Use a single global clock\n"; } /* Clock.moduleVerilog = function() { return ` module Clock(clk); output reg clk; always begin #10 clk=1'b0; #10 clk=1'b0; end endmodule ` } */