CircuitOnline/public/js/sequential.js

1072 lines
35 KiB
JavaScript

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<n;i++)
clockTick();
//console.log((new Date().getTime()-t)/n);
updateCanvas = true;
scheduleUpdate();
}
function TflipFlop(x, y, scope = globalScope, dir = "RIGHT") {
CircuitElement.call(this, x, y, scope, dir, 1);
this.directionFixed = true;
this.fixedBitWidth = true;
this.setDimensions(20, 20);
this.rectangleObject = true;
this.clockInp = new Node(-20, +10, 0, this, 1, "Clock");
this.dInp = new Node(-20, -10, 0, this, this.bitWidth, "T");
this.qOutput = new Node(20, -10, 1, this, this.bitWidth, "Q");
this.qInvOutput = new Node(20, 10, 1, this, this.bitWidth, "Q Inverse");
this.reset = new Node(10, 20, 0, this, 1, "Asynchronous Reset");
this.preset = new Node(0, 20, 0, this, this.bitWidth, "Preset");
this.en = new Node(-10, 20, 0, this, 1, "Enable");
this.masterState = 0;
this.slaveState = 0;
this.prevClockState = 0;
// this.wasClicked = false;
}
TflipFlop.prototype = Object.create(CircuitElement.prototype);
TflipFlop.prototype.constructor = TflipFlop;
TflipFlop.prototype.tooltipText = "T FlipFlop ToolTip : Changes state / Toggles whenever the clock input is strobed.";
TflipFlop.prototype.helplink = "https://docs.circuitverse.org/#/Sequential?id=t-flip-flop";
TflipFlop.prototype.isResolvable = function() {
if (this.reset.value == 1) return true;
if (this.clockInp.value != undefined && this.dInp.value != undefined) return true;
return false;
}
//add this to output the module
TflipFlop.moduleVerilog = function(){
return `
module TflipFlop(q, q_inv, clk, t, a_rst, pre, en);
parameter WIDTH = 1;
output reg [WIDTH-1:0] q, q_inv;
input clk, a_rst, pre, en;
input [WIDTH-1:0] t;
always @ (posedge clk or posedge a_rst)
if (a_rst) begin
q <= 'b0;
q_inv <= 'b1;
end else if (en == 0) ;
else if (t) begin
q <= q ^ t;
q_inv <= ~q ^ t;
end
endmodule
`
}
TflipFlop.prototype.newBitWidth = function(bitWidth) {
this.bitWidth = bitWidth;
this.dInp.bitWidth = bitWidth;
this.qOutput.bitWidth = bitWidth;
this.qInvOutput.bitWidth = bitWidth;
this.preset.bitWidth = bitWidth;
}
TflipFlop.prototype.resolve = function() {
if (this.reset.value == 1) {
this.masterState = this.slaveState = this.preset.value || 0;
} else if (this.en.value == 0) {
this.prevClockState = this.clockInp.value;
} else if (this.en.value == 1 || this.en.connections.length == 0) {
if (this.clockInp.value == this.prevClockState) {
if (this.clockInp.value == 0 && this.dInp.value != undefined) {
this.masterState = this.dInp.value ^ this.slaveState;
}
} else if (this.clockInp.value != undefined) {
if (this.clockInp.value == 1) {
this.slaveState = this.masterState;
} else if (this.clockInp.value == 0 && this.dInp.value != undefined) {
this.masterState = this.dInp.value ^ this.slaveState;
}
this.prevClockState = this.clockInp.value;
}
}
if (this.qOutput.value != this.slaveState) {
this.qOutput.value = this.slaveState;
this.qInvOutput.value = this.flipBits(this.slaveState);
simulationArea.simulationQueue.add(this.qOutput);
simulationArea.simulationQueue.add(this.qInvOutput);
}
}
TflipFlop.prototype.customSave = function() {
var data = {
nodes: {
clockInp: findNode(this.clockInp),
dInp: findNode(this.dInp),
qOutput: findNode(this.qOutput),
qInvOutput: findNode(this.qInvOutput),
reset: findNode(this.reset),
preset: findNode(this.preset),
en: findNode(this.en),
},
constructorParamaters: [this.direction, this.bitWidth]
}
return data;
}
TflipFlop.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 - 20, yy - 20, 40, 40);
moveTo(ctx, -20, 5, xx, yy, this.direction);
lineTo(ctx, -15, 10, xx, yy, this.direction);
lineTo(ctx, -20, 15, 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.font = "20px Georgia";
ctx.fillStyle = "green";
ctx.textAlign = "center";
fillText(ctx, this.slaveState.toString(16), xx, yy + 5);
ctx.fill();
}
function DflipFlop(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.directionFixed = true;
this.setDimensions(20, 20);
this.rectangleObject = true;
this.clockInp = new Node(-20, +10, 0, this, 1, "Clock");
this.dInp = new Node(-20, -10, 0, this, this.bitWidth, "D");
this.qOutput = new Node(20, -10, 1, this, this.bitWidth, "Q");
this.qInvOutput = new Node(20, 10, 1, this, this.bitWidth, "Q Inverse");
this.reset = new Node(10, 20, 0, this, 1, "Asynchronous Reset");
this.preset = new Node(0, 20, 0, this, this.bitWidth, "Preset");
this.en = new Node(-10, 20, 0, this, 1, "Enable");
this.masterState = 0;
this.slaveState = 0;
this.prevClockState = 0;
this.wasClicked = false;
}
DflipFlop.prototype = Object.create(CircuitElement.prototype);
DflipFlop.prototype.constructor = DflipFlop;
DflipFlop.prototype.tooltipText = "D FlipFlop ToolTip : Introduces delay in timing circuit.";
DflipFlop.prototype.helplink = "https://docs.circuitverse.org/#/Sequential?id=d-flip-flop";
DflipFlop.prototype.isResolvable = function() {
return true;
if (this.reset.value == 1) return true;
if (this.clockInp.value != undefined && this.dInp.value != undefined ) return true;
return false;
}
DflipFlop.prototype.newBitWidth = function(bitWidth) {
this.bitWidth = bitWidth;
this.dInp.bitWidth = bitWidth;
this.qOutput.bitWidth = bitWidth;
this.qInvOutput.bitWidth = bitWidth;
this.preset.bitWidth = bitWidth;
}
DflipFlop.prototype.resolve = function() {
if (this.reset.value == 1) {
this.masterState = this.slaveState = (this.preset.value||0);
}
else if (this.en.value == 0) {
this.prevClockState = this.clockInp.value;
}
else if (this.en.value == 1 || this.en.connections.length == 0) { // if(this.en.value==1) // Creating Infinite Loop, WHY ??
if (this.clockInp.value == this.prevClockState) {
if (this.clockInp.value == 0 && this.dInp.value != undefined) {
this.masterState = this.dInp.value;
}
} else if (this.clockInp.value != undefined) {
if (this.clockInp.value == 1) {
this.slaveState = this.masterState;
} else if (this.clockInp.value == 0 && this.dInp.value != undefined) {
this.masterState = this.dInp.value;
}
this.prevClockState = this.clockInp.value;
}
}
if (this.qOutput.value != this.slaveState) {
this.qOutput.value = this.slaveState;
this.qInvOutput.value = this.flipBits(this.slaveState);
simulationArea.simulationQueue.add(this.qOutput);
simulationArea.simulationQueue.add(this.qInvOutput);
}
}
//add this to output the module
DflipFlop.moduleVerilog = function(){
return `
module DflipFlop(q, q_inv, clk, d, a_rst, pre, en);
parameter WIDTH = 1;
output reg [WIDTH-1:0] q, q_inv;
input clk, a_rst, pre, en;
input [WIDTH-1:0] d;
always @ (posedge clk or posedge a_rst)
if (a_rst) begin
q <= 'b0;
q_inv <= 'b1;
end else if (en == 0) ;
else begin
q <= d;
q_inv <= ~d;
end
endmodule
`
}
DflipFlop.prototype.customSave = function() {
var data = {
nodes: {
clockInp: findNode(this.clockInp),
dInp: findNode(this.dInp),
qOutput: findNode(this.qOutput),
qInvOutput: findNode(this.qInvOutput),
reset: findNode(this.reset),
preset: findNode(this.preset),
en: findNode(this.en),
},
constructorParamaters: [this.direction, this.bitWidth]
}
return data;
}
DflipFlop.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 - 20, yy - 20, 40, 40);
moveTo(ctx, -20, 5, xx, yy, this.direction);
lineTo(ctx, -15, 10, xx, yy, this.direction);
lineTo(ctx, -20, 15, 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.font = "20px Georgia";
ctx.fillStyle = "green";
ctx.textAlign = "center";
fillText(ctx, this.slaveState.toString(16), xx, yy + 5);
ctx.fill();
}
function Dlatch(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.directionFixed = true;
this.setDimensions(20, 20);
this.rectangleObject = true;
this.clockInp = new Node(-20, +10, 0, this, 1, "Clock");
this.dInp = new Node(-20, -10, 0, this, this.bitWidth, "D");
this.qOutput = new Node(20, -10, 1, this, this.bitWidth, "Q");
this.qInvOutput = new Node(20, 10, 1, this, this.bitWidth, "Q Inverse");
// this.reset = new Node(10, 20, 0, this, 1, "Asynchronous Reset");
// this.preset = new Node(0, 20, 0, this, this.bitWidth, "Preset");
// this.en = new Node(-10, 20, 0, this, 1, "Enable");
this.state = 0;
this.prevClockState = 0;
this.wasClicked = false;
}
Dlatch.prototype = Object.create(CircuitElement.prototype);
Dlatch.prototype.constructor = Dlatch;
Dlatch.prototype.tooltipText = "D Latch : Single input Flip flop or D FlipFlop";
Dlatch.prototype.helplink = "https://docs.circuitverse.org/#/Sequential?id=d-latch";
Dlatch.prototype.isResolvable = function() {
if (this.clockInp.value != undefined && this.dInp.value != undefined ) return true;
return false;
}
Dlatch.prototype.newBitWidth = function(bitWidth) {
this.bitWidth = bitWidth;
this.dInp.bitWidth = bitWidth;
this.qOutput.bitWidth = bitWidth;
this.qInvOutput.bitWidth = bitWidth;
// this.preset.bitWidth = bitWidth;
}
Dlatch.prototype.resolve = function() {
if (this.clockInp.value == 1 && this.dInp.value!=undefined) {
this.state = this.dInp.value
}
if (this.qOutput.value != this.state) {
this.qOutput.value = this.state;
this.qInvOutput.value = this.flipBits(this.state);
simulationArea.simulationQueue.add(this.qOutput);
simulationArea.simulationQueue.add(this.qInvOutput);
}
}
Dlatch.prototype.customSave = function() {
var data = {
nodes: {
clockInp: findNode(this.clockInp),
dInp: findNode(this.dInp),
qOutput: findNode(this.qOutput),
qInvOutput: findNode(this.qInvOutput),
// reset: findNode(this.reset),
// preset: findNode(this.preset),
// en: findNode(this.en),
},
constructorParamaters: [this.direction, this.bitWidth]
}
return data;
}
Dlatch.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 - 20, yy - 20, 40, 40);
moveTo(ctx, -20, 5, xx, yy, this.direction);
lineTo(ctx, -15, 10, xx, yy, this.direction);
lineTo(ctx, -20, 15, 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.font = "20px Georgia";
ctx.fillStyle = "green";
ctx.textAlign = "center";
fillText(ctx, this.state.toString(16), xx, yy + 5);
ctx.fill();
}
function Random(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.directionFixed = true;
this.setDimensions(20, 20);
this.rectangleObject = true;
this.currentRandomNo = 0;
this.clockInp = new Node(-20, +10, 0, this, 1, "Clock");
this.maxValue = new Node(-20, -10, 0, this, this.bitWidth, "MaxValue");
this.output = new Node(20, -10, 1, this, this.bitWidth, "RandomValue");
this.prevClockState = 0;
this.wasClicked = false;
}
Random.prototype = Object.create(CircuitElement.prototype);
Random.prototype.constructor = Random;
Random.prototype.tooltipText = "Random ToolTip : Random Selected.";
Random.prototype.helplink = "https://docs.circuitverse.org/#/inputElements?id=random";
Random.prototype.isResolvable = function() {
if (this.clockInp.value != undefined && ( this.maxValue.value != undefined || this.maxValue.connections.length == 0 ) )
return true;
return false;
};
Random.prototype.newBitWidth = function(bitWidth) {
this.bitWidth = bitWidth;
this.maxValue.bitWidth = bitWidth;
this.output.bitWidth = bitWidth;
};
Random.prototype.resolve = function() {
//console.log("HIT")
var maxValue = this.maxValue.connections.length ? this.maxValue.value + 1 : (2<<(this.bitWidth-1)) ;
if (this.clockInp.value != undefined) {
if(this.clockInp.value!=this.prevClockState) {
if (this.clockInp.value == 1) {
this.currentRandomNo = Math.floor(Math.random() * maxValue);
}
this.prevClockState = this.clockInp.value;
}
}
if (this.output.value != this.currentRandomNo) {
this.output.value = this.currentRandomNo;
simulationArea.simulationQueue.add(this.output);
}
}
Random.prototype.customSave = function() {
var data = {
nodes: {
clockInp: findNode(this.clockInp),
maxValue: findNode(this.maxValue),
output: findNode(this.output),
},
constructorParamaters: [this.direction, this.bitWidth]
}
return data;
}
Random.prototype.customDraw = function() {
ctx = simulationArea.context;
ctx.beginPath();
xx = this.x;
yy = this.y;
ctx.font = "20px Georgia";
ctx.fillStyle = "green";
ctx.textAlign = "center";
fillText(ctx, this.currentRandomNo.toString(10), this.x, this.y + 5);
ctx.fill();
ctx.beginPath();
moveTo(ctx, -20, 5, xx, yy, this.direction);
lineTo(ctx, -15, 10, xx, yy, this.direction);
lineTo(ctx, -20, 15, xx, yy, this.direction);
ctx.stroke();
}
Random.moduleVerilog = function () {
return `
module Random(val, clk, max);
parameter WIDTH = 1;
output reg [WIDTH-1:0] val;
input clk;
input [WIDTH-1:0] max;
always @ (posedge clk)
if (^max === 1'bX)
val = $urandom_range(0, {WIDTH{1'b1}});
else
val = $urandom_range(0, max);
endmodule
`;
}
function SRflipFlop(x, y, scope = globalScope, dir = "RIGHT") {
CircuitElement.call(this, x, y, scope, dir, 1);
this.directionFixed = true;
this.fixedBitWidth = true;
this.setDimensions(20, 20);
this.rectangleObject = true;
this.R = new Node(-20, +10, 0, this, 1, "R");
this.S = new Node(-20, -10, 0, this, 1, "S");
this.qOutput = new Node(20, -10, 1, this, 1, "Q");
this.qInvOutput = new Node(20, 10, 1, this, 1, "Q Inverse");
this.reset = new Node(10, 20, 0, this, 1, "Asynchronous Reset");
this.preset = new Node(0, 20, 0, this, 1, "Preset");
this.en = new Node(-10, 20, 0, this, 1, "Enable");
this.state = 0;
// this.slaveState = 0;
// this.prevClockState = 0;
// this.wasClicked = false;
}
SRflipFlop.prototype = Object.create(CircuitElement.prototype);
SRflipFlop.prototype.constructor = SRflipFlop;
SRflipFlop.prototype.tooltipText = "SR FlipFlop ToolTip : SR FlipFlop Selected.";
SRflipFlop.prototype.helplink = "https://docs.circuitverse.org/#/Sequential?id=sr-flip-flop";
SRflipFlop.prototype.newBitWidth = function(bitWidth) {
this.bitWidth = bitWidth;
this.dInp.bitWidth = bitWidth;
this.qOutput.bitWidth = bitWidth;
this.qInvOutput.bitWidth = bitWidth;
this.preset.bitWidth = bitWidth;
}
SRflipFlop.prototype.isResolvable = function() {
return true;
if (this.reset.value == 1) return true;
if (this.S.value != undefined && this.R.value != undefined) return true;
return false;
}
SRflipFlop.prototype.resolve = function() {
if (this.reset.value == 1) {
this.state = this.preset.value || 0;
}
else if ((this.en.value ==1||this.en.connections==0) && this.S.value ^ this.R.value) {
this.state = this.S.value;
}
//console.log(this.reset.value != 1 && this.en.value && this.S.value && this.R.value && this.S.value ^ this.R.value);
if (this.qOutput.value != this.state) {
this.qOutput.value = this.state;
this.qInvOutput.value = this.flipBits(this.state);
simulationArea.simulationQueue.add(this.qOutput);
simulationArea.simulationQueue.add(this.qInvOutput);
}
}
SRflipFlop.prototype.customSave = function() {
var data = {
nodes: {
S: findNode(this.S),
R: findNode(this.R),
qOutput: findNode(this.qOutput),
qInvOutput: findNode(this.qInvOutput),
reset: findNode(this.reset),
preset: findNode(this.preset),
en: findNode(this.en),
},
constructorParamaters: [this.direction]
}
return data;
}
SRflipFlop.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 - 20, yy - 20, 40, 40);
// moveTo(ctx, -20, 5, xx, yy, this.direction);
// lineTo(ctx, -15, 10, xx, yy, this.direction);
// lineTo(ctx, -20, 15, 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.font = "20px Georgia";
ctx.fillStyle = "green";
ctx.textAlign = "center";
fillText(ctx, this.state.toString(16), xx, yy + 5);
ctx.fill();
}
function JKflipFlop(x, y, scope = globalScope, dir = "RIGHT") {
CircuitElement.call(this, x, y, scope, dir, 1);
this.directionFixed = true;
this.fixedBitWidth = true;
this.setDimensions(20, 20);
this.rectangleObject = true;
this.J = new Node(-20, -10, 0, this, 1, "J");
this.K = new Node(-20, 0, 0, this, 1, "K");
this.clockInp = new Node(-20, 10, 0, this, 1, "Clock");
this.qOutput = new Node(20, -10, 1, this, 1, "Q");
this.qInvOutput = new Node(20, 10, 1, this, 1, "Q Inverse");
this.reset = new Node(10, 20, 0, this, 1, "Asynchronous Reset");
this.preset = new Node(0, 20, 0, this, 1, "Preset");
this.en = new Node(-10, 20, 0, this, 1, "Enable");
this.state = 0;
this.slaveState = 0;
this.masterState = 0;
this.prevClockState = 0;
// this.wasClicked = false;
}
JKflipFlop.prototype = Object.create(CircuitElement.prototype);
JKflipFlop.prototype.constructor = JKflipFlop;
JKflipFlop.prototype.tooltipText = "JK FlipFlop ToolTip : gated SR flip-flop with the addition of a clock input.";
JKflipFlop.prototype.helplink = "https://docs.circuitverse.org/#/Sequential?id=jk-flip-flop";
JKflipFlop.prototype.isResolvable = function() {
if (this.reset.value == 1) return true;
if (this.clockInp.value != undefined && this.J.value != undefined && this.K.value != undefined) return true;
return false;
}
JKflipFlop.prototype.newBitWidth = function(bitWidth) {
this.bitWidth = bitWidth;
this.dInp.bitWidth = bitWidth;
this.qOutput.bitWidth = bitWidth;
this.qInvOutput.bitWidth = bitWidth;
this.preset.bitWidth = bitWidth;
}
JKflipFlop.prototype.resolve = function() {
if (this.reset.value == 1) {
this.masterState = this.slaveState = this.preset.value || 0;
} else if (this.en.value == 0) {
this.prevClockState = this.clockInp.value;
} else if (this.en.value == 1 || this.en.connections.length == 0) {
if (this.clockInp.value == this.prevClockState) {
if (this.clockInp.value == 0 && this.J.value != undefined && this.K.value != undefined) {
if (this.J.value && this.K.value)
this.masterState = 1 ^ this.slaveState;
else if (this.J.value ^ this.K.value)
this.masterState = this.J.value;
}
} else if (this.clockInp.value != undefined) {
if (this.clockInp.value == 1) {
this.slaveState = this.masterState;
} else if (this.clockInp.value == 0 && this.J.value != undefined && this.K.value != undefined) {
if (this.J.value && this.K.value)
this.masterState = 1 ^ this.slaveState;
else if (this.J.value ^ this.K.value)
this.masterState = this.J.value;
}
this.prevClockState = this.clockInp.value;
}
}
if (this.qOutput.value != this.slaveState) {
this.qOutput.value = this.slaveState;
this.qInvOutput.value = this.flipBits(this.slaveState);
simulationArea.simulationQueue.add(this.qOutput);
simulationArea.simulationQueue.add(this.qInvOutput);
}
}
JKflipFlop.prototype.customSave = function() {
var data = {
nodes: {
J: findNode(this.J),
K: findNode(this.K),
clockInp: findNode(this.clockInp),
qOutput: findNode(this.qOutput),
qInvOutput: findNode(this.qInvOutput),
reset: findNode(this.reset),
preset: findNode(this.preset),
en: findNode(this.en),
},
constructorParamaters: [this.direction]
}
return data;
}
JKflipFlop.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 - 20, yy - 20, 40, 40);
moveTo(ctx, -20, 5, xx, yy, this.direction);
lineTo(ctx, -15, 10, xx, yy, this.direction);
lineTo(ctx, -20, 15, 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.font = "20px Georgia";
ctx.fillStyle = "green";
ctx.textAlign = "center";
fillText(ctx, this.slaveState.toString(16), xx, yy + 5);
ctx.fill();
}
function TTY(x, y, scope = globalScope, rows = 3, cols = 32) {
CircuitElement.call(this, x, y, scope, "RIGHT", 1);
this.directionFixed = true;
this.fixedBitWidth = true;
this.cols = cols || parseInt(prompt("Enter cols:"));
this.rows = rows || parseInt(prompt("Enter rows:"));
this.elementWidth = Math.max(40, Math.ceil(this.cols / 2) * 20);
this.elementHeight = Math.max(40, Math.ceil(this.rows * 15 / 20) * 20);
this.setWidth(this.elementWidth / 2);
this.setHeight(this.elementHeight / 2);
// this.element = new Element(x, y, "TTY",this.elementWidth/2, this,this.elementHeight/2);
this.clockInp = new Node(-this.elementWidth / 2, this.elementHeight / 2 - 10, 0, this, 1,"Clock");
this.asciiInp = new Node(-this.elementWidth / 2, this.elementHeight / 2 - 30, 0, this, 7,"Ascii Input");
// this.qOutput = new Node(20, -10, 1, this);
this.reset = new Node(30 - this.elementWidth / 2, this.elementHeight / 2, 0, this, 1,"Reset");
this.en = new Node(10 - this.elementWidth / 2, this.elementHeight / 2, 0, this, 1,"Enable");
// this.masterState = 0;
// this.slaveState = 0;
this.prevClockState = 0;
this.data = "";
this.buffer = "";
}
TTY.prototype = Object.create(CircuitElement.prototype);
TTY.prototype.constructor = TTY;
TTY.prototype.tooltipText = "TTY ToolTip : Tele typewriter selected.";
TTY.prototype.helplink = "https://docs.circuitverse.org/#/Sequential?id=tty";
TTY.prototype.changeRowSize = function(size) {
if (size == undefined || size < 1 || size > 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
`
}
*/