4461 lines
148 KiB
JavaScript
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();
|
|
|
|
}
|