CircuitOnline/public/js/modules.js

4461 lines
148 KiB
JavaScript

//AndGate - (x,y)-position , scope - circuit level, inputLength - no of nodes, dir - direction of gate
function changeInputSize(size) {
if (size == undefined || size < 2 || size > 10) return;
if (this.inputSize == size) return;
size = parseInt(size, 10)
var obj = new window[this.objectType](this.x, this.y, this.scope, this.direction, size, this.bitWidth);
this.delete();
simulationArea.lastSelected = obj;
return obj;
// showProperties(obj);
}
function AndGate(x, y, scope = globalScope, dir = "RIGHT", inputLength = 2, bitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.rectangleObject = false;
this.setDimensions(15, 20);
this.inp = [];
this.inputSize = inputLength;
//variable inputLength , node creation
if (inputLength % 2 == 1) {
for (var i = 0; i < inputLength / 2 - 1; i++) {
var a = new Node(-10, -10 * (i + 1), 0, this);
this.inp.push(a);
}
var a = new Node(-10, 0, 0, this);
this.inp.push(a);
for (var i = inputLength / 2 + 1; i < inputLength; i++) {
var a = new Node(-10, 10 * (i + 1 - inputLength / 2 - 1), 0, this);
this.inp.push(a);
}
} else {
for (var i = 0; i < inputLength / 2; i++) {
var a = new Node(-10, -10 * (i + 1), 0, this);
this.inp.push(a);
}
for (var i = inputLength / 2; i < inputLength; i++) {
var a = new Node(-10, 10 * (i + 1 - inputLength / 2), 0, this);
this.inp.push(a);
}
}
this.output1 = new Node(20, 0, 1, this);
}
AndGate.prototype = Object.create(CircuitElement.prototype);
AndGate.prototype.constructor = AndGate;
AndGate.prototype.tooltipText = "And Gate Tooltip : Implements logical conjunction";
AndGate.prototype.changeInputSize = changeInputSize;
AndGate.prototype.alwaysResolve = true;
AndGate.prototype.verilogType = "and";
AndGate.prototype.helplink = "https://docs.circuitverse.org/#/gates?id=and-gate";
//fn to create save Json Data of object
AndGate.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.inputSize, this.bitWidth],
nodes: {
inp: this.inp.map(findNode),
output1: findNode(this.output1)
},
}
return data;
}
//resolve output values based on inputData
AndGate.prototype.resolve = function () {
var result = this.inp[0].value || 0;
if (this.isResolvable() == false) {
return;
}
for (var i = 1; i < this.inputSize; i++)
result = result & ((this.inp[i].value) || 0);
this.output1.value = result;
simulationArea.simulationQueue.add(this.output1);
}
//fn to draw
AndGate.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.beginPath();
ctx.lineWidth = correctWidth(3);
ctx.strokeStyle = "black"; //("rgba(0,0,0,1)");
ctx.fillStyle = "white";
var xx = this.x;
var yy = this.y;
moveTo(ctx, -10, -20, xx, yy, this.direction);
lineTo(ctx, 0, -20, xx, yy, this.direction);
arc(ctx, 0, 0, 20, (-Math.PI / 2), (Math.PI / 2), xx, yy, this.direction);
lineTo(ctx, -10, 20, xx, yy, this.direction);
lineTo(ctx, -10, -20, xx, yy, this.direction);
ctx.closePath();
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
ctx.fill();
ctx.stroke();
}
//translate to gate for single bit, assign for multi bit
AndGate.prototype.generateVerilog = function () {
return gateGenerateVerilog.call(this, '&');
}
function NandGate(x, y, scope = globalScope, dir = "RIGHT", inputLength = 2, bitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.rectangleObject = false;
this.setDimensions(15, 20);
this.inp = [];
this.inputSize = inputLength;
//variable inputLength , node creation
if (inputLength % 2 == 1) {
for (var i = 0; i < inputLength / 2 - 1; i++) {
var a = new Node(-10, -10 * (i + 1), 0, this);
this.inp.push(a);
}
var a = new Node(-10, 0, 0, this);
this.inp.push(a);
for (var i = inputLength / 2 + 1; i < inputLength; i++) {
var a = new Node(-10, 10 * (i + 1 - inputLength / 2 - 1), 0, this);
this.inp.push(a);
}
} else {
for (var i = 0; i < inputLength / 2; i++) {
var a = new Node(-10, -10 * (i + 1), 0, this);
this.inp.push(a);
}
for (var i = inputLength / 2; i < inputLength; i++) {
var a = new Node(-10, 10 * (i + 1 - inputLength / 2), 0, this);
this.inp.push(a);
}
}
this.output1 = new Node(30, 0, 1, this);
}
NandGate.prototype = Object.create(CircuitElement.prototype);
NandGate.prototype.constructor = NandGate;
NandGate.prototype.tooltipText = "Nand Gate ToolTip : Combination of AND and NOT gates";
NandGate.prototype.alwaysResolve = true;
NandGate.prototype.changeInputSize = changeInputSize;
NandGate.prototype.verilogType = "nand";
NandGate.prototype.helplink = "https://docs.circuitverse.org/#/gates?id=nand-gate";
//fn to create save Json Data of object
NandGate.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.inputSize, this.bitWidth],
nodes: {
inp: this.inp.map(findNode),
output1: findNode(this.output1)
},
}
return data;
}
//resolve output values based on inputData
NandGate.prototype.resolve = function () {
var result = this.inp[0].value || 0;
if (this.isResolvable() == false) {
return;
}
for (var i = 1; i < this.inputSize; i++)
result = result & (this.inp[i].value || 0);
result = ((~result >>> 0) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
this.output1.value = result;
simulationArea.simulationQueue.add(this.output1);
}
//fn to draw
NandGate.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.beginPath();
ctx.lineWidth = correctWidth(3);
ctx.strokeStyle = "black";
ctx.fillStyle = "white";
var xx = this.x;
var yy = this.y;
moveTo(ctx, -10, -20, xx, yy, this.direction);
lineTo(ctx, 0, -20, xx, yy, this.direction);
arc(ctx, 0, 0, 20, (-Math.PI / 2), (Math.PI / 2), xx, yy, this.direction);
lineTo(ctx, -10, 20, xx, yy, this.direction);
lineTo(ctx, -10, -20, xx, yy, this.direction);
ctx.closePath();
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.5)";
ctx.fill();
ctx.stroke();
ctx.beginPath();
drawCircle2(ctx, 25, 0, 5, xx, yy, this.direction);
ctx.stroke();
}
//translate to gate for single bit, assign for multi bit
NandGate.prototype.generateVerilog = function () {
return gateGenerateVerilog.call(this, '&', true);
}
function Multiplexer(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1, controlSignalSize = 1) {
// //console.log("HIT");
// //console.log(x,y,scope,dir,bitWidth,controlSignalSize);
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.controlSignalSize = controlSignalSize || parseInt(prompt("Enter control signal bitWidth"), 10);
this.inputSize = 1 << this.controlSignalSize;
this.xOff = 0;
this.yOff = 1;
if (this.controlSignalSize == 1) {
this.xOff = 10;
}
if (this.controlSignalSize <= 3) {
this.yOff = 2;
}
this.setDimensions(20 - this.xOff, this.yOff * 5 * (this.inputSize));
this.rectangleObject = false;
this.inp = [];
for (var i = 0; i < this.inputSize; i++) {
var a = new Node(-20 + this.xOff, +this.yOff * 10 * (i - this.inputSize / 2) + 10, 0, this);
this.inp.push(a);
}
this.output1 = new Node(20 - this.xOff, 0, 1, this);
this.controlSignalInput = new Node(0, this.yOff * 10 * (this.inputSize / 2 - 1) + this.xOff + 10, 0, this, this.controlSignalSize, "Control Signal");
}
Multiplexer.prototype = Object.create(CircuitElement.prototype);
Multiplexer.prototype.constructor = Multiplexer;
Multiplexer.prototype.tooltipText = "Multiplexer ToolTip : Multiple inputs and a single line output.";
Multiplexer.prototype.helplink = "https://docs.circuitverse.org/#/decodersandplexers?id=multiplexer";
Multiplexer.prototype.changeControlSignalSize = function (size) {
if (size == undefined || size < 1 || size > 8) return;
if (this.controlSignalSize == size) return;
var obj = new window[this.objectType](this.x, this.y, this.scope, this.direction, this.bitWidth, size);
this.cleanDelete();
simulationArea.lastSelected = obj;
return obj;
}
Multiplexer.prototype.mutableProperties = {
"controlSignalSize": {
name: "Control Signal Size",
type: "number",
max: "8",
min: "1",
func: "changeControlSignalSize",
},
}
Multiplexer.prototype.newBitWidth = function (bitWidth) {
this.bitWidth = bitWidth;
for (var i = 0; i < this.inputSize; i++) {
this.inp[i].bitWidth = bitWidth
}
this.output1.bitWidth = bitWidth;
}
//fn to create save Json Data of object
Multiplexer.prototype.isResolvable = function () {
if (this.controlSignalInput.value != undefined && this.inp[this.controlSignalInput.value].value != undefined) return true;
return false;
}
Multiplexer.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.bitWidth, this.controlSignalSize],
nodes: {
inp: this.inp.map(findNode),
output1: findNode(this.output1),
controlSignalInput: findNode(this.controlSignalInput)
},
}
return data;
}
Multiplexer.prototype.resolve = function () {
if (this.isResolvable() == false) {
return;
}
this.output1.value = this.inp[this.controlSignalInput.value].value;
simulationArea.simulationQueue.add(this.output1);
}
Multiplexer.prototype.customDraw = function () {
ctx = simulationArea.context;
var xx = this.x;
var yy = this.y;
ctx.beginPath();
moveTo(ctx, 0, this.yOff * 10 * (this.inputSize / 2 - 1) + 10 + 0.5 * this.xOff, xx, yy, this.direction);
lineTo(ctx, 0, this.yOff * 5 * (this.inputSize - 1) + this.xOff, xx, yy, this.direction);
ctx.stroke();
ctx.lineWidth = correctWidth(3);
ctx.beginPath();
ctx.strokeStyle = ("rgba(0,0,0,1)");
ctx.fillStyle = "white";
moveTo(ctx, -20 + this.xOff, -this.yOff * 10 * (this.inputSize / 2), xx, yy, this.direction);
lineTo(ctx, -20 + this.xOff, 20 + this.yOff * 10 * (this.inputSize / 2 - 1), xx, yy, this.direction);
lineTo(ctx, 20 - this.xOff, +this.yOff * 10 * (this.inputSize / 2 - 1) + this.xOff, xx, yy, this.direction);
lineTo(ctx, 20 - this.xOff, -this.yOff * 10 * (this.inputSize / 2) - this.xOff + 20, xx, yy, this.direction);
ctx.closePath();
if ((this.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.lineWidth = correctWidth(2);
ctx.fillStyle = "black";
ctx.textAlign = "center";
for (var i = 0; i < this.inputSize; i++) {
if (this.direction == "RIGHT") fillText(ctx, String(i), xx + this.inp[i].x + 7, yy + this.inp[i].y + 2, 10);
else if (this.direction == "LEFT") fillText(ctx, String(i), xx + this.inp[i].x - 7, yy + this.inp[i].y + 2, 10);
else if (this.direction == "UP") fillText(ctx, String(i), xx + this.inp[i].x, yy + this.inp[i].y - 4, 10);
else fillText(ctx, String(i), xx + this.inp[i].x, yy + this.inp[i].y + 10, 10);
}
ctx.fill();
}
Multiplexer.prototype.verilogBaseType = function() {
return this.verilogName() + this.inp.length;
}
//this code to generate Verilog
Multiplexer.prototype.generateVerilog = function () {
Multiplexer.selSizes.add(this.controlSignalSize);
return CircuitElement.prototype.generateVerilog.call(this);
}
//This code to determine what sizes are used to generate the needed modules
Multiplexer.selSizes = new Set();
//generate the needed modules
Multiplexer.moduleVerilog = function () {
var output = "";
for (var size of Multiplexer.selSizes) {
var numInput = 1 << size;
var inpString = "";
for (var j = 0; j < numInput; j++) {
inpString += `in${j}, `;
}
output += `\nmodule Multiplexer${numInput}(out, ${inpString}sel);\n`;
output += " parameter WIDTH = 1;\n";
output += " output reg [WIDTH-1:0] out;\n";
output += " input [WIDTH-1:0] "
for (var j = 0; j < numInput-1; j++) {
output += `in${j}, `;
}
output += "in" + (numInput-1) + ";\n";
output += ` input [${size-1}:0] sel;\n`;
output += " \n";
output += " always @ (*)\n";
output += " case (sel)\n";
for (var j = 0; j < numInput; j++) {
output += ` ${j} : out = in${j};\n`;
}
output += " endcase\n";
output += "endmodule\n";
output += "\n";
}
return output;
}
//reset the sized before Verilog generation
Multiplexer.resetVerilog = function () {
Multiplexer.selSizes = new Set();
}
function XorGate(x, y, scope = globalScope, dir = "RIGHT", inputs = 2, bitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.rectangleObject = false;
this.setDimensions(15, 20);
this.inp = [];
this.inputSize = inputs;
if (inputs % 2 == 1) {
for (var i = 0; i < inputs / 2 - 1; i++) {
var a = new Node(-20, -10 * (i + 1), 0, this);
this.inp.push(a);
}
var a = new Node(-20, 0, 0, this);
this.inp.push(a);
for (var i = inputs / 2 + 1; i < inputs; i++) {
var a = new Node(-20, 10 * (i + 1 - inputs / 2 - 1), 0, this);
this.inp.push(a);
}
} else {
for (var i = 0; i < inputs / 2; i++) {
var a = new Node(-20, -10 * (i + 1), 0, this);
this.inp.push(a);
}
for (var i = inputs / 2; i < inputs; i++) {
var a = new Node(-20, 10 * (i + 1 - inputs / 2), 0, this);
this.inp.push(a);
}
}
this.output1 = new Node(20, 0, 1, this);
}
XorGate.prototype = Object.create(CircuitElement.prototype);
XorGate.prototype.constructor = XorGate;
XorGate.prototype.tooltipText = "Xor Gate Tooltip : Implements an exclusive OR.";
XorGate.prototype.alwaysResolve = true;
XorGate.prototype.changeInputSize = changeInputSize;
XorGate.prototype.verilogType = "xor";
XorGate.prototype.helplink = "https://docs.circuitverse.org/#/gates?id=xor-gate";
XorGate.prototype.customSave = function () {
// //console.log(this.scope.allNodes);
var data = {
constructorParamaters: [this.direction, this.inputSize, this.bitWidth],
nodes: {
inp: this.inp.map(findNode),
output1: findNode(this.output1)
},
}
return data;
}
XorGate.prototype.resolve = function () {
var result = this.inp[0].value || 0;
if (this.isResolvable() == false) {
return;
}
for (var i = 1; i < this.inputSize; i++)
result = result ^ (this.inp[i].value || 0);
this.output1.value = result;
simulationArea.simulationQueue.add(this.output1);
}
XorGate.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.strokeStyle = ("rgba(0,0,0,1)");
ctx.lineWidth = correctWidth(3);
var xx = this.x;
var yy = this.y;
ctx.beginPath();
ctx.fillStyle = "white";
moveTo(ctx, -10, -20, xx, yy, this.direction, true);
bezierCurveTo(0, -20, +15, -10, 20, 0, xx, yy, this.direction);
bezierCurveTo(0 + 15, 0 + 10, 0, 0 + 20, -10, +20, xx, yy, this.direction);
bezierCurveTo(0, 0, 0, 0, -10, -20, xx, yy, this.direction);
// arc(ctx, 0, 0, -20, (-Math.PI / 2), (Math.PI / 2), xx, yy, this.direction);
ctx.closePath();
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
ctx.fill();
ctx.stroke();
ctx.beginPath();
arc2(ctx, -35, 0, 25, 1.70 * (Math.PI), 0.30 * (Math.PI), xx, yy, this.direction);
ctx.stroke();
}
//translate to gate for single bit, assign for multi bit
XorGate.prototype.generateVerilog = function () {
return gateGenerateVerilog.call(this, '^');
}
function XnorGate(x, y, scope = globalScope, dir = "RIGHT", inputs = 2, bitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.rectangleObject = false;
this.setDimensions(15, 20);
this.inp = [];
this.inputSize = inputs;
if (inputs % 2 == 1) {
for (var i = 0; i < inputs / 2 - 1; i++) {
var a = new Node(-20, -10 * (i + 1), 0, this);
this.inp.push(a);
}
var a = new Node(-20, 0, 0, this);
this.inp.push(a);
for (var i = inputs / 2 + 1; i < inputs; i++) {
var a = new Node(-20, 10 * (i + 1 - inputs / 2 - 1), 0, this);
this.inp.push(a);
}
} else {
for (var i = 0; i < inputs / 2; i++) {
var a = new Node(-20, -10 * (i + 1), 0, this);
this.inp.push(a);
}
for (var i = inputs / 2; i < inputs; i++) {
var a = new Node(-20, 10 * (i + 1 - inputs / 2), 0, this);
this.inp.push(a);
}
}
this.output1 = new Node(30, 0, 1, this);
}
XnorGate.prototype = Object.create(CircuitElement.prototype);
XnorGate.prototype.constructor = XnorGate;
XnorGate.prototype.alwaysResolve = true;
XnorGate.prototype.tooltipText = "Xnor Gate ToolTip : Logical complement of the XOR gate";
XnorGate.prototype.changeInputSize = changeInputSize;
XnorGate.prototype.verilogType = "xnor";
XnorGate.prototype.helplink = "https://docs.circuitverse.org/#/gates?id=xnor-gate";
XnorGate.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.inputSize, this.bitWidth],
nodes: {
inp: this.inp.map(findNode),
output1: findNode(this.output1)
},
}
return data;
}
XnorGate.prototype.resolve = function () {
var result = this.inp[0].value || 0;
if (this.isResolvable() == false) {
return;
}
for (var i = 1; i < this.inputSize; i++)
result = result ^ (this.inp[i].value || 0);
result = ((~result >>> 0) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
this.output1.value = result;
simulationArea.simulationQueue.add(this.output1);
}
XnorGate.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.strokeStyle = ("rgba(0,0,0,1)");
ctx.lineWidth = correctWidth(3);
var xx = this.x;
var yy = this.y;
ctx.beginPath();
ctx.fillStyle = "white";
moveTo(ctx, -10, -20, xx, yy, this.direction, true);
bezierCurveTo(0, -20, +15, -10, 20, 0, xx, yy, this.direction);
bezierCurveTo(0 + 15, 0 + 10, 0, 0 + 20, -10, +20, xx, yy, this.direction);
bezierCurveTo(0, 0, 0, 0, -10, -20, xx, yy, this.direction);
// arc(ctx, 0, 0, -20, (-Math.PI / 2), (Math.PI / 2), xx, yy, this.direction);
ctx.closePath();
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
ctx.fill();
ctx.stroke();
ctx.beginPath();
arc2(ctx, -35, 0, 25, 1.70 * (Math.PI), 0.30 * (Math.PI), xx, yy, this.direction);
ctx.stroke();
ctx.beginPath();
drawCircle2(ctx, 25, 0, 5, xx, yy, this.direction);
ctx.stroke();
}
//translate to gate for single bit, assign for multi bit
XnorGate.prototype.generateVerilog = function () {
return gateGenerateVerilog.call(this,'^', true);
}
function SevenSegDisplay(x, y, scope = globalScope) {
CircuitElement.call(this, x, y, scope, "RIGHT", 1);
this.fixedBitWidth = true;
this.directionFixed = true;
this.setDimensions(30, 50);
this.g = new Node(-20, -50, 0, this);
this.f = new Node(-10, -50, 0, this);
this.a = new Node(+10, -50, 0, this);
this.b = new Node(+20, -50, 0, this);
this.e = new Node(-20, +50, 0, this);
this.d = new Node(-10, +50, 0, this);
this.c = new Node(+10, +50, 0, this);
this.dot = new Node(+20, +50, 0, this);
this.direction = "RIGHT";
}
SevenSegDisplay.prototype = Object.create(CircuitElement.prototype);
SevenSegDisplay.prototype.constructor = SevenSegDisplay;
SevenSegDisplay.prototype.tooltipText = "Seven Display ToolTip: Consists of 7+1 single bit inputs.";
SevenSegDisplay.prototype.helplink = "https://docs.circuitverse.org/#/outputs?id=seven-segment-display";
SevenSegDisplay.prototype.customSave = function () {
var data = {
nodes: {
g: findNode(this.g),
f: findNode(this.f),
a: findNode(this.a),
b: findNode(this.b),
d: findNode(this.d),
e: findNode(this.e),
c: findNode(this.c),
d: findNode(this.d),
dot: findNode(this.dot)
},
}
return data;
}
SevenSegDisplay.prototype.customDrawSegment = function (x1, y1, x2, y2, color) {
if (color == undefined) color = "lightgrey";
ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = color;
ctx.lineWidth = correctWidth(5);
xx = this.x;
yy = this.y;
moveTo(ctx, x1, y1, xx, yy, this.direction);
lineTo(ctx, x2, y2, xx, yy, this.direction);
ctx.closePath();
ctx.stroke();
}
SevenSegDisplay.prototype.customDraw = function () {
ctx = simulationArea.context;
var xx = this.x;
var yy = this.y;
this.customDrawSegment(18, -3, 18, -38, ["lightgrey", "red"][this.b.value]);
this.customDrawSegment(18, 3, 18, 38, ["lightgrey", "red"][this.c.value]);
this.customDrawSegment(-18, -3, -18, -38, ["lightgrey", "red"][this.f.value]);
this.customDrawSegment(-18, 3, -18, 38, ["lightgrey", "red"][this.e.value]);
this.customDrawSegment(-17, -38, 17, -38, ["lightgrey", "red"][this.a.value]);
this.customDrawSegment(-17, 0, 17, 0, ["lightgrey", "red"][this.g.value]);
this.customDrawSegment(-15, 38, 17, 38, ["lightgrey", "red"][this.d.value]);
ctx.beginPath();
var dotColor = ["lightgrey", "red"][this.dot.value] || "lightgrey"
ctx.strokeStyle = dotColor;
rect(ctx, xx + 22, yy + 42, 2, 2);
ctx.stroke();
}
SevenSegDisplay.prototype.generateVerilog = function () {
return `
always @ (*)
$display("SevenSegDisplay:${this.verilogLabel}.abcdefg. = %b%b%b%b%b%b%b%b}",
${this.a.verilogLabel}, ${this.b.verilogLabel}, ${this.c.verilogLabel}, ${this.d.verilogLabel}, ${this.e.verilogLabel}, ${this.f.verilogLabel}, ${this.g.verilogLabel}, ${this.dot.verilogLabel});`;
}
function SixteenSegDisplay(x, y, scope = globalScope) {
CircuitElement.call(this, x, y, scope, "RIGHT", 16);
this.fixedBitWidth = true;
this.directionFixed = true;
this.setDimensions(30, 50);
this.input1 = new Node(0, -50, 0, this, 16);
this.dot = new Node(0, 50, 0, this, 1);
this.direction = "RIGHT";
}
SixteenSegDisplay.prototype = Object.create(CircuitElement.prototype);
SixteenSegDisplay.prototype.constructor = SixteenSegDisplay;
SixteenSegDisplay.prototype.tooltipText = "Sixteen Display ToolTip: Consists of 16+1 bit inputs.";
SixteenSegDisplay.prototype.helplink = "https://docs.circuitverse.org/#/outputs?id=sixteen-segment-display";
SixteenSegDisplay.prototype.customSave = function () {
var data = {
nodes: {
input1: findNode(this.input1),
dot: findNode(this.dot)
}
}
return data;
}
SixteenSegDisplay.prototype.customDrawSegment = function (x1, y1, x2, y2, color) {
if (color == undefined) color = "lightgrey";
ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = color;
ctx.lineWidth = correctWidth(4);
xx = this.x;
yy = this.y;
moveTo(ctx, x1, y1, xx, yy, this.direction);
lineTo(ctx, x2, y2, xx, yy, this.direction);
ctx.closePath();
ctx.stroke();
}
SixteenSegDisplay.prototype.customDrawSegmentSlant = function (x1, y1, x2, y2, color) {
if (color == undefined) color = "lightgrey";
ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = color;
ctx.lineWidth = correctWidth(3);
xx = this.x;
yy = this.y;
moveTo(ctx, x1, y1, xx, yy, this.direction);
lineTo(ctx, x2, y2, xx, yy, this.direction);
ctx.closePath();
ctx.stroke();
}
SixteenSegDisplay.prototype.customDraw = function () {
ctx = simulationArea.context;
var xx = this.x;
var yy = this.y;
var color = ["lightgrey", "red"];
var value = this.input1.value;
this.customDrawSegment(-20, -38, 0, -38, ["lightgrey", "red"][(value >> 15) & 1]); //a1
this.customDrawSegment(20, -38, 0, -38, ["lightgrey", "red"][(value >> 14) & 1]); //a2
this.customDrawSegment(21.5, -2, 21.5, -36, ["lightgrey", "red"][(value >> 13) & 1]); //b
this.customDrawSegment(21.5, 2, 21.5, 36, ["lightgrey", "red"][(value >> 12) & 1]); //c
this.customDrawSegment(-20, 38, 0, 38, ["lightgrey", "red"][(value >> 11) & 1]); //d1
this.customDrawSegment(20, 38, 0, 38, ["lightgrey", "red"][(value >> 10) & 1]); //d2
this.customDrawSegment(-21.5, 2, -21.5, 36, ["lightgrey", "red"][(value >> 9) & 1]); //e
this.customDrawSegment(-21.5, -36, -21.5, -2, ["lightgrey", "red"][(value >> 8) & 1]); //f
this.customDrawSegment(-20, 0, 0, 0, ["lightgrey", "red"][(value >> 7) & 1]); //g1
this.customDrawSegment(20, 0, 0, 0, ["lightgrey", "red"][(value >> 6) & 1]); //g2
this.customDrawSegmentSlant(0, 0, -21, -37, ["lightgrey", "red"][(value >> 5) & 1]); //h
this.customDrawSegment(0, -2, 0, -36, ["lightgrey", "red"][(value >> 4) & 1]); //i
this.customDrawSegmentSlant(0, 0, 21, -37, ["lightgrey", "red"][(value >> 3) & 1]); //j
this.customDrawSegmentSlant(0, 0, 21, 37, ["lightgrey", "red"][(value >> 2) & 1]); //k
this.customDrawSegment(0, 2, 0, 36, ["lightgrey", "red"][(value >> 1) & 1]); //l
this.customDrawSegmentSlant(0, 0, -21, 37, ["lightgrey", "red"][(value >> 0) & 1]); //m
ctx.beginPath();
var dotColor = ["lightgrey", "red"][this.dot.value] || "lightgrey"
ctx.strokeStyle = dotColor;
rect(ctx, xx + 22, yy + 42, 2, 2);
ctx.stroke();
}
SixteenSegDisplay.prototype.generateVerilog = function () {
return `
always @ (*)
$display("SixteenSegDisplay:{${this.input1.verilogLabel},${this.dot.verilogLabel}} = {%16b,%1b}", ${this.input1.verilogLabel}, ${this.dot.verilogLabel});`;
}
function HexDisplay(x, y, scope = globalScope) {
CircuitElement.call(this, x, y, scope, "RIGHT", 4);
this.directionFixed = true;
this.fixedBitWidth = true;
this.setDimensions(30, 50);
this.inp = new Node(0, -50, 0, this, 4);
this.direction = "RIGHT";
}
HexDisplay.prototype = Object.create(CircuitElement.prototype);
HexDisplay.prototype.constructor = HexDisplay;
HexDisplay.prototype.tooltipText = "Hex Display ToolTip: Inputs a 4 Bit Hex number and displays it."
HexDisplay.prototype.helplink = "https://docs.circuitverse.org/#/outputs?id=hex-display";
/* Older code convert HexDisplay to output
HexDisplay.prototype.generateVerilog = function () {
return "assign " + this.label + " = " + this.inp.verilogLabel + ";"
}
*/
//Use $display
HexDisplay.prototype.generateVerilog = function () {
return `
always @ (*)
$display("HexDisplay:${this.verilogLabel}=%d", ${this.inp.verilogLabel});`;
}
HexDisplay.prototype.customSave = function () {
var data = {
nodes: {
inp: findNode(this.inp)
}
}
return data;
}
HexDisplay.prototype.customDrawSegment = function (x1, y1, x2, y2, color) {
if (color == undefined) color = "lightgrey";
ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = color;
ctx.lineWidth = correctWidth(5);
xx = this.x;
yy = this.y;
moveTo(ctx, x1, y1, xx, yy, this.direction);
lineTo(ctx, x2, y2, xx, yy, this.direction);
ctx.closePath();
ctx.stroke();
}
HexDisplay.prototype.customDraw = function () {
ctx = simulationArea.context;
var xx = this.x;
var yy = this.y;
ctx.strokeStyle = "black";
ctx.lineWidth = correctWidth(3);
var a = b = c = d = e = f = g = 0;
switch (this.inp.value) {
case 0:
a = b = c = d = e = f = 1;
break;
case 1:
b = c = 1;
break;
case 2:
a = b = g = e = d = 1;
break;
case 3:
a = b = g = c = d = 1;
break;
case 4:
f = g = b = c = 1;
break;
case 5:
a = f = g = c = d = 1;
break;
case 6:
a = f = g = e = c = d = 1;
break;
case 7:
a = b = c = 1;
break;
case 8:
a = b = c = d = e = g = f = 1;
break;
case 9:
a = f = g = b = c = 1;
break;
case 0xA:
a = f = b = c = g = e = 1;
break;
case 0xB:
f = e = g = c = d = 1;
break;
case 0xC:
a = f = e = d = 1;
break;
case 0xD:
b = c = g = e = d = 1;
break;
case 0xE:
a = f = g = e = d = 1;
break;
case 0xF:
a = f = g = e = 1;
break;
default:
}
this.customDrawSegment(18, -3, 18, -38, ["lightgrey", "red"][b]);
this.customDrawSegment(18, 3, 18, 38, ["lightgrey", "red"][c]);
this.customDrawSegment(-18, -3, -18, -38, ["lightgrey", "red"][f]);
this.customDrawSegment(-18, 3, -18, 38, ["lightgrey", "red"][e]);
this.customDrawSegment(-17, -38, 17, -38, ["lightgrey", "red"][a]);
this.customDrawSegment(-17, 0, 17, 0, ["lightgrey", "red"][g]);
this.customDrawSegment(-15, 38, 17, 38, ["lightgrey", "red"][d]);
}
function OrGate(x, y, scope = globalScope, dir = "RIGHT", inputs = 2, bitWidth = 1) {
// Calling base class constructor
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.rectangleObject = false;
this.setDimensions(15, 20);
// Inherit base class prototype
this.inp = [];
this.inputSize = inputs;
if (inputs % 2 == 1) {
// for (var i = 0; i < inputs / 2 - 1; i++) {
// var a = new Node(-10, -10 * (i + 1), 0, this);
// this.inp.push(a);
// }
// var a = new Node(-10, 0, 0, this);
// this.inp.push(a);
// for (var i = inputs / 2 + 1; i < inputs; i++) {
// var a = new Node(-10, 10 * (i + 1 - inputs / 2 - 1), 0, this);
// this.inp.push(a);
// }
for (var i = Math.floor(inputs / 2) - 1; i >= 0; i--) {
var a = new Node(-10, -10 * (i + 1), 0, this);
this.inp.push(a);
}
var a = new Node(-10, 0, 0, this);
this.inp.push(a);
for (var i = 0; i < Math.floor(inputs / 2); i++) {
var a = new Node(-10, 10 * (i + 1), 0, this);
this.inp.push(a);
}
} else {
for (var i = inputs / 2 - 1; i >= 0; i--) {
var a = new Node(-10, -10 * (i + 1), 0, this);
this.inp.push(a);
}
for (var i = 0; i < inputs / 2; i++) {
var a = new Node(-10, 10 * (i + 1), 0, this);
this.inp.push(a);
}
}
this.output1 = new Node(20, 0, 1, this);
}
OrGate.prototype = Object.create(CircuitElement.prototype);
OrGate.prototype.constructor = OrGate;
OrGate.prototype.tooltipText = "Or Gate Tooltip : Implements logical disjunction";
OrGate.prototype.changeInputSize = changeInputSize;
OrGate.prototype.alwaysResolve = true;
OrGate.prototype.verilogType = "or";
OrGate.prototype.helplink = "https://docs.circuitverse.org/#/gates?id=or-gate";
OrGate.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.inputSize, this.bitWidth],
nodes: {
inp: this.inp.map(findNode),
output1: findNode(this.output1),
},
}
return data;
}
OrGate.prototype.resolve = function () {
var result = this.inp[0].value || 0;
if (this.isResolvable() == false) {
return;
}
for (var i = 1; i < this.inputSize; i++)
result = result | (this.inp[i].value || 0);
this.output1.value = result;
simulationArea.simulationQueue.add(this.output1);
}
OrGate.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.strokeStyle = ("rgba(0,0,0,1)");
ctx.lineWidth = correctWidth(3);
var xx = this.x;
var yy = this.y;
ctx.beginPath();
ctx.fillStyle = "white";
moveTo(ctx, -10, -20, xx, yy, this.direction, true);
bezierCurveTo(0, -20, +15, -10, 20, 0, xx, yy, this.direction);
bezierCurveTo(0 + 15, 0 + 10, 0, 0 + 20, -10, +20, xx, yy, this.direction);
bezierCurveTo(0, 0, 0, 0, -10, -20, xx, yy, this.direction);
ctx.closePath();
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
ctx.fill();
ctx.stroke();
}
OrGate.prototype.generateVerilog = function () {
return gateGenerateVerilog.call(this, '|');
}
function Stepper(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 8) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.setDimensions(20, 20);
this.output1 = new Node(20, 0, 1, this, bitWidth);
this.state = 0;
}
Stepper.prototype = Object.create(CircuitElement.prototype);
Stepper.prototype.constructor = Stepper;
Stepper.prototype.tooltipText = "Stepper ToolTip: Increase/Decrease value by selecting the stepper and using +/- keys."
Stepper.prototype.helplink = "https://docs.circuitverse.org/#/inputElements?id=stepper";
Stepper.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.bitWidth],
nodes: {
output1: findNode(this.output1),
},
values: {
state: this.state
}
}
return data;
}
Stepper.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.beginPath();
ctx.font = "20px Georgia";
ctx.fillStyle = "green";
ctx.textAlign = "center";
fillText(ctx, this.state.toString(16), this.x, this.y + 5);
ctx.fill();;
}
Stepper.prototype.resolve = function () {
this.state = Math.min(this.state, (1 << this.bitWidth) - 1);
this.output1.value = this.state;
simulationArea.simulationQueue.add(this.output1);
}
Stepper.prototype.keyDown2 = function (key) {
//console.log(key);
if (this.state + 1 < (1 << this.bitWidth) && (key == "+" || key == "=")) this.state++;
if (this.state > 0 && (key == "_" || key == "-")) this.state--;
}
function NotGate(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.rectangleObject = false;
this.setDimensions(15, 15);
this.inp1 = new Node(-10, 0, 0, this);
this.output1 = new Node(20, 0, 1, this);
}
NotGate.prototype = Object.create(CircuitElement.prototype);
NotGate.prototype.constructor = NotGate;
NotGate.prototype.tooltipText = "Not Gate Tooltip : Inverts the input digital signal.";
NotGate.prototype.verilogType = "not";
NotGate.prototype.helplink = "https://docs.circuitverse.org/#/gates?id=not-gate";
NotGate.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.bitWidth],
nodes: {
output1: findNode(this.output1),
inp1: findNode(this.inp1)
},
}
return data;
}
NotGate.prototype.resolve = function () {
if (this.isResolvable() == false) {
return;
}
this.output1.value = ((~this.inp1.value >>> 0) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
simulationArea.simulationQueue.add(this.output1);
}
NotGate.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.strokeStyle = "black";
ctx.lineWidth = correctWidth(3);
var xx = this.x;
var yy = this.y;
ctx.beginPath();
ctx.fillStyle = "white";
moveTo(ctx, -10, -10, xx, yy, this.direction);
lineTo(ctx, 10, 0, xx, yy, this.direction);
lineTo(ctx, -10, 10, xx, yy, this.direction);
ctx.closePath();
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
ctx.fill();
ctx.stroke();
ctx.beginPath();
drawCircle2(ctx, 15, 0, 5, xx, yy, this.direction);
ctx.stroke();
}
//translate to gate for single bit, assign for multi bit
NotGate.prototype.generateVerilog = function () {
return "assign " + this.output1.verilogLabel + " = ~" + this.inp1.verilogLabel + ";"
}
function ForceGate(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.setDimensions(20, 10);
this.inp1 = new Node(-20, 0, 0, this);
this.inp2 = new Node(0, 0, 0, this);
this.output1 = new Node(20, 0, 1, this);
}
ForceGate.prototype = Object.create(CircuitElement.prototype);
ForceGate.prototype.constructor = ForceGate;
ForceGate.prototype.tooltipText = "Force Gate ToolTip : ForceGate Selected.";
ForceGate.prototype.isResolvable = function () {
return (this.inp1.value != undefined || this.inp2.value != undefined)
}
ForceGate.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.bitWidth],
nodes: {
output1: findNode(this.output1),
inp1: findNode(this.inp1),
inp2: findNode(this.inp2)
},
}
return data;
}
ForceGate.prototype.resolve = function () {
if (this.inp2.value != undefined)
this.output1.value = this.inp2.value;
else
this.output1.value = this.inp1.value;
simulationArea.simulationQueue.add(this.output1);
}
ForceGate.prototype.customDraw = function () {
ctx = simulationArea.context;
var xx = this.x;
var yy = this.y;
ctx.beginPath();
ctx.fillStyle = "Black";
ctx.textAlign = "center"
fillText4(ctx, "I", -10, 0, xx, yy, this.direction, 10);
fillText4(ctx, "O", 10, 0, xx, yy, this.direction, 10);
ctx.fill();
}
function Text(x, y, scope = globalScope, label = "", fontSize = 14) {
CircuitElement.call(this, x, y, scope, "RIGHT", 1);
// this.setDimensions(15, 15);
this.fixedBitWidth = true;
this.directionFixed = true;
this.labelDirectionFixed = true;
this.setHeight(10);
this.setLabel(label);
this.setFontSize(fontSize);
}
Text.prototype = Object.create(CircuitElement.prototype);
Text.prototype.constructor = Text;
Text.prototype.propagationDelayFixed = true;
Text.prototype.tooltipText = "Text ToolTip: Use this to document your circuit."
Text.prototype.helplink = "https://docs.circuitverse.org/#/annotation?id=adding-labels";
Text.prototype.setLabel = function (str = "") {
this.label = str;
ctx = simulationArea.context;
ctx.font = this.fontSize + "px Georgia";
this.leftDimensionX = 10;
this.rightDimensionX = ctx.measureText(this.label).width + 10;
//console.log(this.leftDimensionX,this.rightDimensionX,ctx.measureText(this.label))
}
Text.prototype.setFontSize = function (fontSize = 14) {
this.fontSize = fontSize;
ctx = simulationArea.context;
ctx.font = this.fontSize + "px Georgia";
this.leftDimensionX = 10;
this.rightDimensionX = ctx.measureText(this.label).width + 10;
}
Text.prototype.customSave = function () {
var data = {
constructorParamaters: [this.label, this.fontSize],
}
return data;
}
Text.prototype.keyDown = function (key) {
if (key.length == 1) {
if (this.label == "Enter Text Here")
this.setLabel(key)
else
this.setLabel(this.label + key);
} else if (key == "Backspace") {
if (this.label == "Enter Text Here")
this.setLabel("")
else
this.setLabel(this.label.slice(0, -1));
}
}
Text.prototype.mutableProperties = {
"fontSize": {
name: "Font size: ",
type: "number",
max: "84",
min: "14",
func: "setFontSize",
}
}
Text.prototype.draw = function () {
if (this.label.length == 0 && simulationArea.lastSelected != this) this.delete();
ctx = simulationArea.context;
ctx.strokeStyle = "black";
ctx.lineWidth = 1;
var xx = this.x;
var yy = this.y;
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) {
ctx.beginPath();
ctx.fillStyle = "white";
var magicDimenstion = this.fontSize - 14;
rect2(ctx, -this.leftDimensionX, -this.upDimensionY - magicDimenstion,
this.leftDimensionX + this.rightDimensionX,
this.upDimensionY + this.downDimensionY + magicDimenstion, this.x, this.y, "RIGHT");
ctx.fillStyle = "rgba(255, 255, 32,0.1)";
ctx.fill();
ctx.stroke();
}
ctx.beginPath();
ctx.textAlign = "left";
ctx.fillStyle = "black"
fillText(ctx, this.label, xx, yy + 5, this.fontSize);
ctx.fill();
}
function TriState(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.rectangleObject = false;
this.setDimensions(15, 15);
this.inp1 = new Node(-10, 0, 0, this);
this.output1 = new Node(20, 0, 1, this);
this.state = new Node(0, 0, 0, this, 1, "Enable");
}
TriState.prototype = Object.create(CircuitElement.prototype);
TriState.prototype.constructor = TriState;
TriState.prototype.tooltipText = "TriState ToolTip : Effectively removes the output from the circuit.";
TriState.prototype.helplink = "https://docs.circuitverse.org/#/miscellaneous?id=tri-state-buffer"
// TriState.prototype.propagationDelay=10000;
TriState.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.bitWidth],
nodes: {
output1: findNode(this.output1),
inp1: findNode(this.inp1),
state: findNode(this.state),
},
}
return data;
}
// TriState.prototype.isResolvable = function(){
// return this.inp1.value!=undefined
// }
TriState.prototype.newBitWidth = function (bitWidth) {
this.inp1.bitWidth = bitWidth;
this.output1.bitWidth = bitWidth;
this.bitWidth = bitWidth;
}
TriState.prototype.resolve = function () {
if (this.isResolvable() == false) {
return;
}
if (this.state.value == 1) {
if (this.output1.value != this.inp1.value) {
this.output1.value = this.inp1.value; //>>>0)<<(32-this.bitWidth))>>>(32-this.bitWidth);
simulationArea.simulationQueue.add(this.output1);
}
simulationArea.contentionPending.clean(this);
} else {
if (this.output1.value != undefined && !simulationArea.contentionPending.contains(this)) {
this.output1.value = undefined;
simulationArea.simulationQueue.add(this.output1);
}
}
simulationArea.contentionPending.clean(this);
}
TriState.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.strokeStyle = ("rgba(0,0,0,1)");
ctx.lineWidth = correctWidth(3);
var xx = this.x;
var yy = this.y;
ctx.beginPath();
ctx.fillStyle = "white";
moveTo(ctx, -10, -15, xx, yy, this.direction);
lineTo(ctx, 20, 0, xx, yy, this.direction);
lineTo(ctx, -10, 15, xx, yy, this.direction);
ctx.closePath();
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
ctx.fill();
ctx.stroke();
}
TriState.prototype.generateVerilog = function () {
return `assign ${this.output1.verilogLabel} = (${this.state.verilogLabel}!=0) ? ${this.inp1.verilogLabel} : ${this.inp1.bitWidth}'b?;`;
}
function Buffer(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.rectangleObject = false;
this.setDimensions(15, 15);
this.state = 0;
this.preState = 0;
this.inp1 = new Node(-10, 0, 0, this);
this.reset = new Node(0, 0, 0, this, 1, "reset");
this.output1 = new Node(20, 0, 1, this);
}
Buffer.prototype = Object.create(CircuitElement.prototype);
Buffer.prototype.constructor = Buffer;
Buffer.prototype.tooltipText = "Buffer ToolTip : Isolate the input from the output.";
Buffer.prototype.helplink = "https://docs.circuitverse.org/#/miscellaneous?id=buffer"
Buffer.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.bitWidth],
nodes: {
output1: findNode(this.output1),
inp1: findNode(this.inp1),
reset: findNode(this.reset),
},
}
return data;
}
Buffer.prototype.newBitWidth = function (bitWidth) {
this.inp1.bitWidth = bitWidth;
this.output1.bitWidth = bitWidth;
this.bitWidth = bitWidth;
}
Buffer.prototype.isResolvable = function () {
return true;
}
Buffer.prototype.resolve = function () {
if (this.reset.value == 1) {
this.state = this.preState;
}
if (this.inp1.value !== undefined)
this.state = this.inp1.value;
this.output1.value = this.state;
simulationArea.simulationQueue.add(this.output1);
}
Buffer.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.strokeStyle = ("rgba(200,0,0,1)");
ctx.lineWidth = correctWidth(3);
var xx = this.x;
var yy = this.y;
ctx.beginPath();
ctx.fillStyle = "white";
moveTo(ctx, -10, -15, xx, yy, this.direction);
lineTo(ctx, 20, 0, xx, yy, this.direction);
lineTo(ctx, -10, 15, xx, yy, this.direction);
ctx.closePath();
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
ctx.fill();
ctx.stroke();
}
Buffer.prototype.generateVerilog = function () {
return "assign " + this.output1.verilogLabel + " = " + this.inp1.verilogLabel + ";"
}
function ControlledInverter(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.rectangleObject = false;
this.setDimensions(15, 15);
this.inp1 = new Node(-10, 0, 0, this);
this.output1 = new Node(30, 0, 1, this);
this.state = new Node(0, 0, 0, this, 1, "Enable");
}
ControlledInverter.prototype = Object.create(CircuitElement.prototype);
ControlledInverter.prototype.constructor = ControlledInverter;
ControlledInverter.prototype.tooltipText = "Controlled Inverter ToolTip : Controlled buffer and NOT gate.";
ControlledInverter.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.bitWidth],
nodes: {
output1: findNode(this.output1),
inp1: findNode(this.inp1),
state: findNode(this.state)
},
}
return data;
}
ControlledInverter.prototype.newBitWidth = function (bitWidth) {
this.inp1.bitWidth = bitWidth;
this.output1.bitWidth = bitWidth;
this.bitWidth = bitWidth;
}
ControlledInverter.prototype.resolve = function () {
if (this.isResolvable() == false) {
return;
}
if (this.state.value == 1) {
this.output1.value = ((~this.inp1.value >>> 0) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
simulationArea.simulationQueue.add(this.output1);
}
if (this.state.value == 0) {
this.output1.value = undefined;
}
}
ControlledInverter.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.strokeStyle = ("rgba(0,0,0,1)");
ctx.lineWidth = correctWidth(3);
var xx = this.x;
var yy = this.y;
ctx.beginPath();
ctx.fillStyle = "white";
moveTo(ctx, -10, -15, xx, yy, this.direction);
lineTo(ctx, 20, 0, xx, yy, this.direction);
lineTo(ctx, -10, 15, xx, yy, this.direction);
ctx.closePath();
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
ctx.fill();
ctx.stroke();
ctx.beginPath();
drawCircle2(ctx, 25, 0, 5, xx, yy, this.direction);
ctx.stroke();
}
ControlledInverter.prototype.generateVerilog = function () {
return `assign ${this.output1.verilogLabel} = (${this.state.verilogLabel}!=0) ? ~${this.inp1.verilogLabel} : ${this.inp1.verilogLabel};`;
}
function Adder(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.setDimensions(20, 20);
this.inpA = new Node(-20, -10, 0, this, this.bitWidth, "A");
this.inpB = new Node(-20, 0, 0, this, this.bitWidth, "B");
this.carryIn = new Node(-20, 10, 0, this, 1, "Cin");
this.sum = new Node(20, 0, 1, this, this.bitWidth, "Sum");
this.carryOut = new Node(20, 10, 1, this, 1, "Cout");
}
Adder.prototype = Object.create(CircuitElement.prototype);
Adder.prototype.constructor = Adder;
Adder.prototype.tooltipText = "Adder ToolTip : Performs addition of numbers.";
Adder.prototype.helplink = "https://docs.circuitverse.org/#/miscellaneous?id=adder"
Adder.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.bitWidth],
nodes: {
inpA: findNode(this.inpA),
inpB: findNode(this.inpB),
carryIn: findNode(this.carryIn),
carryOut: findNode(this.carryOut),
sum: findNode(this.sum)
},
}
return data;
}
Adder.prototype.isResolvable = function () {
return this.inpA.value != undefined && this.inpB.value != undefined;
}
Adder.prototype.newBitWidth = function (bitWidth) {
this.bitWidth = bitWidth;
this.inpA.bitWidth = bitWidth;
this.inpB.bitWidth = bitWidth;
this.sum.bitWidth = bitWidth;
}
Adder.prototype.resolve = function () {
if (this.isResolvable() == false) {
return;
}
var carryIn = this.carryIn.value;
if (carryIn == undefined) carryIn = 0;
var sum = this.inpA.value + this.inpB.value + carryIn;
this.sum.value = ((sum) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
this.carryOut.value = +((sum >>> (this.bitWidth)) !== 0);
simulationArea.simulationQueue.add(this.carryOut);
simulationArea.simulationQueue.add(this.sum);
}
Adder.prototype.generateVerilog = function () {
if(this.carryIn.verilogLabel) {
return `assign ${this.sum.verilogLabel} = ${this.inpA.verilogLabel} + ${this.inpB.verilogLabel} + ${this.carryIn.verilogLabel};`;
}
return `assign ${this.sum.verilogLabel} = ${this.inpA.verilogLabel} + ${this.inpB.verilogLabel};`;
}
function TwoComplement(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.rectangleObject = false;
this.setDimensions(15, 15);
this.inp1 = new Node(-10, 0, 0, this, this.bitWidth, "input stream");
this.output1 = new Node(20, 0, 1, this, this.bitWidth, "2's complement");
}
TwoComplement.prototype = Object.create(CircuitElement.prototype);
TwoComplement.prototype.constructor = TwoComplement;
TwoComplement.prototype.tooltipText = "Two's Complement Tooltip : Calculates the two's complement";
TwoComplement.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.bitWidth],
nodes: {
output1: findNode(this.output1),
inp1: findNode(this.inp1)
},
}
return data;
}
TwoComplement.prototype.resolve = function () {
if (this.isResolvable() == false) {
return;
}
let output = ((~this.inp1.value >>> 0) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
output += 1;
this.output1.value = ((output) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
simulationArea.simulationQueue.add(this.output1);
}
TwoComplement.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.strokeStyle = "black";
ctx.lineWidth = correctWidth(3);
var xx = this.x;
var yy = this.y;
ctx.beginPath();
ctx.fillStyle = "black";
fillText(ctx, "2'", xx, yy, 10);
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
ctx.fill();
ctx.beginPath();
drawCircle2(ctx, 5, 0, 15, xx, yy, this.direction);
ctx.stroke();
}
TwoComplement.prototype.generateVerilog = function () {
return `assign ${this.output1.verilogLabel} = ~${this.inp1.verilogLabel} + 1;`;
}
function Rom(x, y, scope = globalScope, data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) {
CircuitElement.call(this, x, y, scope, "RIGHT", 1);
this.fixedBitWidth = true;
this.directionFixed = true;
this.rectangleObject = false;
this.setDimensions(80, 50);
this.memAddr = new Node(-80, 0, 0, this, 4, "Address");
this.en = new Node(0, 50, 0, this, 1, "Enable");
this.dataOut = new Node(80, 0, 1, this, 8, "DataOut");
this.data = data || prompt("Enter data").split(' ').map(function (x) {
return parseInt(x, 16);
});
//console.log(this.data);
}
Rom.prototype = Object.create(CircuitElement.prototype);
Rom.prototype.constructor = Rom;
Rom.prototype.tooltipText = "Read-only memory";
Rom.prototype.helplink = "https://docs.circuitverse.org/#/memoryElements?id=rom";
Rom.prototype.isResolvable = function () {
if ((this.en.value == 1 || this.en.connections.length == 0) && this.memAddr.value != undefined) return true;
return false;
}
Rom.prototype.customSave = function () {
var data = {
constructorParamaters: [this.data],
nodes: {
memAddr: findNode(this.memAddr),
dataOut: findNode(this.dataOut),
en: findNode(this.en),
},
}
return data;
}
Rom.prototype.findPos = function () {
var i = Math.floor((simulationArea.mouseX - this.x + 35) / 20)
var j = Math.floor((simulationArea.mouseY - this.y + 35) / 16);
if (i < 0 || j < 0 || i > 3 || j > 3) return undefined;
return j * 4 + i;
}
Rom.prototype.click = function () { // toggle
this.selectedIndex = this.findPos();
}
Rom.prototype.keyDown = function (key) {
if (key == "Backspace") this.delete();
if (this.selectedIndex == undefined) return;
key = key.toLowerCase();
if (!~"1234567890abcdef".indexOf(key)) return;
else {
this.data[this.selectedIndex] = (this.data[this.selectedIndex] * 16 + parseInt(key, 16)) % 256;
}
}
Rom.prototype.customDraw = function () {
var ctx = simulationArea.context;
var xx = this.x;
var yy = this.y;
var hoverIndex = this.findPos();
ctx.strokeStyle = "black";
ctx.fillStyle = "white";
ctx.lineWidth = correctWidth(3);
ctx.beginPath();
rect2(ctx, -this.leftDimensionX, -this.upDimensionY, this.leftDimensionX + this.rightDimensionX, this.upDimensionY + this.downDimensionY, this.x, this.y, [this.direction, "RIGHT"][+this.directionFixed]);
if (hoverIndex == undefined && ((!simulationArea.shiftDown && this.hover) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this))) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
ctx.fill();
ctx.stroke();
// if (this.hover)
// ////console.log(this);
ctx.strokeStyle = "black";
ctx.fillStyle = "#fafafa";
ctx.lineWidth = correctWidth(1);
ctx.beginPath();
for (var i = 0; i < 16; i += 4) {
for (var j = i; j < i + 4; j++) {
rect2(ctx, (j % 4) * 20, i * 4, 20, 16, xx - 35, yy - 35);
}
}
ctx.fill();
ctx.stroke();
if (hoverIndex != undefined) {
ctx.beginPath();
ctx.fillStyle = "yellow";
rect2(ctx, (hoverIndex % 4) * 20, Math.floor(hoverIndex / 4) * 16, 20, 16, xx - 35, yy - 35);
ctx.fill();
ctx.stroke();
}
if (this.selectedIndex != undefined) {
ctx.beginPath();
ctx.fillStyle = "lightgreen";
rect2(ctx, (this.selectedIndex % 4) * 20, Math.floor(this.selectedIndex / 4) * 16, 20, 16, xx - 35, yy - 35);
ctx.fill();
ctx.stroke();
}
if (this.memAddr.value != undefined) {
ctx.beginPath();
ctx.fillStyle = "green";
rect2(ctx, (this.memAddr.value % 4) * 20, Math.floor(this.memAddr.value / 4) * 16, 20, 16, xx - 35, yy - 35);
ctx.fill();
ctx.stroke();
}
ctx.beginPath();
ctx.fillStyle = "Black";
fillText3(ctx, "A", -65, 5, xx, yy, fontSize = 16, font = "Georgia", textAlign = "right");
fillText3(ctx, "D", 75, 5, xx, yy, fontSize = 16, font = "Georgia", textAlign = "right");
fillText3(ctx, "En", 5, 47, xx, yy, fontSize = 16, font = "Georgia", textAlign = "right");
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "Black";
for (var i = 0; i < 16; i += 4) {
for (var j = i; j < i + 4; j++) {
var s = this.data[j].toString(16);
if (s.length < 2) s = '0' + s;
fillText3(ctx, s, (j % 4) * 20, i * 4, xx - 35 + 10, yy - 35 + 12, fontSize = 14, font = "Georgia", textAlign = "center")
}
}
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "Black";
for (var i = 0; i < 16; i += 4) {
var s = i.toString(16);
if (s.length < 2) s = '0' + s;
fillText3(ctx, s, 0, i * 4, xx - 40, yy - 35 + 12, fontSize = 14, font = "Georgia", textAlign = "right")
}
ctx.fill();
}
Rom.prototype.resolve = function () {
if (this.isResolvable() == false) {
return;
}
this.dataOut.value = this.data[this.memAddr.value];
simulationArea.simulationQueue.add(this.dataOut);
}
Rom.prototype.verilogBaseType = function() {
return this.verilogName() + (Rom.selSizes.length-1);
}
//this code to generate Verilog
Rom.prototype.generateVerilog = function () {
Rom.selSizes.push(this.data);
return CircuitElement.prototype.generateVerilog.call(this);
}
//This code to determine what sizes are used to generate the needed modules
Rom.selSizes = [];
//generate the needed modules
Rom.moduleVerilog = function () {
var output = "";
for (var i = 0; i < Rom.selSizes.length; i++) {
output += `
module Rom${i}(dout, addr, en);
parameter WIDTH = 8;
parameter ADDR = 4;
output reg [WIDTH-1:0] dout;
input [ADDR-1:0] addr;
input en;
always @ (*) begin
if (en == 0)
dout = {WIDTH{1'bz}};
else
case (addr)
`;
for (var j = 0; j < (1 << 4); j++) {
output += " " + j + " : dout = " + Rom.selSizes[i][j] + ";\n";
}
output += ` endcase
end
endmodule
`;
}
return output;
}
//reset the sized before Verilog generation
Rom.resetVerilog = function () {
Rom.selSizes = [];
}
/*
//This is a Rom without a clock - not normal
Rom.moduleVerilog = function () {
var output = `
module ROM(dout, addr, en);
parameter WIDTH = 8;
parameter ADDR = 4;
output [WIDTH-1:0] dout;
input [ADDR-1:0] addr;
input en;
always @ (*) begin
if (en)
case (addr) begin
`;
for (var i = 0; i < (1 << 4); i++) {
output += " " + i + " : dout = " + this.data[i];
}
output += `
endcase
else
dout = WIDTH'z;
end
endmodule
`;
return output;
}
*/
function Splitter(x, y, scope = globalScope, dir = "RIGHT", bitWidth = undefined, bitWidthSplit = undefined) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.rectangleObject = false;
this.bitWidthSplit = bitWidthSplit || prompt("Enter bitWidth Split").split(' ').filter(x => x != '').map(function(x) {
return parseInt(x, 10)||1;
});
this.splitCount = this.bitWidthSplit.length;
this.setDimensions(10, (this.splitCount - 1) * 10 + 10);
this.yOffset = (this.splitCount / 2 - 1) * 20;
this.inp1 = new Node(-10, 10 + this.yOffset, 0, this, this.bitWidth);
this.outputs = [];
// this.prevOutValues=new Array(this.splitCount)
for (var i = 0; i < this.splitCount; i++)
this.outputs.push(new Node(20, i * 20 - this.yOffset - 20, 0, this, this.bitWidthSplit[i]));
this.prevInpValue = undefined;
}
Splitter.prototype = Object.create(CircuitElement.prototype);
Splitter.prototype.constructor = Splitter;
Splitter.prototype.tooltipText = "Splitter ToolTip: Split multiBit Input into smaller bitwidths or vice versa."
Splitter.prototype.helplink = "https://docs.circuitverse.org/#/splitter";
Splitter.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.bitWidth, this.bitWidthSplit],
nodes: {
outputs: this.outputs.map(findNode),
inp1: findNode(this.inp1)
},
}
return data;
}
Splitter.prototype.removePropagation = function () {
if (this.inp1.value == undefined) {
let i = 0;
for (i = 0; i < this.outputs.length; i++) { // False Hit
if (this.outputs[i].value == undefined) return;
}
for (i = 0; i < this.outputs.length; i++) {
if (this.outputs[i].value !== undefined) {
this.outputs[i].value = undefined;
simulationArea.simulationQueue.add(this.outputs[i]);
}
}
} else {
if (this.inp1.value !== undefined) {
this.inp1.value = undefined;
simulationArea.simulationQueue.add(this.inp1);
}
}
this.prevInpValue = undefined;
}
Splitter.prototype.isResolvable = function () {
var resolvable = false;
if (this.inp1.value != this.prevInpValue) {
if (this.inp1.value !== undefined) return true;
return false;
}
var i;
for (i = 0; i < this.splitCount; i++)
if (this.outputs[i].value === undefined) break;
if (i == this.splitCount) resolvable = true;
return resolvable;
}
Splitter.prototype.resolve = function () {
if (this.isResolvable() == false) {
return;
}
if (this.inp1.value !== undefined && this.inp1.value != this.prevInpValue) {
var bitCount = 1;
for (var i = 0; i < this.splitCount; i++) {
var bitSplitValue = extractBits(this.inp1.value, bitCount, bitCount + this.bitWidthSplit[i] - 1);
if (this.outputs[i].value != bitSplitValue) {
if (this.outputs[i].value != bitSplitValue) {
this.outputs[i].value = bitSplitValue;
simulationArea.simulationQueue.add(this.outputs[i]);
}
}
bitCount += this.bitWidthSplit[i];
}
} else {
var n = 0;
for (var i = this.splitCount - 1; i >= 0; i--) {
n <<= this.bitWidthSplit[i];
n += this.outputs[i].value;
}
if (this.inp1.value != (n >>> 0)) {
this.inp1.value = (n >>> 0);
simulationArea.simulationQueue.add(this.inp1);
}
// else if (this.inp1.value != n) {
// console.log("CONTENTION");
// }
}
this.prevInpValue = this.inp1.value;
}
Splitter.prototype.reset = function () {
this.prevInpValue = undefined;
}
Splitter.prototype.processVerilog = function () {
// Combiner
if (this.inp1.verilogLabel == "") {
this.isSplitter = false;
this.inp1.verilogLabel = this.verilogLabel + "_cmb";
if (!this.scope.verilogWireList[this.bitWidth].contains(this.inp1.verilogLabel))
this.scope.verilogWireList[this.bitWidth].push(this.inp1.verilogLabel);
this.scope.stack.push(this.inp1);
return;
}
// Splitter
this.isSplitter = true;
for (var j = 0; j < this.outputs.length; j++) {
var bitCount = 0;
var inpLabel = this.inp1.verilogLabel;
// Already Split Regex
var re = /^(.*)\[(\d*):(\d*)\]$/;
if(re.test(inpLabel)) {
var matches = inpLabel.match(re);
inpLabel = matches[1];
bitCount = parseInt(matches[3]);
}
for (var i = 0; i < this.splitCount; i++) {
if (this.bitWidthSplit[i] > 1)
var label = inpLabel + '[' + (bitCount + this.bitWidthSplit[i] - 1) + ":" + bitCount + "]";
else
var label = inpLabel + '[' + bitCount + "]";
if (this.outputs[i].verilogLabel != label) {
this.outputs[i].verilogLabel = label;
this.scope.stack.push(this.outputs[i]);
}
bitCount += this.bitWidthSplit[i];
}
}
}
//added to generate Splitter INPUTS
Splitter.prototype.generateVerilog = function () {
var res = "";
if (!this.isSplitter) {
res += "assign " + this.inp1.verilogLabel + " = {";
for (var i = this.outputs.length - 1; i > 0; i--)
res += this.outputs[i].verilogLabel + ",";
res += this.outputs[0].verilogLabel + "};";
}
return res;
}
Splitter.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.strokeStyle = ["black", "brown"][((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) + 0];
ctx.lineWidth = correctWidth(3);
var xx = this.x;
var yy = this.y;
ctx.beginPath();
// drawLine(ctx, -10, -10, xx, y2, color, width)
moveTo(ctx, -10, 10 + this.yOffset, xx, yy, this.direction);
lineTo(ctx, 0, 0 + this.yOffset, xx, yy, this.direction);
lineTo(ctx, 0, -20 * (this.splitCount - 1) + this.yOffset, xx, yy, this.direction);
var bitCount = 0;
for (var i = this.splitCount - 1; i >= 0; i--) {
moveTo(ctx, 0, -20 * i + this.yOffset, xx, yy, this.direction);
lineTo(ctx, 20, -20 * i + this.yOffset, xx, yy, this.direction);
}
ctx.stroke();
ctx.beginPath();
ctx.fillStyle = "black";
for (var i = this.splitCount - 1; i >= 0; i--) {
fillText2(ctx, bitCount + ":" + (bitCount + this.bitWidthSplit[this.splitCount - i - 1]), 12, -20 * i + this.yOffset + 10, xx, yy, this.direction);
bitCount += this.bitWidthSplit[this.splitCount - i - 1];
}
ctx.fill();
}
function Ground(x, y, scope = globalScope, bitWidth = 1) {
CircuitElement.call(this, x, y, scope, "RIGHT", bitWidth);
this.rectangleObject = false;
this.setDimensions(10, 10);
this.directionFixed = true;
this.output1 = new Node(0, -10, 1, this);
}
Ground.prototype = Object.create(CircuitElement.prototype);
Ground.prototype.tooltipText = "Ground: All bits are Low(0).";
Ground.prototype.helplink = "https://docs.circuitverse.org/#/inputElements?id=ground";
Ground.prototype.constructor = Ground;
Ground.prototype.propagationDelay = 0;
Ground.prototype.customSave = function () {
var data = {
nodes: {
output1: findNode(this.output1)
},
values: {
state: this.state
},
constructorParamaters: [this.direction, this.bitWidth]
}
return data;
}
Ground.prototype.resolve = function () {
this.output1.value = 0;
simulationArea.simulationQueue.add(this.output1);
}
Ground.prototype.customSave = function () {
var data = {
nodes: {
output1: findNode(this.output1)
},
constructorParamaters: [this.bitWidth],
}
return data;
}
Ground.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = ["black", "brown"][((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) + 0];
ctx.lineWidth = correctWidth(3);
var xx = this.x;
var yy = this.y;
moveTo(ctx, 0, -10, xx, yy, this.direction);
lineTo(ctx, 0, 0, xx, yy, this.direction);
moveTo(ctx, -10, 0, xx, yy, this.direction);
lineTo(ctx, 10, 0, xx, yy, this.direction);
moveTo(ctx, -6, 5, xx, yy, this.direction);
lineTo(ctx, 6, 5, xx, yy, this.direction);
moveTo(ctx, -2.5, 10, xx, yy, this.direction);
lineTo(ctx, 2.5, 10, xx, yy, this.direction);
ctx.stroke();
}
//Ground translated into assign
Ground.prototype.generateVerilog = function () {
return `assign ${this.output1.verilogLabel} = ${this.bitWidth}'b0;`;
}
function Power(x, y, scope = globalScope, bitWidth = 1) {
CircuitElement.call(this, x, y, scope, "RIGHT", bitWidth);
this.directionFixed = true;
this.rectangleObject = false;
this.setDimensions(10, 10);
this.output1 = new Node(0, 10, 1, this);
}
Power.prototype = Object.create(CircuitElement.prototype);
Power.prototype.tooltipText = "Power: All bits are High(1).";
Power.prototype.helplink = "https://docs.circuitverse.org/#/inputElements?id=power";
Power.prototype.constructor = Power;
Power.prototype.propagationDelay = 0;
Power.prototype.resolve = function () {
this.output1.value = ~0 >>> (32 - this.bitWidth);
simulationArea.simulationQueue.add(this.output1);
}
Power.prototype.customSave = function () {
var data = {
nodes: {
output1: findNode(this.output1)
},
constructorParamaters: [this.bitWidth],
}
return data;
}
Power.prototype.customDraw = function () {
ctx = simulationArea.context;
var xx = this.x;
var yy = this.y;
ctx.beginPath();
ctx.strokeStyle = ("rgba(0,0,0,1)");
ctx.lineWidth = correctWidth(3);
ctx.fillStyle = "green";
moveTo(ctx, 0, -10, xx, yy, this.direction);
lineTo(ctx, -10, 0, xx, yy, this.direction);
lineTo(ctx, 10, 0, xx, yy, this.direction);
lineTo(ctx, 0, -10, xx, yy, this.direction);
ctx.closePath();
ctx.stroke();
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
ctx.fill();
moveTo(ctx, 0, 0, xx, yy, this.direction);
lineTo(ctx, 0, 10, xx, yy, this.direction);
ctx.stroke();
}
//Power translated into assign
Power.prototype.generateVerilog = function () {
return `assign ${this.output1.verilogLabel} = ~${this.bitWidth}'b0;`;
}
function get_next_position(x = 0, scope = globalScope) {
var possible_y = 20;
var done = {}
for (var i = 0; i < scope.Input.length; i++)
if (scope.Input[i].layoutProperties.x == x)
done[scope.Input[i].layoutProperties.y] = 1
for (var i = 0; i < scope.Output.length; i++)
if (scope.Output[i].layoutProperties.x == x)
done[scope.Output[i].layoutProperties.y] = 1
// console.log(done)
// return possible_y;
while (done[possible_y] || done[possible_y + 10] || done[possible_y - 10])
possible_y += 10;
var height = possible_y + 20;
if (height > scope.layout.height) {
var old_height = scope.layout.height
scope.layout.height = height;
for (var i = 0; i < scope.Input.length; i++) {
if (scope.Input[i].layoutProperties.y == old_height)
scope.Input[i].layoutProperties.y = scope.layout.height;
}
for (var i = 0; i < scope.Output.length; i++) {
if (scope.Output[i].layoutProperties.y == old_height)
scope.Output[i].layoutProperties.y = scope.layout.height;
}
}
return possible_y;
}
function Input(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1, layoutProperties) {
if (layoutProperties)
this.layoutProperties = layoutProperties;
else {
this.layoutProperties = {
x: 0,
y: get_next_position(0, scope),
id: generateId(),
}
}
// Call base class constructor
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.state = 0;
this.orientationFixed = false;
this.state = bin2dec(this.state); // in integer format
this.output1 = new Node(this.bitWidth * 10, 0, 1, this);
this.wasClicked = false;
this.directionFixed = true;
this.setWidth(this.bitWidth * 10);
this.rectangleObject = true; // Trying to make use of base class draw
}
Input.prototype = Object.create(CircuitElement.prototype);
Input.prototype.constructor = Input;
Input.prototype.tooltipText = "Input ToolTip: Toggle the individual bits by clicking on them."
Input.prototype.helplink = "https://docs.circuitverse.org/#/inputElements?id=input";
Input.prototype.propagationDelay = 0;
Input.prototype.customSave = function () {
var data = {
nodes: {
output1: findNode(this.output1)
},
values: {
state: this.state
},
constructorParamaters: [this.direction, this.bitWidth, this.layoutProperties]
}
return data;
}
Input.prototype.resolve = function () {
this.output1.value = this.state;
simulationArea.simulationQueue.add(this.output1);
}
// Check if override is necessary!!
Input.prototype.newBitWidth = function (bitWidth) {
if (bitWidth < 1) return;
var diffBitWidth = bitWidth - this.bitWidth;
this.bitWidth = bitWidth; //||parseInt(prompt("Enter bitWidth"),10);
this.setWidth(this.bitWidth * 10);
this.state = 0;
this.output1.bitWidth = bitWidth;
if (this.direction == "RIGHT") {
this.x -= 10 * diffBitWidth;
this.output1.x = 10 * this.bitWidth;
this.output1.leftx = 10 * this.bitWidth;
} else if (this.direction == "LEFT") {
this.x += 10 * diffBitWidth;
this.output1.x = -10 * this.bitWidth;
this.output1.leftx = 10 * this.bitWidth;
}
}
Input.prototype.click = function () { // toggle
var pos = this.findPos();
if (pos == 0) pos = 1; // minor correction
if (pos < 1 || pos > this.bitWidth) return;
this.state = ((this.state >>> 0) ^ (1 << (this.bitWidth - pos))) >>> 0;
}
Input.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = ("rgba(0,0,0,1)");
ctx.lineWidth = correctWidth(3);
var xx = this.x;
var yy = this.y;
ctx.beginPath();
ctx.fillStyle = "green";
ctx.textAlign = "center";
var bin = dec2bin(this.state, this.bitWidth);
for (var k = 0; k < this.bitWidth; k++)
fillText(ctx, bin[k], xx - 10 * this.bitWidth + 10 + (k) * 20, yy + 5);
ctx.fill();
}
Input.prototype.newDirection = function (dir) {
if (dir == this.direction) return;
this.direction = dir;
this.output1.refresh();
if (dir == "RIGHT" || dir == "LEFT") {
this.output1.leftx = 10 * this.bitWidth;
this.output1.lefty = 0;
} else {
this.output1.leftx = 10; //10*this.bitWidth;
this.output1.lefty = 0;
}
this.output1.refresh();
this.labelDirection = oppositeDirection[this.direction];
}
Input.prototype.findPos = function () {
return Math.round((simulationArea.mouseX - this.x + 10 * this.bitWidth) / 20.0);
}
function Output(x, y, scope = globalScope, dir = "LEFT", bitWidth = 1, layoutProperties) {
// Calling base class constructor
if (layoutProperties)
this.layoutProperties = layoutProperties
else {
this.layoutProperties = {
x: scope.layout.width,
y: get_next_position(scope.layout.width, scope),
id: generateId(),
}
}
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.rectangleObject = false;
this.directionFixed = true;
this.orientationFixed = false;
this.setDimensions(this.bitWidth * 10, 10);
this.inp1 = new Node(this.bitWidth * 10, 0, 0, this);
}
Output.prototype = Object.create(CircuitElement.prototype);
Output.prototype.constructor = Output;
Output.prototype.tooltipText = "Output ToolTip: Simple output element showing output in binary.";
Output.prototype.helplink = "https://docs.circuitverse.org/#/outputs?id=output";
Output.prototype.propagationDelay = 0;
Output.prototype.generateVerilog = function () {
return "assign " + this.verilogLabel + " = " + this.inp1.verilogLabel + ";"
}
Output.prototype.customSave = function () {
var data = {
nodes: {
inp1: findNode(this.inp1)
},
constructorParamaters: [this.direction, this.bitWidth, this.layoutProperties],
}
return data;
}
Output.prototype.newBitWidth = function (bitWidth) {
if (bitWidth < 1) return;
var diffBitWidth = bitWidth - this.bitWidth;
this.state = undefined;
this.inp1.bitWidth = bitWidth;
this.bitWidth = bitWidth;
this.setWidth(10 * this.bitWidth);
if (this.direction == "RIGHT") {
this.x -= 10 * diffBitWidth;
this.inp1.x = 10 * this.bitWidth;
this.inp1.leftx = 10 * this.bitWidth;
} else if (this.direction == "LEFT") {
this.x += 10 * diffBitWidth;
this.inp1.x = -10 * this.bitWidth;
this.inp1.leftx = 10 * this.bitWidth;
}
}
Output.prototype.customDraw = function () {
this.state = this.inp1.value;
ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = ["blue", "red"][+(this.inp1.value == undefined)];
ctx.fillStyle = "white";
ctx.lineWidth = correctWidth(3);
var xx = this.x;
var yy = this.y;
rect2(ctx, -10 * this.bitWidth, -10, 20 * this.bitWidth, 20, xx, yy, "RIGHT");
if ((this.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";
if (this.state === undefined)
var bin = 'x'.repeat(this.bitWidth);
else
var bin = dec2bin(this.state, this.bitWidth);
for (var k = 0; k < this.bitWidth; k++)
fillText(ctx, bin[k], xx - 10 * this.bitWidth + 10 + (k) * 20, yy + 5);
ctx.fill();
}
Output.prototype.newDirection = function (dir) {
if (dir == this.direction) return;
this.direction = dir;
this.inp1.refresh();
if (dir == "RIGHT" || dir == "LEFT") {
this.inp1.leftx = 10 * this.bitWidth;
this.inp1.lefty = 0;
} else {
this.inp1.leftx = 10; //10*this.bitWidth;
this.inp1.lefty = 0;
}
this.inp1.refresh();
this.labelDirection = oppositeDirection[this.direction];
}
function BitSelector(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 2, selectorBitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.setDimensions(20, 20);
this.selectorBitWidth = selectorBitWidth || parseInt(prompt("Enter Selector bitWidth"), 10);
this.rectangleObject = false;
this.inp1 = new Node(-20, 0, 0, this, this.bitWidth, "Input");
this.output1 = new Node(20, 0, 1, this, 1, "Output");
this.bitSelectorInp = new Node(0, 20, 0, this, this.selectorBitWidth, "Bit Selector");
}
BitSelector.prototype = Object.create(CircuitElement.prototype);
BitSelector.prototype.constructor = BitSelector;
BitSelector.prototype.tooltipText = "BitSelector ToolTip : Divides input bits into several equal-sized groups.";
BitSelector.prototype.helplink = "https://docs.circuitverse.org/#/decodersandplexers?id=bit-selector";
BitSelector.prototype.changeSelectorBitWidth = function (size) {
if (size == undefined || size < 1 || size > 32) return;
this.selectorBitWidth = size;
this.bitSelectorInp.bitWidth = size;
}
BitSelector.prototype.mutableProperties = {
"selectorBitWidth": {
name: "Selector Bit Width: ",
type: "number",
max: "32",
min: "1",
func: "changeSelectorBitWidth",
}
}
BitSelector.prototype.customSave = function () {
var data = {
nodes: {
inp1: findNode(this.inp1),
output1: findNode(this.output1),
bitSelectorInp: findNode(this.bitSelectorInp)
},
constructorParamaters: [this.direction, this.bitWidth, this.selectorBitWidth],
}
return data;
}
BitSelector.prototype.newBitWidth = function (bitWidth) {
this.inp1.bitWidth = bitWidth;
this.bitWidth = bitWidth;
}
BitSelector.prototype.resolve = function () {
this.output1.value = extractBits(this.inp1.value, this.bitSelectorInp.value + 1, this.bitSelectorInp.value + 1); //(this.inp1.value^(1<<this.bitSelectorInp.value))==(1<<this.bitSelectorInp.value);
simulationArea.simulationQueue.add(this.output1);
}
BitSelector.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = ["blue", "red"][(this.state === undefined) + 0];
ctx.fillStyle = "white";
ctx.lineWidth = correctWidth(3);
var xx = this.x;
var yy = this.y;
rect(ctx, xx - 20, yy - 20, 40, 40);
if ((this.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";
if (this.bitSelectorInp.value === undefined)
var bit = 'x';
else
var bit = this.bitSelectorInp.value;
fillText(ctx, bit, xx, yy + 5);
ctx.fill();
}
BitSelector.prototype.generateVerilog = function () {
return `assign ${this.output1.verilogLabel} = ${this.inp1.verilogLabel} >> ${this.bitSelectorInp.verilogLabel};`;
}
function ConstantVal(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1, state = "0") {
this.state = state || prompt("Enter value");
CircuitElement.call(this, x, y, scope, dir, this.state.length);
this.setDimensions(10 * this.state.length, 10);
this.bitWidth = bitWidth || this.state.length;
this.directionFixed = true;
this.orientationFixed = false;
this.rectangleObject = false;
this.output1 = new Node(this.bitWidth * 10, 0, 1, this);
this.wasClicked = false;
this.label = "";
}
ConstantVal.prototype = Object.create(CircuitElement.prototype);
ConstantVal.prototype.constructor = ConstantVal;
ConstantVal.prototype.tooltipText = "Constant ToolTip: Bits are fixed. Double click element to change the bits."
ConstantVal.prototype.helplink = "https://docs.circuitverse.org/#/inputElements?id=constantval";
ConstantVal.prototype.propagationDelay = 0;
ConstantVal.prototype.customSave = function () {
var data = {
nodes: {
output1: findNode(this.output1)
},
constructorParamaters: [this.direction, this.bitWidth, this.state],
}
return data;
}
ConstantVal.prototype.resolve = function () {
this.output1.value = bin2dec(this.state);
simulationArea.simulationQueue.add(this.output1);
}
ConstantVal.prototype.dblclick = function () {
this.state = prompt("Re enter the value") || "0";
//console.log(this.state);
this.newBitWidth(this.state.toString().length);
//console.log(this.state, this.bitWidth);
}
ConstantVal.prototype.newBitWidth = function (bitWidth) {
if (bitWidth > this.state.length) this.state = '0'.repeat(bitWidth - this.state.length) + this.state;
else if (bitWidth < this.state.length) this.state = this.state.slice(this.bitWidth - bitWidth);
this.bitWidth = bitWidth; //||parseInt(prompt("Enter bitWidth"),10);
this.output1.bitWidth = bitWidth;
this.setDimensions(10 * this.bitWidth, 10);
if (this.direction == "RIGHT") {
this.output1.x = 10 * this.bitWidth;
this.output1.leftx = 10 * this.bitWidth;
} else if (this.direction == "LEFT") {
this.output1.x = -10 * this.bitWidth;
this.output1.leftx = 10 * this.bitWidth;
}
}
ConstantVal.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = ("rgba(0,0,0,1)");
ctx.fillStyle = "white";
ctx.lineWidth = correctWidth(1);
var xx = this.x;
var yy = this.y;
rect2(ctx, -10 * this.bitWidth, -10, 20 * this.bitWidth, 20, xx, yy, "RIGHT");
if ((this.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 bin = this.state; //dec2bin(this.state,this.bitWidth);
for (var k = 0; k < this.bitWidth; k++)
fillText(ctx, bin[k], xx - 10 * this.bitWidth + 10 + (k) * 20, yy + 5);
ctx.fill();
}
ConstantVal.prototype.newDirection = function (dir) {
if (dir == this.direction) return;
this.direction = dir;
this.output1.refresh();
if (dir == "RIGHT" || dir == "LEFT") {
this.output1.leftx = 10 * this.bitWidth;
this.output1.lefty = 0;
} else {
this.output1.leftx = 10; //10*this.bitWidth;
this.output1.lefty = 0;
}
this.output1.refresh();
this.labelDirection = oppositeDirection[this.direction];
}
//ConstantValue translated into assign
ConstantVal.prototype.generateVerilog = function () {
return `assign ${this.output1.verilogLabel} = ${this.bitWidth}'b${this.state};`;
}
function NorGate(x, y, scope = globalScope, dir = "RIGHT", inputs = 2, bitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.rectangleObject = false;
this.setDimensions(15, 20);
this.inp = [];
this.inputSize = inputs;
if (inputs % 2 == 1) {
for (var i = 0; i < inputs / 2 - 1; i++) {
var a = new Node(-10, -10 * (i + 1), 0, this);
this.inp.push(a);
}
var a = new Node(-10, 0, 0, this);
this.inp.push(a);
for (var i = inputs / 2 + 1; i < inputs; i++) {
var a = new Node(-10, 10 * (i + 1 - inputs / 2 - 1), 0, this);
this.inp.push(a);
}
} else {
for (var i = 0; i < inputs / 2; i++) {
var a = new Node(-10, -10 * (i + 1), 0, this);
this.inp.push(a);
}
for (var i = inputs / 2; i < inputs; i++) {
var a = new Node(-10, 10 * (i + 1 - inputs / 2), 0, this);
this.inp.push(a);
}
}
this.output1 = new Node(30, 0, 1, this);
}
NorGate.prototype = Object.create(CircuitElement.prototype);
NorGate.prototype.constructor = NorGate;
NorGate.prototype.tooltipText = "Nor Gate ToolTip : Combination of OR gate and NOT gate.";
NorGate.prototype.alwaysResolve = true;
NorGate.prototype.changeInputSize = changeInputSize;
NorGate.prototype.verilogType = "nor";
NorGate.prototype.helplink = "https://docs.circuitverse.org/#/gates?id=nor-gate";
NorGate.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.inputSize, this.bitWidth],
nodes: {
inp: this.inp.map(findNode),
output1: findNode(this.output1)
},
}
return data;
}
NorGate.prototype.resolve = function () {
var result = this.inp[0].value || 0;
for (var i = 1; i < this.inputSize; i++)
result = result | (this.inp[i].value || 0);
result = ((~result >>> 0) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
this.output1.value = result
simulationArea.simulationQueue.add(this.output1);
}
NorGate.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.strokeStyle = ("rgba(0,0,0,1)");
ctx.lineWidth = correctWidth(3);
var xx = this.x;
var yy = this.y;
ctx.beginPath();
ctx.fillStyle = "white";
moveTo(ctx, -10, -20, xx, yy, this.direction, true);
bezierCurveTo(0, -20, +15, -10, 20, 0, xx, yy, this.direction);
bezierCurveTo(0 + 15, 0 + 10, 0, 0 + 20, -10, +20, xx, yy, this.direction);
bezierCurveTo(0, 0, 0, 0, -10, -20, xx, yy, this.direction);
ctx.closePath();
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.5)";
ctx.fill();
ctx.stroke();
ctx.beginPath();
drawCircle2(ctx, 25, 0, 5, xx, yy, this.direction);
ctx.stroke();
//for debugging
}
//translate to gate for single bit, assign for multi bit
NorGate.prototype.generateVerilog = function () {
return gateGenerateVerilog.call(this, '|', true);
}
function DigitalLed(x, y, scope = globalScope, color = "Red") {
// Calling base class constructor
CircuitElement.call(this, x, y, scope, "UP", 1);
this.rectangleObject = false;
this.setDimensions(10, 20);
this.inp1 = new Node(-40, 0, 0, this, 1);
this.directionFixed = true;
this.fixedBitWidth = true;
this.color = color;
var temp = colorToRGBA(this.color)
this.actualColor = "rgba(" + temp[0] + "," + temp[1] + "," + temp[2] + "," + 0.8 + ")";
}
DigitalLed.prototype = Object.create(CircuitElement.prototype);
DigitalLed.prototype.constructor = DigitalLed;
/* Outdated, was translating into Output
DigitalLed.prototype.generateVerilog = function () {
return "assign " + this.label + " = " + this.inp1.verilogLabel + ";"
}
*/
/*
//DigitalLed translated into $display
DigitalLed.prototype.generateVerilog = function () {
var output = "";
output += "\n";
output += " always @ (" + this.inp1.verilogLabel + ")\n";
output += " $display(\"" + this.inp1.verilogLabel + " = %d\", "
+ this.inp1.verilogLabel + ");\n";
return output;
}
*/
DigitalLed.prototype.tooltipText = "Digital Led ToolTip: Digital LED glows high when input is High(1)."
DigitalLed.prototype.helplink = "https://docs.circuitverse.org/#/outputs?id=digital-led";
DigitalLed.prototype.customSave = function () {
var data = {
constructorParamaters: [this.color],
nodes: {
inp1: findNode(this.inp1)
},
}
return data;
}
DigitalLed.prototype.mutableProperties = {
"color": {
name: "Color: ",
type: "text",
func: "changeColor",
},
}
DigitalLed.prototype.changeColor = function (value) {
if (validColor(value)) {
this.color = value;
var temp = colorToRGBA(this.color)
this.actualColor = "rgba(" + temp[0] + "," + temp[1] + "," + temp[2] + "," + 0.8 + ")";
}
}
DigitalLed.prototype.customDraw = function () {
ctx = simulationArea.context;
var xx = this.x;
var yy = this.y;
ctx.strokeStyle = "#e3e4e5";
ctx.lineWidth = correctWidth(3);
ctx.beginPath();
moveTo(ctx, -20, 0, xx, yy, this.direction);
lineTo(ctx, -40, 0, xx, yy, this.direction);
ctx.stroke();
ctx.strokeStyle = "#d3d4d5";
ctx.fillStyle = ["rgba(227,228,229,0.8)", this.actualColor][this.inp1.value || 0];
ctx.lineWidth = correctWidth(1);
ctx.beginPath();
moveTo(ctx, -15, -9, xx, yy, this.direction);
lineTo(ctx, 0, -9, xx, yy, this.direction);
arc(ctx, 0, 0, 9, (-Math.PI / 2), (Math.PI / 2), xx, yy, this.direction);
lineTo(ctx, -15, 9, xx, yy, this.direction);
lineTo(ctx, -18, 12, xx, yy, this.direction);
arc(ctx, 0, 0, Math.sqrt(468), ((Math.PI / 2) + Math.acos(12 / Math.sqrt(468))), ((-Math.PI / 2) - Math.asin(18 / Math.sqrt(468))), xx, yy, this.direction);
lineTo(ctx, -15, -9, xx, yy, this.direction);
ctx.stroke();
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
ctx.fill();
}
//Use $display
DigitalLed.prototype.generateVerilog = function () {
var label = this.label ? this.verilogLabel : this.inp1.verilogLabel;
return `
always @ (*)
$display("DigitalLed:${label}=%d", ${this.inp1.verilogLabel});`;
}
/* Outdated, was translating into Output
DigitalLed.prototype.generateVerilog = function () {
return "assign " + this.label + " = " + this.inp1.verilogLabel + ";"
}
*/
//DigitalLed translated into $display
// DigitalLed.prototype.generateVerilog = function () {
// var output = "";
// output += " always @ (" + this.inp1.verilogLabel + ")\n";
// output += " $display(\"" + this.inp1.verilogLabel + " = %d\", "
// + this.inp1.verilogLabel + ");";
// return output;
// }
function VariableLed(x, y, scope = globalScope) {
// Calling base class constructor
CircuitElement.call(this, x, y, scope, "UP", 8);
this.rectangleObject = false;
this.setDimensions(10, 20);
this.inp1 = new Node(-40, 0, 0, this, 8);
this.directionFixed = true;
this.fixedBitWidth = true;
}
VariableLed.prototype = Object.create(CircuitElement.prototype);
VariableLed.prototype.constructor = VariableLed;
VariableLed.prototype.tooltipText = "Variable Led ToolTip: Variable LED inputs an 8 bit value and glows with a proportional intensity."
VariableLed.prototype.helplink = "https://docs.circuitverse.org/#/outputs?id=variable-led";
VariableLed.prototype.customSave = function () {
var data = {
nodes: {
inp1: findNode(this.inp1)
},
}
return data;
}
VariableLed.prototype.customDraw = function () {
ctx = simulationArea.context;
var xx = this.x;
var yy = this.y;
ctx.strokeStyle = "#353535";
ctx.lineWidth = correctWidth(3);
ctx.beginPath();
moveTo(ctx, -20, 0, xx, yy, this.direction);
lineTo(ctx, -40, 0, xx, yy, this.direction);
ctx.stroke();
var c = this.inp1.value;
var alpha = c / 255;
ctx.strokeStyle = "#090a0a";
ctx.fillStyle = ["rgba(255,29,43," + alpha + ")", "rgba(227, 228, 229, 0.8)"][(c === undefined || c == 0) + 0];
ctx.lineWidth = correctWidth(1);
ctx.beginPath();
moveTo(ctx, -20, -9, xx, yy, this.direction);
lineTo(ctx, 0, -9, xx, yy, this.direction);
arc(ctx, 0, 0, 9, (-Math.PI / 2), (Math.PI / 2), xx, yy, this.direction);
lineTo(ctx, -20, 9, xx, yy, this.direction);
/*lineTo(ctx,-18,12,xx,yy,this.direction);
arc(ctx,0,0,Math.sqrt(468),((Math.PI/2) + Math.acos(12/Math.sqrt(468))),((-Math.PI/2) - Math.asin(18/Math.sqrt(468))),xx,yy,this.direction);
*/
lineTo(ctx, -20, -9, xx, yy, this.direction);
ctx.stroke();
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
ctx.fill();
}
VariableLed.prototype.generateVerilog = function () {
return `
always @ (*)
$display("VeriableLed:${this.inp1.verilogLabel}=%d", ${this.inp1.verilogLabel});`;
}
function Button(x, y, scope = globalScope, dir = "RIGHT") {
CircuitElement.call(this, x, y, scope, dir, 1);
this.state = 0;
this.output1 = new Node(30, 0, 1, this);
this.wasClicked = false;
this.rectangleObject = false;
this.setDimensions(10, 10);
}
Button.prototype = Object.create(CircuitElement.prototype);
Button.prototype.constructor = Button;
Button.prototype.tooltipText = "Button ToolTip: High(1) when pressed and Low(0) when released."
Button.prototype.helplink = "https://docs.circuitverse.org/#/inputElements?id=button";
Button.prototype.propagationDelay = 0;
Button.prototype.customSave = function () {
var data = {
nodes: {
output1: findNode(this.output1)
},
values: {
state: this.state
},
constructorParamaters: [this.direction, this.bitWidth]
}
return data;
}
Button.prototype.resolve = function () {
if (this.wasClicked) {
this.state = 1;
this.output1.value = this.state;
} else {
this.state = 0;
this.output1.value = this.state;
}
simulationArea.simulationQueue.add(this.output1);
}
Button.prototype.customDraw = function () {
ctx = simulationArea.context;
var xx = this.x;
var yy = this.y;
ctx.fillStyle = "#ddd";
ctx.strokeStyle = "#353535";
ctx.lineWidth = correctWidth(5);
ctx.beginPath();
moveTo(ctx, 10, 0, xx, yy, this.direction);
lineTo(ctx, 30, 0, xx, yy, this.direction);
ctx.stroke();
ctx.beginPath();
drawCircle2(ctx, 0, 0, 12, xx, yy, this.direction);
ctx.stroke();
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this))
ctx.fillStyle = "rgba(232, 13, 13,0.6)"
if (this.wasClicked)
ctx.fillStyle = "rgba(232, 13, 13,0.8)";
ctx.fill();
}
Button.verilogInstructions = function() {
return `Button - Buttons are not natively supported in verilog, consider using Inputs instead\n`;
}
Button.prototype.verilogBaseType = function() {
return this.verilogName() + (Button.selSizes.length-1);
}
//this code to generate Verilog
Button.prototype.generateVerilog = function () {
Button.selSizes.push(this.data);
return CircuitElement.prototype.generateVerilog.call(this);
}
//This code to determine what sizes are used to generate the needed modules
Button.selSizes = [];
//generate the needed modules
Button.moduleVerilog = function () {
var output = "";
for (var i = 0; i < Button.selSizes.length; i++) {
output += `// Skeleton for Button${i}
/*
module Button${i}(out);
output reg out;
initial begin
//do something with the button here
end
endmodule
*/
`;
}
return output;
}
//reset the sized before Verilog generation
Button.resetVerilog = function () {
Button.selSizes = [];
}
function RGBLed(x, y, scope = globalScope) {
// Calling base class constructor
CircuitElement.call(this, x, y, scope, "UP", 8);
this.rectangleObject = false;
this.inp = [];
this.setDimensions(10, 10);
this.inp1 = new Node(-40, -10, 0, this, 8);
this.inp2 = new Node(-40, 0, 0, this, 8);
this.inp3 = new Node(-40, 10, 0, this, 8);
this.inp.push(this.inp1);
this.inp.push(this.inp2);
this.inp.push(this.inp3);
this.directionFixed = true;
this.fixedBitWidth = true;
}
RGBLed.prototype = Object.create(CircuitElement.prototype);
RGBLed.prototype.constructor = RGBLed;
RGBLed.prototype.tooltipText = "RGB Led ToolTip: RGB Led inputs 8 bit values for the colors RED, GREEN and BLUE."
RGBLed.prototype.helplink = "https://docs.circuitverse.org/#/outputs?id=rgb-led";
RGBLed.prototype.customSave = function () {
var data = {
nodes: {
inp1: findNode(this.inp1),
inp2: findNode(this.inp2),
inp3: findNode(this.inp3),
},
}
return data;
}
RGBLed.prototype.customDraw = function () {
ctx = simulationArea.context;
var xx = this.x;
var yy = this.y;
ctx.strokeStyle = "green";
ctx.lineWidth = correctWidth(3);
ctx.beginPath();
moveTo(ctx, -20, 0, xx, yy, this.direction);
lineTo(ctx, -40, 0, xx, yy, this.direction);
ctx.stroke();
ctx.strokeStyle = "red";
ctx.lineWidth = correctWidth(3);
ctx.beginPath();
moveTo(ctx, -20, -10, xx, yy, this.direction);
lineTo(ctx, -40, -10, xx, yy, this.direction);
ctx.stroke();
ctx.strokeStyle = "blue";
ctx.lineWidth = correctWidth(3);
ctx.beginPath();
moveTo(ctx, -20, 10, xx, yy, this.direction);
lineTo(ctx, -40, 10, xx, yy, this.direction);
ctx.stroke();
var a = this.inp1.value;
var b = this.inp2.value;
var c = this.inp3.value;
ctx.strokeStyle = "#d3d4d5";
ctx.fillStyle = ["rgba(" + a + ", " + b + ", " + c + ", 0.8)", "rgba(227, 228, 229, 0.8)"][((a === undefined || b === undefined || c === undefined)) + 0]
//ctx.fillStyle = ["rgba(200, 200, 200, 0.3)","rgba(227, 228, 229, 0.8)"][((a === undefined || b === undefined || c === undefined) || (a == 0 && b == 0 && c == 0)) + 0];
ctx.lineWidth = correctWidth(1);
ctx.beginPath();
moveTo(ctx, -18, -11, xx, yy, this.direction);
lineTo(ctx, 0, -11, xx, yy, this.direction);
arc(ctx, 0, 0, 11, (-Math.PI / 2), (Math.PI / 2), xx, yy, this.direction);
lineTo(ctx, -18, 11, xx, yy, this.direction);
lineTo(ctx, -21, 15, xx, yy, this.direction);
arc(ctx, 0, 0, Math.sqrt(666), ((Math.PI / 2) + Math.acos(15 / Math.sqrt(666))), ((-Math.PI / 2) - Math.asin(21 / Math.sqrt(666))), xx, yy, this.direction);
lineTo(ctx, -18, -11, xx, yy, this.direction);
ctx.stroke();
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
ctx.fill();
}
RGBLed.prototype.generateVerilog = function () {
return `
always @ (*)
$display("RGBLed:{${this.inp1.verilogLabel},${this.inp2.verilogLabel},${this.inp3.verilogLabel}} = {%d,%d,%d}", ${this.inp1.verilogLabel}, ${this.inp2.verilogLabel}, ${this.inp3.verilogLabel});`;
}
function SquareRGBLed(x, y, scope = globalScope, dir = "UP", pinLength = 1) {
CircuitElement.call(this, x, y, scope, dir, 8);
this.rectangleObject = false;
this.setDimensions(15, 15);
this.pinLength = pinLength === undefined ? 1 : pinLength;
var nodeX = -10 - 10 * pinLength;
this.inp1 = new Node(nodeX, -10, 0, this, 8, "R");
this.inp2 = new Node(nodeX, 0, 0, this, 8, "G");
this.inp3 = new Node(nodeX, 10, 0, this, 8, "B");
this.inp = [this.inp1, this.inp2, this.inp3];
this.labelDirection = "UP";
this.fixedBitWidth = true;
this.changePinLength = function (pinLength) {
if (pinLength == undefined) return;
pinLength = parseInt(pinLength, 10);
if (pinLength < 0 || pinLength > 1000) return;
// Calculate the new position of the LED, so the nodes will stay in the same place.
var diff = 10 * (pinLength - this.pinLength);
var diffX = this.direction == "LEFT" ? -diff : this.direction == "RIGHT" ? diff : 0;
var diffY = this.direction == "UP" ? -diff : this.direction == "DOWN" ? diff : 0;
// Build a new LED with the new values; preserve label properties too.
var obj = new window[this.objectType](this.x + diffX, this.y + diffY, this.scope, this.direction, pinLength);
obj.label = this.label;
obj.labelDirection = this.labelDirection;
this.cleanDelete();
simulationArea.lastSelected = obj;
return obj;
}
this.mutableProperties = {
"pinLength": {
name: "Pin Length",
type: "number",
max: "1000",
min: "0",
func: "changePinLength",
},
}
}
SquareRGBLed.prototype = Object.create(CircuitElement.prototype);
SquareRGBLed.prototype.constructor = SquareRGBLed;
SquareRGBLed.prototype.tooltipText = "Square RGB Led ToolTip: RGB Led inputs 8 bit values for the colors RED, GREEN and BLUE."
SquareRGBLed.prototype.helplink = "https://docs.circuitverse.org/#/outputs?id=square-rgb-led";
SquareRGBLed.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.pinLength],
nodes: {
inp1: findNode(this.inp1),
inp2: findNode(this.inp2),
inp3: findNode(this.inp3),
},
}
return data;
}
SquareRGBLed.prototype.customDraw = function () {
var ctx = simulationArea.context;
var xx = this.x;
var yy = this.y;
var r = this.inp1.value;
var g = this.inp2.value;
var b = this.inp3.value;
var colors = ["rgb(174,20,20)", "rgb(40,174,40)", "rgb(0,100,255)"];
for (var i = 0; i < 3; i++) {
var x = -10 - 10 * this.pinLength;
var y = i * 10 - 10;
ctx.lineWidth = correctWidth(3);
// A gray line, which makes it easy on the eyes when the pin length is large
ctx.beginPath();
ctx.lineCap = "butt";
ctx.strokeStyle = "rgb(227, 228, 229)";
moveTo(ctx, -15, y, xx, yy, this.direction);
lineTo(ctx, x + 10, y, xx, yy, this.direction);
ctx.stroke();
// A colored line, so people know which pin does what.
ctx.lineCap = "round";
ctx.beginPath();
ctx.strokeStyle = colors[i];
moveTo(ctx, x + 10, y, xx, yy, this.direction);
lineTo(ctx, x, y, xx, yy, this.direction);
ctx.stroke();
}
ctx.strokeStyle = "#d3d4d5";
ctx.fillStyle = (r === undefined && g === undefined && b === undefined) ? "rgb(227, 228, 229)" : "rgb(" + (r || 0) + ", " + (g || 0) + ", " + (b || 0) + ")";
ctx.lineWidth = correctWidth(1);
ctx.beginPath();
rect2(ctx, -15, -15, 30, 30, xx, yy, this.direction);
ctx.stroke();
if ((this.hover && !simulationArea.shiftDown) ||
simulationArea.lastSelected == this ||
simulationArea.multipleObjectSelections.contains(this)) {
ctx.fillStyle = "rgba(255, 255, 32)";
}
ctx.fill();
}
SquareRGBLed.prototype.generateVerilog = function () {
return RGBLed.prototype.generateVerilog.call(this);
}
function Demultiplexer(x, y, scope = globalScope, dir = "LEFT", bitWidth = 1, controlSignalSize = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.controlSignalSize = controlSignalSize || parseInt(prompt("Enter control signal bitWidth"), 10);
this.outputsize = 1 << this.controlSignalSize;
this.xOff = 0;
this.yOff = 1;
if (this.controlSignalSize == 1) {
this.xOff = 10;
}
if (this.controlSignalSize <= 3) {
this.yOff = 2;
}
this.changeControlSignalSize = function (size) {
if (size == undefined || size < 1 || size > 32) return;
if (this.controlSignalSize == size) return;
var obj = new window[this.objectType](this.x, this.y, this.scope, this.direction, this.bitWidth, size);
this.cleanDelete();
simulationArea.lastSelected = obj;
return obj;
}
this.mutableProperties = {
"controlSignalSize": {
name: "Control Signal Size",
type: "number",
max: "32",
min: "1",
func: "changeControlSignalSize",
},
}
this.newBitWidth = function (bitWidth) {
this.bitWidth = bitWidth;
for (var i = 0; i < this.outputsize; i++) {
this.output1[i].bitWidth = bitWidth
}
this.input.bitWidth = bitWidth;
}
this.setDimensions(20 - this.xOff, this.yOff * 5 * (this.outputsize));
this.rectangleObject = false;
this.input = new Node(20 - this.xOff, 0, 0, this);
this.output1 = [];
for (var i = 0; i < this.outputsize; i++) {
var a = new Node(-20 + this.xOff, +this.yOff * 10 * (i - this.outputsize / 2) + 10, 1, this);
this.output1.push(a);
}
this.controlSignalInput = new Node(0, this.yOff * 10 * (this.outputsize / 2 - 1) + this.xOff + 10, 0, this, this.controlSignalSize, "Control Signal");
}
Demultiplexer.prototype = Object.create(CircuitElement.prototype);
Demultiplexer.prototype.constructor = Demultiplexer;
Demultiplexer.prototype.tooltipText = "DeMultiplexer ToolTip : Multiple outputs and a single line input.";
Demultiplexer.prototype.helplink = "https://docs.circuitverse.org/#/decodersandplexers?id=demultiplexer";
Demultiplexer.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.bitWidth, this.controlSignalSize],
nodes: {
output1: this.output1.map(findNode),
input: findNode(this.input),
controlSignalInput: findNode(this.controlSignalInput)
},
}
return data;
}
Demultiplexer.prototype.resolve = function () {
for (var i = 0; i < this.output1.length; i++)
this.output1[i].value = 0;
this.output1[this.controlSignalInput.value].value = this.input.value;
for (var i = 0; i < this.output1.length; i++)
simulationArea.simulationQueue.add(this.output1[i]);
}
Demultiplexer.prototype.customDraw = function () {
ctx = simulationArea.context;
var xx = this.x;
var yy = this.y;
ctx.beginPath();
moveTo(ctx, 0, this.yOff * 10 * (this.outputsize / 2 - 1) + 10 + 0.5 * this.xOff, xx, yy, this.direction);
lineTo(ctx, 0, this.yOff * 5 * (this.outputsize - 1) + this.xOff, xx, yy, this.direction);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = ("rgba(0,0,0,1)");
ctx.lineWidth = correctWidth(4);
ctx.fillStyle = "white";
moveTo(ctx, -20 + this.xOff, -this.yOff * 10 * (this.outputsize / 2), xx, yy, this.direction);
lineTo(ctx, -20 + this.xOff, 20 + this.yOff * 10 * (this.outputsize / 2 - 1), xx, yy, this.direction);
lineTo(ctx, 20 - this.xOff, +this.yOff * 10 * (this.outputsize / 2 - 1) + this.xOff, xx, yy, this.direction);
lineTo(ctx, 20 - this.xOff, -this.yOff * 10 * (this.outputsize / 2) - this.xOff + 20, xx, yy, this.direction);
ctx.closePath();
if ((this.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 = "black";
ctx.textAlign = "center";
//[xFill,yFill] = rotate(xx + this.output1[i].x - 7, yy + this.output1[i].y + 2);
////console.log([xFill,yFill])
for (var i = 0; i < this.outputsize; i++) {
if (this.direction == "LEFT") fillText(ctx, String(i), xx + this.output1[i].x - 7, yy + this.output1[i].y + 2, 10);
else if (this.direction == "RIGHT") fillText(ctx, String(i), xx + this.output1[i].x + 7, yy + this.output1[i].y + 2, 10);
else if (this.direction == "UP") fillText(ctx, String(i), xx + this.output1[i].x, yy + this.output1[i].y - 5, 10);
else fillText(ctx, String(i), xx + this.output1[i].x, yy + this.output1[i].y + 10, 10);
}
ctx.fill();
}
Demultiplexer.prototype.verilogBaseType = function() {
return this.verilogName() + this.output1.length;
}
//this code to generate Verilog
Demultiplexer.prototype.generateVerilog = function () {
Demultiplexer.selSizes.add(this.controlSignalSize);
return CircuitElement.prototype.generateVerilog.call(this);
}
//This code to determine what sizes are used to generate the needed modules
Demultiplexer.selSizes = new Set();
//generate the needed modules
Demultiplexer.moduleVerilog = function () {
var output = "";
for (var size of Demultiplexer.selSizes) {
var numOutput = 1 << size;
output += "\n";
output += "module Demultiplexer" + numOutput;
output += "(";
for (var j = 0; j < numOutput; j++) {
output += "out" + j + ", ";
}
output += "in, sel);\n";
output += " parameter WIDTH = 1;\n";
output += " output reg [WIDTH-1:0] ";
for (var j = 0; j < numOutput-1; j++) {
output += "out" + j + ", ";
}
output += "out" + (numOutput-1) + ";\n";
output += " input [WIDTH-1:0] in;\n"
output += " input [" + (size-1) +":0] sel;\n";
output += " \n";
output += " always @ (*) begin\n";
for (var j = 0; j < numOutput; j++) {
output += " out" + j + " = 0;\n";
}
output += " case (sel)\n";
for (var j = 0; j < numOutput; j++) {
output += " " + j + " : out" + j + " = in;\n";
}
output += " endcase\n";
output += " end\n";
output += "endmodule\n";
}
return output;
}
//reset the sized before Verilog generation
Demultiplexer.resetVerilog = function () {
Demultiplexer.selSizes = new Set();
}
function Decoder(x, y, scope = globalScope, dir = "LEFT", bitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
// this.controlSignalSize = controlSignalSize || parseInt(prompt("Enter control signal bitWidth"), 10);
this.outputsize = 1 << this.bitWidth;
this.xOff = 0;
this.yOff = 1;
if (this.bitWidth == 1) {
this.xOff = 10;
}
if (this.bitWidth <= 3) {
this.yOff = 2;
}
// this.changeControlSignalSize = function(size) {
// if (size == undefined || size < 1 || size > 32) return;
// if (this.controlSignalSize == size) return;
// var obj = new window[this.objectType](this.x, this.y, this.scope, this.direction, this.bitWidth, size);
// this.cleanDelete();
// simulationArea.lastSelected = obj;
// return obj;
// }
// this.mutableProperties = {
// "controlSignalSize": {
// name: "Control Signal Size",
// type: "number",
// max: "32",
// min: "1",
// func: "changeControlSignalSize",
// },
// }
this.newBitWidth = function (bitWidth) {
// this.bitWidth = bitWidth;
// for (var i = 0; i < this.inputSize; i++) {
// this.outputs1[i].bitWidth = bitWidth
// }
// this.input.bitWidth = bitWidth;
if (bitWidth == undefined || bitWidth < 1 || bitWidth > 32) return;
if (this.bitWidth == bitWidth) return;
var obj = new window[this.objectType](this.x, this.y, this.scope, this.direction, bitWidth);
this.cleanDelete();
simulationArea.lastSelected = obj;
return obj;
}
this.setDimensions(20 - this.xOff, this.yOff * 5 * (this.outputsize));
this.rectangleObject = false;
this.input = new Node(20 - this.xOff, 0, 0, this);
this.output1 = [];
for (var i = 0; i < this.outputsize; i++) {
var a = new Node(-20 + this.xOff, +this.yOff * 10 * (i - this.outputsize / 2) + 10, 1, this, 1);
this.output1.push(a);
}
// this.controlSignalInput = new Node(0,this.yOff * 10 * (this.outputsize / 2 - 1) +this.xOff + 10, 0, this, this.controlSignalSize,"Control Signal");
}
Decoder.prototype = Object.create(CircuitElement.prototype);
Decoder.prototype.constructor = Decoder;
Decoder.prototype.tooltipText = "Decoder ToolTip : Converts coded inputs into coded outputs.";
Decoder.prototype.helplink = "https://docs.circuitverse.org/#/decodersandplexers?id=decoder";
Decoder.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.bitWidth],
nodes: {
output1: this.output1.map(findNode),
input: findNode(this.input),
},
}
return data;
}
Decoder.prototype.resolve = function () {
for (var i = 0; i < this.output1.length; i++)
this.output1[i].value = 0;
this.output1[this.input.value].value = 1;
for (var i = 0; i < this.output1.length; i++)
simulationArea.simulationQueue.add(this.output1[i]);
}
Decoder.prototype.customDraw = function () {
ctx = simulationArea.context;
var xx = this.x;
var yy = this.y;
// ctx.beginPath();
// moveTo(ctx, 0,this.yOff * 10 * (this.outputsize / 2 - 1) + 10 + 0.5 *this.xOff, xx, yy, this.direction);
// lineTo(ctx, 0,this.yOff * 5 * (this.outputsize - 1) +this.xOff, xx, yy, this.direction);
// ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = ("rgba(0,0,0,1)");
ctx.lineWidth = correctWidth(4);
ctx.fillStyle = "white";
moveTo(ctx, -20 + this.xOff, -this.yOff * 10 * (this.outputsize / 2), xx, yy, this.direction);
lineTo(ctx, -20 + this.xOff, 20 + this.yOff * 10 * (this.outputsize / 2 - 1), xx, yy, this.direction);
lineTo(ctx, 20 - this.xOff, +this.yOff * 10 * (this.outputsize / 2 - 1) + this.xOff, xx, yy, this.direction);
lineTo(ctx, 20 - this.xOff, -this.yOff * 10 * (this.outputsize / 2) - this.xOff + 20, xx, yy, this.direction);
ctx.closePath();
if ((this.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 = "black";
ctx.textAlign = "center";
//[xFill,yFill] = rotate(xx + this.output1[i].x - 7, yy + this.output1[i].y + 2);
////console.log([xFill,yFill])
for (var i = 0; i < this.outputsize; i++) {
if (this.direction == "LEFT") fillText(ctx, String(i), xx + this.output1[i].x - 7, yy + this.output1[i].y + 2, 10);
else if (this.direction == "RIGHT") fillText(ctx, String(i), xx + this.output1[i].x + 7, yy + this.output1[i].y + 2, 10);
else if (this.direction == "UP") fillText(ctx, String(i), xx + this.output1[i].x, yy + this.output1[i].y - 5, 10);
else fillText(ctx, String(i), xx + this.output1[i].x, yy + this.output1[i].y + 10, 10);
}
ctx.fill();
}
Decoder.prototype.verilogBaseType = function() {
return this.verilogName() + this.output1.length;
}
//this code to generate Verilog
Decoder.prototype.generateVerilog = function () {
Decoder.selSizes.add(this.bitWidth);
return CircuitElement.prototype.generateVerilog.call(this);
}
Decoder.selSizes = new Set();
//generate the needed modules
Decoder.moduleVerilog = function () {
var output = "";
for (var size of Decoder.selSizes) {
var numOutput = 1 << size;
output += "\n";
output += "module Decoder" + numOutput;
output += "(";
for (var j = 0; j < numOutput; j++) {
output += "out" + j + ", ";
}
output += "sel);\n";
output += " output reg ";
for (var j = 0; j < numOutput-1; j++) {
output += "out" + j + ", ";
}
output += "out" + (numOutput-1) + ";\n";
output += " input [" + (size-1) +":0] sel;\n";
output += " \n";
output += " always @ (*) begin\n";
for (var j = 0; j < numOutput; j++) {
output += " out" + j + " = 0;\n";
}
output += " case (sel)\n";
for (var j = 0; j < numOutput; j++) {
output += " " + j + " : out" + j + " = 1;\n";
}
output += " endcase\n";
output += " end\n";
output += "endmodule\n";
}
return output;
}
//reset the sized before Verilog generation
Decoder.resetVerilog = function () {
Decoder.selSizes = new Set();
}
function Flag(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1, identifier) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.setWidth(60);
this.setHeight(20);
this.rectangleObject = false;
this.directionFixed = true;
this.orientationFixed = false;
this.identifier = identifier || ("F" + this.scope.Flag.length);
this.plotValues = [];
this.xSize = 10;
this.inp1 = new Node(40, 0, 0, this);
}
Flag.prototype = Object.create(CircuitElement.prototype);
Flag.prototype.constructor = Flag;
Flag.prototype.tooltipText = "FLag ToolTip: Use this for debugging and plotting."
Flag.prototype.helplink = "https://docs.circuitverse.org/#/timing_diagrams?id=using-flags";
Flag.prototype.setPlotValue = function () {
var time = plotArea.stopWatch.ElapsedMilliseconds;
// //console.log("DEB:",time);
if (this.plotValues.length && this.plotValues[this.plotValues.length - 1][0] == time)
this.plotValues.pop();
if (this.plotValues.length == 0) {
this.plotValues.push([time, this.inp1.value]);
return;
}
if (this.plotValues[this.plotValues.length - 1][1] == this.inp1.value)
return;
else
this.plotValues.push([time, this.inp1.value]);
}
Flag.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.bitWidth],
nodes: {
inp1: findNode(this.inp1),
},
values: {
identifier: this.identifier
}
}
return data;
}
Flag.prototype.setIdentifier = function (id = "") {
if (id.length == 0) return;
this.identifier = id;
var len = this.identifier.length;
if (len == 1) this.xSize = 20;
else if (len > 1 && len < 4) this.xSize = 10;
else this.xSize = 0;
}
Flag.prototype.mutableProperties = {
"identifier": {
name: "Debug Flag identifier",
type: "text",
maxlength: "5",
func: "setIdentifier",
},
}
Flag.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = "grey";
ctx.fillStyle = "#fcfcfc";
ctx.lineWidth = correctWidth(1);
var xx = this.x;
var yy = this.y;
rect2(ctx, -50 + this.xSize, -20, 100 - 2 * this.xSize, 40, xx, yy, "RIGHT");
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
ctx.fill();
ctx.stroke();
ctx.font = "14px Georgia";
this.xOff = ctx.measureText(this.identifier).width;
ctx.beginPath();
rect2(ctx, -40 + this.xSize, -12, this.xOff + 10, 25, xx, yy, "RIGHT");
ctx.fillStyle = "#eee"
ctx.strokeStyle = "#ccc";
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.textAlign = "center";
ctx.fillStyle = "black";
fillText(ctx, this.identifier, xx - 35 + this.xOff / 2 + this.xSize, yy + 5, 14);
ctx.fill();
ctx.beginPath();
ctx.font = "30px Georgia";
ctx.textAlign = "center";
ctx.fillStyle = ["blue", "red"][+(this.inp1.value == undefined)];
if (this.inp1.value !== undefined)
fillText(ctx, this.inp1.value.toString(16), xx + 35 - this.xSize, yy + 8, 25);
else
fillText(ctx, "x", xx + 35 - this.xSize, yy + 8, 25);
ctx.fill();
}
Flag.prototype.newDirection = function (dir) {
if (dir == this.direction) return;
this.direction = dir;
this.inp1.refresh();
if (dir == "RIGHT" || dir == "LEFT") {
this.inp1.leftx = 50 - this.xSize;
} else if (dir == "UP") {
this.inp1.leftx = 20;
} else {
this.inp1.leftx = 20;
}
// if(this.direction=="LEFT" || this.direction=="RIGHT") this.inp1.leftx=50-this.xSize;
// this.inp1.refresh();
this.inp1.refresh();
}
function MSB(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
// this.setDimensions(20, 20);
this.leftDimensionX = 10;
this.rightDimensionX = 20;
this.setHeight(30);
this.directionFixed = true;
this.bitWidth = bitWidth || parseInt(prompt("Enter bitWidth"), 10);
this.rectangleObject = false;
this.inputSize = 1 << this.bitWidth;
this.inp1 = new Node(-10, 0, 0, this, this.inputSize);
this.output1 = new Node(20, 0, 1, this, this.bitWidth);
this.enable = new Node(20, 20, 1, this, 1);
}
MSB.prototype = Object.create(CircuitElement.prototype);
MSB.prototype.constructor = MSB;
MSB.prototype.tooltipText = "MSB ToolTip : The most significant bit or the high-order bit.";
MSB.prototype.helplink = "https://docs.circuitverse.org/#/decodersandplexers?id=most-significant-bit-msb-detector";
MSB.prototype.customSave = function () {
var data = {
nodes: {
inp1: findNode(this.inp1),
output1: findNode(this.output1),
enable: findNode(this.enable)
},
constructorParamaters: [this.direction, this.bitWidth],
}
return data;
}
MSB.prototype.newBitWidth = function (bitWidth) {
// this.inputSize = 1 << bitWidth
this.inputSize = bitWidth
this.inp1.bitWidth = this.inputSize;
this.bitWidth = bitWidth;
this.output1.bitWidth = bitWidth;
}
MSB.prototype.resolve = function () {
var inp = this.inp1.value;
this.output1.value = (dec2bin(inp).length) - 1
simulationArea.simulationQueue.add(this.output1);
if (inp != 0) {
this.enable.value = 1;
} else {
this.enable.value = 0;
}
simulationArea.simulationQueue.add(this.enable);
}
MSB.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = "black";
ctx.fillStyle = "white";
ctx.lineWidth = correctWidth(3);
var xx = this.x;
var yy = this.y;
rect(ctx, xx - 10, yy - 30, 30, 60);
if ((this.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 = "black";
ctx.textAlign = "center";
fillText(ctx, "MSB", xx + 6, yy - 12, 10);
fillText(ctx, "EN", xx + this.enable.x - 12, yy + this.enable.y + 3, 8);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "green";
ctx.textAlign = "center";
if (this.output1.value != undefined) {
fillText(ctx, this.output1.value, xx + 5, yy + 14, 13);
}
ctx.stroke();
ctx.fill();
}
MSB.prototype.generateVerilog = function () {
return `assign ${this.output1.verilogLabel} = (${this.enable.verilogLabel}!=0) ? ${this.inp1.verilogLabel}[${this.inp1.bitWidth-1}] : 0;`;
}
function LSB(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.leftDimensionX = 10;
this.rightDimensionX = 20;
this.setHeight(30);
this.directionFixed = true;
this.bitWidth = bitWidth || parseInt(prompt("Enter bitWidth"), 10);
this.rectangleObject = false;
this.inputSize = 1 << this.bitWidth;
this.inp1 = new Node(-10, 0, 0, this, this.inputSize);
this.output1 = new Node(20, 0, 1, this, this.bitWidth);
this.enable = new Node(20, 20, 1, this, 1);
}
LSB.prototype = Object.create(CircuitElement.prototype);
LSB.prototype.constructor = LSB;
LSB.prototype.tooltipText = "LSB ToolTip : The least significant bit or the low-order bit.";
LSB.prototype.helplink = "https://docs.circuitverse.org/#/decodersandplexers?id=least-significant-bit-lsb-detector";
LSB.prototype.customSave = function () {
var data = {
nodes: {
inp1: findNode(this.inp1),
output1: findNode(this.output1),
enable: findNode(this.enable)
},
constructorParamaters: [this.direction, this.bitWidth],
}
return data;
}
LSB.prototype.newBitWidth = function (bitWidth) {
// this.inputSize = 1 << bitWidth
this.inputSize = bitWidth
this.inp1.bitWidth = this.inputSize;
this.bitWidth = bitWidth;
this.output1.bitWidth = bitWidth;
}
LSB.prototype.resolve = function () {
var inp = dec2bin(this.inp1.value);
var out = 0;
for (var i = inp.length - 1; i >= 0; i--) {
if (inp[i] == 1) {
out = inp.length - 1 - i;
break;
}
}
this.output1.value = out;
simulationArea.simulationQueue.add(this.output1);
if (inp != 0) {
this.enable.value = 1;
} else {
this.enable.value = 0;
}
simulationArea.simulationQueue.add(this.enable);
}
LSB.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = "black";
ctx.fillStyle = "white";
ctx.lineWidth = correctWidth(3);
var xx = this.x;
var yy = this.y;
rect(ctx, xx - 10, yy - 30, 30, 60);
if ((this.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 = "black";
ctx.textAlign = "center";
fillText(ctx, "LSB", xx + 6, yy - 12, 10);
fillText(ctx, "EN", xx + this.enable.x - 12, yy + this.enable.y + 3, 8);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "green";
ctx.textAlign = "center";
if (this.output1.value != undefined) {
fillText(ctx, this.output1.value, xx + 5, yy + 14, 13);
}
ctx.stroke();
ctx.fill();
}
LSB.prototype.generateVerilog = function () {
return `assign ${this.output1.verilogLabel} = (${this.enable.verilogLabel}!=0) ? ${this.inp1.verilogLabel}[0] : 0;`;
}
function PriorityEncoder(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.bitWidth = bitWidth || parseInt(prompt("Enter bitWidth"), 10);
this.inputSize = 1 << this.bitWidth;
this.yOff = 1;
if (this.bitWidth <= 3) {
this.yOff = 2;
}
this.setDimensions(20, this.yOff * 5 * (this.inputSize));
this.directionFixed = true;
this.rectangleObject = false;
this.inp1 = [];
for (var i = 0; i < this.inputSize; i++) {
var a = new Node(-10, +this.yOff * 10 * (i - this.inputSize / 2) + 10, 0, this, 1);
this.inp1.push(a);
}
this.output1 = [];
for (var i = 0; i < this.bitWidth; i++) {
var a = new Node(30, +2 * 10 * (i - this.bitWidth / 2) + 10, 1, this, 1);
this.output1.push(a);
}
this.enable = new Node(10, 20 + this.inp1[this.inputSize - 1].y, 1, this, 1);
}
PriorityEncoder.prototype = Object.create(CircuitElement.prototype);
PriorityEncoder.prototype.constructor = PriorityEncoder;
PriorityEncoder.prototype.tooltipText = "Priority Encoder ToolTip : Compresses binary inputs into a smaller number of outputs.";
PriorityEncoder.prototype.helplink = "https://docs.circuitverse.org/#/decodersandplexers?id=priority-encoder";
PriorityEncoder.prototype.customSave = function () {
var data = {
nodes: {
inp1: this.inp1.map(findNode),
output1: this.output1.map(findNode),
enable: findNode(this.enable)
},
constructorParamaters: [this.direction, this.bitWidth],
}
return data;
}
PriorityEncoder.prototype.newBitWidth = function (bitWidth) {
if (bitWidth == undefined || bitWidth < 1 || bitWidth > 32) return;
if (this.bitWidth == bitWidth) return;
this.bitWidth = bitWidth;
var obj = new window[this.objectType](this.x, this.y, this.scope, this.direction, this.bitWidth);
this.inputSize = 1 << bitWidth;
this.cleanDelete();
simulationArea.lastSelected = obj;
return obj;
}
PriorityEncoder.prototype.resolve = function () {
var out = 0;
var temp = 0;
for (var i = this.inputSize - 1; i >= 0; i--) {
if (this.inp1[i].value == 1) {
out = dec2bin(i);
break;
}
}
temp = out;
if (out.length != undefined) {
this.enable.value = 1;
} else {
this.enable.value = 0;
}
simulationArea.simulationQueue.add(this.enable);
if (temp.length == undefined) {
temp = "0";
for (var i = 0; i < this.bitWidth - 1; i++) {
temp = "0" + temp;
}
}
if (temp.length != this.bitWidth) {
for (var i = temp.length; i < this.bitWidth; i++) {
temp = "0" + temp;
}
}
for (var i = this.bitWidth - 1; i >= 0; i--) {
this.output1[this.bitWidth - 1 - i].value = Number(temp[i]);
simulationArea.simulationQueue.add(this.output1[this.bitWidth - 1 - i]);
}
}
PriorityEncoder.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = "black";
ctx.fillStyle = "white";
ctx.lineWidth = correctWidth(3);
var xx = this.x;
var yy = this.y;
if (this.bitWidth <= 3)
rect(ctx, xx - 10, yy - 10 - this.yOff * 5 * (this.inputSize), 40, 20 * (this.inputSize + 1));
else
rect(ctx, xx - 10, yy - 10 - this.yOff * 5 * (this.inputSize), 40, 10 * (this.inputSize + 3));
if ((this.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 = "black";
ctx.textAlign = "center";
for (var i = 0; i < this.inputSize; i++) {
fillText(ctx, String(i), xx, yy + this.inp1[i].y + 2, 10);
}
for (var i = 0; i < this.bitWidth; i++) {
fillText(ctx, String(i), xx + this.output1[0].x - 10, yy + this.output1[i].y + 2, 10);
}
fillText(ctx, "EN", xx + this.enable.x, yy + this.enable.y - 5, 10);
ctx.fill();
}
PriorityEncoder.prototype.verilogBaseType = function() {
return this.verilogName() + this.inp1.length;
}
PriorityEncoder.prototype.generateVerilog = function () {
PriorityEncoder.selSizes.add(this.bitWidth);
return CircuitElement.prototype.generateVerilog.call(this);
}
PriorityEncoder.selSizes = new Set();
//generate the needed modules
PriorityEncoder.moduleVerilog = function () {
var output = "";
for (var size of PriorityEncoder.selSizes) {
var numInput = 1 << size;
output += "\n";
output += "module PriorityEncoder" + numInput;
output += "(sel, ze, ";
for (var j = 0; j < numInput-1; j++) {
output += "in" + j + ", ";
}
output += "in" + (numInput-1) + ");\n";
output += " output reg [" + (size-1) + ":0] sel;\n";
output += " output reg ze;\n";
output += " input "
for (var j = 0; j < numInput-1; j++) {
output += "in" + j + ", ";
}
output += "in" + (numInput-1) + ";\n";
output += "\n";
output += " always @ (*) begin\n";
output += " sel = 0;\n";
output += " ze = 0;\n";
output += " if (in" + (numInput-1) + ")\n";
output += " sel = " + (numInput-1) + ";\n";
for (var j = numInput-2; j <= 0; j++) {
output += " else if (in" + j + ")\n";
output += " sel = " + j + ";\n";
}
output += " else\n";
output += " ze = 1;\n"
output += " end\n";
output += "endmodule\n";
}
return output;
}
//reset the sized before Verilog generation
PriorityEncoder.resetVerilog = function () {
PriorityEncoder.selSizes = new Set
}
function Tunnel(x, y, scope = globalScope, dir = "LEFT", bitWidth = 1, identifier) {
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.rectangleObject = false;
this.centerElement = true;
this.xSize = 10;
this.plotValues = [];
this.inp1 = new Node(0, 0, 0, this);
this.setIdentifier(identifier || "T");
this.setBounds();
}
Tunnel.prototype = Object.create(CircuitElement.prototype);
Tunnel.prototype.constructor = Tunnel;
Tunnel.prototype.tooltipText = "Tunnel ToolTip : Tunnel Selected.";
Tunnel.prototype.helplink = "https://docs.circuitverse.org/#/miscellaneous?id=tunnel";
Tunnel.prototype.newDirection = function (dir) {
if (this.direction == dir) return;
this.direction = dir;
this.setBounds();
}
Tunnel.prototype.overrideDirectionRotation = true;
Tunnel.prototype.setBounds = function () {
var xRotate = 0;
var yRotate = 0;
if (this.direction == "LEFT") {
xRotate = 0;
yRotate = 0;
} else if (this.direction == "RIGHT") {
xRotate = 120 - this.xSize;
yRotate = 0;
} else if (this.direction == "UP") {
xRotate = 60 - this.xSize / 2;
yRotate = -20;
} else {
xRotate = 60 - this.xSize / 2;
yRotate = 20;
}
this.leftDimensionX = Math.abs(-120 + xRotate + this.xSize);
this.upDimensionY = Math.abs(-20 + yRotate);
this.rightDimensionX = Math.abs(xRotate)
this.downDimensionY = Math.abs(20 + yRotate);
console.log(this.leftDimensionX, this.upDimensionY, this.rightDimensionX, this.downDimensionY);
// rect2(ctx, -120 + xRotate + this.xSize, -20 + yRotate, 120 - this.xSize, 40, xx, yy, "RIGHT");
}
Tunnel.prototype.setTunnelValue = function (val) {
this.inp1.value = val;
for (var i = 0; i < this.inp1.connections.length; i++) {
if (this.inp1.connections[i].value != val) {
this.inp1.connections[i].value = val;
simulationArea.simulationQueue.add(this.inp1.connections[i]);
}
}
}
Tunnel.prototype.resolve = function () {
for (var i = 0; i < this.scope.tunnelList[this.identifier].length; i++) {
if (this.scope.tunnelList[this.identifier][i].inp1.value != this.inp1.value) {
this.scope.tunnelList[this.identifier][i].setTunnelValue(this.inp1.value);
}
}
}
Tunnel.prototype.updateScope = function (scope) {
this.scope = scope;
this.inp1.updateScope(scope);
this.setIdentifier(this.identifier);
//console.log("ShouldWork!");
}
Tunnel.prototype.setPlotValue = function () {
var time = plotArea.stopWatch.ElapsedMilliseconds;
if (this.plotValues.length && this.plotValues[this.plotValues.length - 1][0] == time)
this.plotValues.pop();
if (this.plotValues.length == 0) {
this.plotValues.push([time, this.inp1.value]);
return;
}
if (this.plotValues[this.plotValues.length - 1][1] == this.inp1.value)
return;
else
this.plotValues.push([time, this.inp1.value]);
}
Tunnel.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.bitWidth, this.identifier],
nodes: {
inp1: findNode(this.inp1),
},
values: {
identifier: this.identifier
}
}
return data;
}
Tunnel.prototype.setIdentifier = function (id = "") {
if (id.length == 0) return;
if (this.scope.tunnelList[this.identifier]) this.scope.tunnelList[this.identifier].clean(this);
this.identifier = id;
if (this.scope.tunnelList[this.identifier]) this.scope.tunnelList[this.identifier].push(this);
else this.scope.tunnelList[this.identifier] = [this];
var len = this.identifier.length;
if (len == 1) this.xSize = 40;
else if (len > 1 && len < 4) this.xSize = 20;
else this.xSize = 0;
this.setBounds();
}
Tunnel.prototype.mutableProperties = {
"identifier": {
name: "Debug Flag identifier",
type: "text",
maxlength: "5",
func: "setIdentifier",
},
}
Tunnel.prototype.delete = function () {
this.scope.Tunnel.clean(this);
this.scope.tunnelList[this.identifier].clean(this);
CircuitElement.prototype.delete.call(this);
}
Tunnel.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = "grey";
ctx.fillStyle = "#fcfcfc";
ctx.lineWidth = correctWidth(1);
var xx = this.x;
var yy = this.y;
var xRotate = 0;
var yRotate = 0;
if (this.direction == "LEFT") {
xRotate = 0;
yRotate = 0;
} else if (this.direction == "RIGHT") {
xRotate = 120 - this.xSize;
yRotate = 0;
} else if (this.direction == "UP") {
xRotate = 60 - this.xSize / 2;
yRotate = -20;
} else {
xRotate = 60 - this.xSize / 2;
yRotate = 20;
}
rect2(ctx, -120 + xRotate + this.xSize, -20 + yRotate, 120 - this.xSize, 40, xx, yy, "RIGHT");
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this))
ctx.fillStyle = "rgba(255, 255, 32,0.8)";
ctx.fill();
ctx.stroke();
ctx.font = "14px Georgia";
this.xOff = ctx.measureText(this.identifier).width;
ctx.beginPath();
rect2(ctx, -105 + xRotate + this.xSize, -11 + yRotate, this.xOff + 10, 23, xx, yy, "RIGHT");
ctx.fillStyle = "#eee"
ctx.strokeStyle = "#ccc";
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.textAlign = "center";
ctx.fillStyle = "black";
fillText(ctx, this.identifier, xx - 100 + this.xOff / 2 + xRotate + this.xSize, yy + 6 + yRotate, 14);
ctx.fill();
ctx.beginPath();
ctx.font = "30px Georgia";
ctx.textAlign = "center";
ctx.fillStyle = ["blue", "red"][+(this.inp1.value == undefined)];
if (this.inp1.value !== undefined)
fillText(ctx, this.inp1.value.toString(16), xx - 23 + xRotate, yy + 8 + yRotate, 25);
else
fillText(ctx, "x", xx - 23 + xRotate, yy + 8 + yRotate, 25);
ctx.fill();
}
function ALU(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
// //console.log("HIT");
// //console.log(x,y,scope,dir,bitWidth,controlSignalSize);
CircuitElement.call(this, x, y, scope, dir, bitWidth);
this.message = "ALU";
this.setDimensions(30, 40);
this.rectangleObject = false;
this.inp1 = new Node(-30, -30, 0, this, this.bitwidth, "A");
this.inp2 = new Node(-30, 30, 0, this, this.bitwidth, "B");
this.controlSignalInput = new Node(-10, -40, 0, this, 3, "Ctrl");
this.carryOut = new Node(-10, 40, 1, this, 1, "Cout");
this.output = new Node(30, 0, 1, this, this.bitwidth, "Out");
}
ALU.prototype = Object.create(CircuitElement.prototype);
ALU.prototype.constructor = ALU;
ALU.prototype.tooltipText = "ALU ToolTip: 0: A&B, 1:A|B, 2:A+B, 4:A&~B, 5:A|~B, 6:A-B, 7:SLT "
ALU.prototype.helplink = "https://docs.circuitverse.org/#/miscellaneous?id=alu";
ALU.prototype.newBitWidth = function (bitWidth) {
this.bitWidth = bitWidth;
this.inp1.bitWidth = bitWidth;
this.inp2.bitWidth = bitWidth;
this.output.bitWidth = bitWidth;
}
ALU.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction, this.bitWidth],
nodes: {
inp1: findNode(this.inp1),
inp2: findNode(this.inp2),
output: findNode(this.output),
carryOut: findNode(this.carryOut),
controlSignalInput: findNode(this.controlSignalInput)
},
}
return data;
}
ALU.prototype.customDraw = function () {
ctx = simulationArea.context;
var xx = this.x;
var yy = this.y;
ctx.strokeStyle = "black";
ctx.fillStyle = "white";
ctx.lineWidth = correctWidth(3);
ctx.beginPath();
moveTo(ctx, 30, 10, xx, yy, this.direction);
lineTo(ctx, 30, -10, xx, yy, this.direction);
lineTo(ctx, 10, -40, xx, yy, this.direction);
lineTo(ctx, -30, -40, xx, yy, this.direction);
lineTo(ctx, -30, -20, xx, yy, this.direction);
lineTo(ctx, -20, -10, xx, yy, this.direction);
lineTo(ctx, -20, 10, xx, yy, this.direction);
lineTo(ctx, -30, 20, xx, yy, this.direction);
lineTo(ctx, -30, 40, xx, yy, this.direction);
lineTo(ctx, 10, 40, xx, yy, this.direction);
lineTo(ctx, 30, 10, xx, yy, this.direction);
ctx.closePath();
ctx.stroke();
if ((this.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 = "Black";
ctx.textAlign = "center"
fillText4(ctx, "B", -23, 30, xx, yy, this.direction, 6);
fillText4(ctx, "A", -23, -30, xx, yy, this.direction, 6);
fillText4(ctx, "CTR", -10, -30, xx, yy, this.direction, 6);
fillText4(ctx, "Carry", -10, 30, xx, yy, this.direction, 6);
fillText4(ctx, "Ans", 20, 0, xx, yy, this.direction, 6);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "DarkGreen";
fillText4(ctx, this.message, 0, 0, xx, yy, this.direction, 12);
ctx.fill();
}
ALU.prototype.resolve = function () {
if (this.controlSignalInput.value == 0) {
this.output.value = ((this.inp1.value) & (this.inp2.value));
simulationArea.simulationQueue.add(this.output);
this.carryOut.value = 0;
simulationArea.simulationQueue.add(this.carryOut);
this.message = "A&B";
} else if (this.controlSignalInput.value == 1) {
this.output.value = ((this.inp1.value) | (this.inp2.value));
simulationArea.simulationQueue.add(this.output);
this.carryOut.value = 0;
simulationArea.simulationQueue.add(this.carryOut);
this.message = "A|B";
} else if (this.controlSignalInput.value == 2) {
var sum = this.inp1.value + this.inp2.value;
this.output.value = ((sum) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
this.carryOut.value = +((sum >>> (this.bitWidth)) !== 0);
simulationArea.simulationQueue.add(this.carryOut);
simulationArea.simulationQueue.add(this.output);
this.message = "A+B";
} else if (this.controlSignalInput.value == 3) {
this.message = "ALU";
return;
} else if (this.controlSignalInput.value == 4) {
this.message = "A&~B";
this.output.value = ((this.inp1.value) & this.flipBits(this.inp2.value));
simulationArea.simulationQueue.add(this.output);
this.carryOut.value = 0;
simulationArea.simulationQueue.add(this.carryOut);
} else if (this.controlSignalInput.value == 5) {
this.message = "A|~B";
this.output.value = ((this.inp1.value) | this.flipBits(this.inp2.value));
simulationArea.simulationQueue.add(this.output);
this.carryOut.value = 0;
simulationArea.simulationQueue.add(this.carryOut);
} else if (this.controlSignalInput.value == 6) {
this.message = "A-B";
this.output.value = ((this.inp1.value - this.inp2.value) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
simulationArea.simulationQueue.add(this.output);
this.carryOut.value = 0;
simulationArea.simulationQueue.add(this.carryOut);
} else if (this.controlSignalInput.value == 7) {
this.message = "A<B";
if (this.inp1.value < this.inp2.value)
this.output.value = 1;
else
this.output.value = 0;
simulationArea.simulationQueue.add(this.output);
this.carryOut.value = 0;
simulationArea.simulationQueue.add(this.carryOut);
}
}
ALU.moduleVerilog = function () {
return `
module ALU(out, carryOut, inp1, inp2, controlSignalInput);
parameter WIDTH = 1;
output reg [WIDTH-1:0] out;
output reg carryOut;
input [WIDTH-1:0] inp1, inp2;
input [2:0] controlSignalInput;
always @ (*)
case (controlSignalInput)
0 :
begin
out = inp1 & inp2;
carryOut = 0;
end
1 :
begin
out = inp1 | inp2;
carryOut = 0;
end
2 :
begin
{carryOut, out} = inp1 + inp2;
end
4 :
begin
out = inp1 & ~inp2;
carryOut = 0;
end
5 :
begin
out = inp1 | ~inp2;
carryOut = 0;
end
6 :
begin
out = inp1 < inp2;
carryOut = 0;
end
7 :
begin
out = inp1 & inp2;
carryOut = 0;
end
default :
begin
out = inp1 & inp2;
carryOut = 0;
end
endcase
endmodule
`;
}
function Rectangle(x, y, scope = globalScope, rows = 15, cols = 20) {
CircuitElement.call(this, x, y, scope, "RIGHT", 1);
this.directionFixed = true;
this.fixedBitWidth = true;
this.rectangleObject = false;
this.cols = cols || parseInt(prompt("Enter cols:"));
this.rows = rows || parseInt(prompt("Enter rows:"));
this.setSize()
}
Rectangle.prototype = Object.create(CircuitElement.prototype);
Rectangle.prototype.constructor = Rectangle;
Rectangle.prototype.propagationDelayFixed = true;
Rectangle.prototype.tooltipText = "Rectangle ToolTip : Used to Box the Circuit or area you want to highlight.";
Rectangle.prototype.helplink = "https://docs.circuitverse.org/#/annotation?id=rectangle";
Rectangle.prototype.changeRowSize = function (size) {
if (size == undefined || size < 5 || size > 1000) return;
if (this.rows == size) return;
this.rows = parseInt(size)
this.setSize()
return this;
}
Rectangle.prototype.changeColSize = function (size) {
if (size == undefined || size < 5 || size > 1000) return;
if (this.cols == size) return;
this.cols = parseInt(size);
this.setSize()
return this;
}
Rectangle.prototype.keyDown3 = function (dir) {
//console.log(dir)
if (dir == "ArrowRight")
this.changeColSize(this.cols + 2)
if (dir == "ArrowLeft")
this.changeColSize(this.cols - 2)
if (dir == "ArrowDown")
this.changeRowSize(this.rows + 2)
if (dir == "ArrowUp")
this.changeRowSize(this.rows - 2)
}
Rectangle.prototype.mutableProperties = {
"cols": {
name: "Columns",
type: "number",
max: "1000",
min: "5",
func: "changeColSize",
},
"rows": {
name: "Rows",
type: "number",
max: "1000",
min: "5",
func: "changeRowSize",
}
}
Rectangle.prototype.customSave = function () {
var data = {
constructorParamaters: [this.rows, this.cols],
}
return data;
}
Rectangle.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = "rgba(0,0,0,1)";
ctx.setLineDash([5 * globalScope.scale, 5 * globalScope.scale])
ctx.lineWidth = correctWidth(1.5);
var xx = this.x;
var yy = this.y;
rect(ctx, xx, yy, this.elementWidth, this.elementHeight);
ctx.stroke();
if (simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) {
ctx.fillStyle = "rgba(255, 255, 32,0.1)";
ctx.fill();
}
ctx.setLineDash([])
}
Rectangle.prototype.setSize = function () {
this.elementWidth = this.cols * 10;
this.elementHeight = this.rows * 10;
this.upDimensionY = 0;
this.leftDimensionX = 0;
this.rightDimensionX = this.elementWidth;
this.downDimensionY = this.elementHeight;
}
function Arrow(x, y, scope = globalScope, dir = "RIGHT") {
CircuitElement.call(this, x, y, scope, dir, 8);
this.rectangleObject = false;
this.fixedBitWidth = true
this.setDimensions(30, 20);
}
Arrow.prototype = Object.create(CircuitElement.prototype);
Arrow.prototype.constructor = Arrow;
Arrow.prototype.propagationDelayFixed = true;
Arrow.prototype.tooltipText = "Arrow ToolTip : Arrow Selected.";
Arrow.prototype.helplink = "https://docs.circuitverse.org/#/annotation?id=arrow";
Arrow.prototype.customSave = function () {
var data = {
constructorParamaters: [this.direction],
}
return data;
}
Arrow.prototype.customDraw = function () {
ctx = simulationArea.context;
ctx.lineWidth = correctWidth(3);
var xx = this.x;
var yy = this.y;
ctx.strokeStyle = "red";
ctx.fillStyle = "white";
ctx.beginPath();
moveTo(ctx, -30, -3, xx, yy, this.direction);
lineTo(ctx, 10, -3, xx, yy, this.direction);
lineTo(ctx, 10, -15, xx, yy, this.direction);
lineTo(ctx, 30, 0, xx, yy, this.direction);
lineTo(ctx, 10, 15, xx, yy, this.direction);
lineTo(ctx, 10, 3, xx, yy, this.direction);
lineTo(ctx, -30, 3, xx, yy, this.direction);
ctx.closePath()
ctx.stroke();
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
ctx.fill();
}