把前端从CircuitVerse中拆了出来

This commit is contained in:
zhbaor 2022-01-23 17:33:42 +08:00
commit 5bf1284599
2182 changed files with 189323 additions and 0 deletions

188
simulator/src/modules/ALU.js Executable file
View file

@ -0,0 +1,188 @@
/* eslint-disable no-bitwise */
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
import {
correctWidth, lineTo, moveTo, fillText4,
} from '../canvasApi';
import { colors } from '../themer/themer';
/**
* @class
* ALU
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node.
* @category modules
*/
export default class ALU extends CircuitElement {
constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['ALU'].push(this);
*/
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');
}
/**
* @memberof ALU
* function to change bitwidth of the element
* @param {number} bitWidth - new bitwidth
*/
newBitWidth(bitWidth) {
this.bitWidth = bitWidth;
this.inp1.bitWidth = bitWidth;
this.inp2.bitWidth = bitWidth;
this.output.bitWidth = bitWidth;
}
/**
* @memberof ALU
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const 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;
}
/**
* @memberof ALU
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
const xx = this.x;
const yy = this.y;
ctx.strokeStyle = colors['stroke'];
ctx.fillStyle = colors['fill'];
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 = colors["hover_select"]; }
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();
}
/**
* @memberof ALU
* resolve output values based on inputData
*/
resolve() {
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) {
const 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';
} 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);
}
}
}
/**
* @memberof ALU
* Help Tip
* @type {string}
* @category modules
*/
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 ';
/**
* @memberof ALU
* Help URL
* @type {string}
* @category modules
*/
ALU.prototype.helplink = 'https://docs.circuitverse.org/#/miscellaneous?id=alu';
ALU.prototype.objectType = 'ALU';

106
simulator/src/modules/Adder.js Executable file
View file

@ -0,0 +1,106 @@
/* eslint-disable no-bitwise */
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
/**
* @class
* Adder
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node. modules
* @category modules
*/
export default class Adder extends CircuitElement {
constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['Adder'].push(this);
*/
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');
}
/**
* @memberof Adder
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const 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;
}
/**
* @memberof Adder
* Checks if the element is resolvable
* @return {boolean}
*/
isResolvable() {
return this.inpA.value !== undefined && this.inpB.value !== undefined;
}
/**
* @memberof Adder
* function to change bitwidth of the element
* @param {number} bitWidth - new bitwidth
*/
newBitWidth(bitWidth) {
this.bitWidth = bitWidth;
this.inpA.bitWidth = bitWidth;
this.inpB.bitWidth = bitWidth;
this.sum.bitWidth = bitWidth;
}
/**
* @memberof Adder
* resolve output values based on inputData
*/
resolve() {
if (this.isResolvable() === false) {
return;
}
let carryIn = this.carryIn.value;
if (carryIn === undefined) carryIn = 0;
const 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);
}
generateVerilog() {
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};`;
}
}
/**
* @memberof Adder
* Help Tip
* @type {string}
* @category modules
*/
Adder.prototype.tooltipText = 'Adder ToolTip : Performs addition of numbers.';
Adder.prototype.helplink = 'https://docs.circuitverse.org/#/miscellaneous?id=adder';
Adder.prototype.objectType = 'Adder';

174
simulator/src/modules/AndGate.js Executable file
View file

@ -0,0 +1,174 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, lineTo, moveTo, arc } from "../canvasApi";
import { changeInputSize } from "../modules";
import { colors } from "../themer/themer";
import { gateGenerateVerilog } from '../utils';
/**
* @class
* AndGate
* @extends CircuitElement
* @param {number} x - x coordinate of And Gate.
* @param {number} y - y coordinate of And Gate.
* @param {Scope=} scope - Cirucit on which and gate is drawn
* @param {string=} dir - direction of And Gate
* @param {number=} inputLength - number of input nodes
* @param {number=} bitWidth - bit width per node.
* @category modules
*/
export default class AndGate extends CircuitElement {
constructor(
x,
y,
scope = globalScope,
dir = "RIGHT",
inputLength = 2,
bitWidth = 1
) {
/**
* super call
*/
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['AndGate'].push(this);
*/
this.rectangleObject = false;
this.setDimensions(15, 20);
this.inp = [];
this.inputSize = inputLength;
// variable inputLength , node creation
if (inputLength % 2 === 1) {
for (let i = 0; i < inputLength / 2 - 1; i++) {
const a = new Node(-10, -10 * (i + 1), 0, this);
this.inp.push(a);
}
let a = new Node(-10, 0, 0, this);
this.inp.push(a);
for (let i = inputLength / 2 + 1; i < inputLength; i++) {
a = new Node(-10, 10 * (i + 1 - inputLength / 2 - 1), 0, this);
this.inp.push(a);
}
} else {
for (let i = 0; i < inputLength / 2; i++) {
const a = new Node(-10, -10 * (i + 1), 0, this);
this.inp.push(a);
}
for (let i = inputLength / 2; i < inputLength; i++) {
const a = new Node(
-10,
10 * (i + 1 - inputLength / 2),
0,
this
);
this.inp.push(a);
}
}
this.output1 = new Node(20, 0, 1, this);
}
/**
* @memberof AndGate
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [
this.direction,
this.inputSize,
this.bitWidth,
],
nodes: {
inp: this.inp.map(findNode),
output1: findNode(this.output1),
},
};
return data;
}
/**
* @memberof AndGate
* resolve output values based on inputData
*/
resolve() {
let result = this.inp[0].value || 0;
if (this.isResolvable() === false) {
return;
}
for (let i = 1; i < this.inputSize; i++)
result &= this.inp[i].value || 0;
this.output1.value = result >>> 0;
simulationArea.simulationQueue.add(this.output1);
}
/**
* @memberof AndGate
* function to draw And Gate
*/
customDraw() {
var ctx = simulationArea.context;
ctx.beginPath();
ctx.lineWidth = correctWidth(3);
ctx.strokeStyle = colors["stroke"]; // ("rgba(0,0,0,1)");
ctx.fillStyle = colors["fill"];
const xx = this.x;
const 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 = colors["hover_select"];
ctx.fill();
ctx.stroke();
}
generateVerilog() {
return gateGenerateVerilog.call(this, '&');
}
}
/**
* @memberof AndGate
* Help Tip
* @type {string}
* @category modules
*/
AndGate.prototype.tooltipText =
"And Gate Tooltip : Implements logical conjunction";
/**
* @memberof AndGate
* @type {boolean}
* @category modules
*/
AndGate.prototype.alwaysResolve = true;
/**
* @memberof AndGate
* @type {string}
* @category modules
*/
AndGate.prototype.verilogType = "and";
/**
* @memberof AndGate
* function to change input nodes of the gate
* @category modules
*/
AndGate.prototype.changeInputSize = changeInputSize;
AndGate.prototype.helplink =
"https://docs.circuitverse.org/#/gates?id=and-gate";
AndGate.prototype.objectType = "AndGate";

84
simulator/src/modules/Arrow.js Executable file
View file

@ -0,0 +1,84 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, lineTo, moveTo, arc } from "../canvasApi";
import { changeInputSize } from "../modules";
/**
* @class
* Arrow
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @category modules
*/
import { colors } from "../themer/themer";
export default class Arrow extends CircuitElement {
constructor(x, y, scope = globalScope, dir = "RIGHT") {
super(x, y, scope, dir, 8);
/* this is done in this.baseSetup() now
this.scope['Arrow'].push(this);
*/
this.rectangleObject = false;
this.fixedBitWidth = true;
this.setDimensions(30, 20);
}
/**
* @memberof Arrow
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [this.direction],
};
return data;
}
/**
* @memberof Arrow
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
ctx.lineWidth = correctWidth(3);
const xx = this.x;
const yy = this.y;
ctx.strokeStyle = colors["stroke_alt"];
ctx.fillStyle = colors["fill"];
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 = colors["hover_select"];
ctx.fill();
}
}
/**
* @memberof Arrow
* Help Tip
* @type {string}
* @category modules
*/
Arrow.prototype.tooltipText = "Arrow ToolTip : Arrow Selected.";
Arrow.prototype.propagationDelayFixed = true;
Arrow.prototype.helplink =
"https://docs.circuitverse.org/#/annotation?id=arrow";
Arrow.prototype.objectType = "Arrow";

View file

@ -0,0 +1,173 @@
import CircuitElement from "../circuitElement";
import Node, { findNode, extractBits } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, rect, fillText } from "../canvasApi";
/**
* @class
* BitSelector
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node.
* @param {number=} selectorBitWidth - 1 by default
* @category modules
*/
import { colors } from "../themer/themer";
export default class BitSelector extends CircuitElement {
constructor(
x,
y,
scope = globalScope,
dir = "RIGHT",
bitWidth = 2,
selectorBitWidth = 1
) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['BitSelector'].push(this);
*/
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"
);
}
/**
* @memberof BitSelector
* Function to change selector Bitwidth
* @param {size}
*/
changeSelectorBitWidth(size) {
if (size === undefined || size < 1 || size > 32) return;
this.selectorBitWidth = size;
this.bitSelectorInp.bitWidth = size;
}
/**
* @memberof BitSelector
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
nodes: {
inp1: findNode(this.inp1),
output1: findNode(this.output1),
bitSelectorInp: findNode(this.bitSelectorInp),
},
constructorParamaters: [
this.direction,
this.bitWidth,
this.selectorBitWidth,
],
};
return data;
}
/**
* @memberof BitSelector
* function to change bitwidth of the element
* @param {number} bitWidth - new bitwidth
*/
newBitWidth(bitWidth) {
this.inp1.bitWidth = bitWidth;
this.bitWidth = bitWidth;
}
/**
* @memberof BitSelector
* resolve output values based on inputData
*/
resolve() {
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);
}
/**
* @memberof BitSelector
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = ["blue", colors["stroke_alt"]][
(this.state === undefined) + 0
];
ctx.fillStyle = colors["fill"];
ctx.lineWidth = correctWidth(3);
const xx = this.x;
const 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 = colors["hover_select"];
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.font = "20px Raleway";
ctx.fillStyle = colors["input_text"];
ctx.textAlign = "center";
var bit;
if (this.bitSelectorInp.value === undefined) {
bit = "x";
} else {
bit = this.bitSelectorInp.value;
}
fillText(ctx, bit, xx, yy + 5);
ctx.fill();
}
generateVerilog() {
return `assign ${this.output1.verilogLabel} = ${this.inp1.verilogLabel} >> ${this.bitSelectorInp.verilogLabel};`;
}
}
/**
* @memberof BitSelector
* Help Tip
* @type {string}
* @category modules
*/
BitSelector.prototype.tooltipText =
"BitSelector ToolTip : Divides input bits into several equal-sized groups.";
BitSelector.prototype.helplink =
"https://docs.circuitverse.org/#/decodersandplexers?id=bit-selector";
/**
* @memberof BitSelector
* Mutable properties of the element
* @type {JSON}
* @category modules
*/
BitSelector.prototype.mutableProperties = {
selectorBitWidth: {
name: "Selector Bit Width: ",
type: "number",
max: "32",
min: "1",
func: "changeSelectorBitWidth",
},
};
BitSelector.prototype.objectType = "BitSelector";

128
simulator/src/modules/Buffer.js Executable file
View file

@ -0,0 +1,128 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, lineTo, moveTo, arc } from "../canvasApi";
import { changeInputSize } from "../modules";
/**
* @class
* Buffer
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node.
* @category modules
*/
import { colors } from "../themer/themer";
export default class Buffer extends CircuitElement {
constructor(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['Buffer'].push(this);
*/
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);
}
/**
* @memberof Buffer
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [this.direction, this.bitWidth],
nodes: {
output1: findNode(this.output1),
inp1: findNode(this.inp1),
reset: findNode(this.reset),
},
};
return data;
}
/**
* @memberof Buffer
* function to change bitwidth of the element
* @param {number} bitWidth - new bitwidth
*/
newBitWidth(bitWidth) {
this.inp1.bitWidth = bitWidth;
this.output1.bitWidth = bitWidth;
this.bitWidth = bitWidth;
}
/**
* @memberof Buffer
* Checks if the element is resolvable
* @return {boolean}
*/
isResolvable() {
return true;
}
/**
* @memberof Buffer
* resolve output values based on inputData
*/
resolve() {
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);
}
/**
* @memberof Buffer
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
ctx.strokeStyle = colors["stroke_alt"];
ctx.lineWidth = correctWidth(3);
const xx = this.x;
const yy = this.y;
ctx.beginPath();
ctx.fillStyle = colors["fill"];
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 = colors["hover_select"];
ctx.fill();
ctx.stroke();
}
generateVerilog() {
return "assign " + this.output1.verilogLabel + " = " + this.inp1.verilogLabel + ";"
}
}
/**
* @memberof Buffer
* Help Tip
* @type {string}
* @category modules
*/
Buffer.prototype.tooltipText =
"Buffer ToolTip : Isolate the input from the output.";
Buffer.prototype.helplink =
"https://docs.circuitverse.org/#/miscellaneous?id=buffer";
Buffer.prototype.objectType = "Buffer";

173
simulator/src/modules/Button.js Executable file
View file

@ -0,0 +1,173 @@
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
import {
correctWidth, lineTo, moveTo, drawCircle2,
} from '../canvasApi';
/**
* @class
* Button
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @category modules
*/
export default class Button extends CircuitElement {
constructor(x, y, scope = globalScope, dir = 'RIGHT') {
super(x, y, scope, dir, 1);
/* this is done in this.baseSetup() now
this.scope['Button'].push(this);
*/
this.state = 0;
this.output1 = new Node(30, 0, 1, this);
this.wasClicked = false;
this.rectangleObject = false;
this.setDimensions(10, 10);
}
/**
* @memberof Button
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
nodes: {
output1: findNode(this.output1),
},
values: {
state: this.state,
},
constructorParamaters: [this.direction, this.bitWidth],
};
return data;
}
/**
* @memberof Button
* resolve output values based on inputData
*/
resolve() {
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);
}
/**
* @memberof Button
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
const xx = this.x;
const 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();
}
subcircuitDraw(xOffset = 0, yOffset = 0) {
var ctx = simulationArea.context;
var xx = this.subcircuitMetadata.x + xOffset;
var yy = this.subcircuitMetadata.y + yOffset;
ctx.fillStyle = "#ddd";
ctx.strokeStyle = "#353535";
ctx.lineWidth = correctWidth(3);
ctx.beginPath();
drawCircle2(ctx, 0, 0, 6, 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();
}
static verilogInstructions() {
return `Button - Buttons are not natively supported in verilog, consider using Inputs instead\n`;
}
verilogBaseType() {
return this.verilogName() + (Button.selSizes.length-1);
}
//this code to generate Verilog
generateVerilog() {
Button.selSizes.push(this.data);
return CircuitElement.prototype.generateVerilog.call(this);
}
static moduleVerilog() {
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
static resetVerilog() {
Button.selSizes = [];
}
}
/**
* @memberof Button
* Help Tip
* @type {string}
* @category modules
*/
Button.prototype.tooltipText = 'Button ToolTip: High(1) when pressed and Low(0) when released.';
/**
* @memberof Button
* Help URL
* @type {string}
* @category modules
*/
Button.prototype.helplink = 'https://docs.circuitverse.org/#/inputElements?id=button';
/**
* @memberof Button
* @type {number}
* @category modules
*/
Button.prototype.propagationDelay = 0;
Button.prototype.objectType = 'Button';
Button.prototype.canShowInSubcircuit = true;

View file

@ -0,0 +1,214 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, rect2, fillText, oppositeDirection } from "../canvasApi";
import { colors } from "../themer/themer";
function bin2dec(binString) {
return parseInt(binString, 2);
}
function dec2bin(dec, bitWidth = undefined) {
// only for positive nos
var bin = dec.toString(2);
if (bitWidth == undefined) return bin;
return "0".repeat(bitWidth - bin.length) + bin;
}
/**
* @class
* ConstantVal
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node.
* @param {string=} state - The state of element
* @category modules
*/
export default class ConstantVal extends CircuitElement {
constructor(
x,
y,
scope = globalScope,
dir = "RIGHT",
bitWidth = 1,
state = "0"
) {
// state = state || prompt('Enter value');
super(x, y, scope, dir, state.length);
/* this is done in this.baseSetup() now
this.scope['ConstantVal'].push(this);
*/
this.state = state;
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 = "";
}
generateVerilog() {
return `localparam [${this.bitWidth - 1}:0] ${this.verilogLabel}=${
this.bitWidth
}b'${this.state};`;
}
/**
* @memberof ConstantVal
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
nodes: {
output1: findNode(this.output1),
},
constructorParamaters: [this.direction, this.bitWidth, this.state],
};
return data;
}
/**
* @memberof ConstantVal
* resolve output values based on inputData
*/
resolve() {
this.output1.value = bin2dec(this.state);
simulationArea.simulationQueue.add(this.output1);
}
/**
* @memberof ConstantVal
* updates state using a prompt when dbl clicked
*/
dblclick() {
this.state = prompt("Re enter the value") || "0";
this.newBitWidth(this.state.toString().length);
}
/**
* @memberof ConstantVal
* function to change bitwidth of the element
* @param {number} bitWidth - new bitwidth
*/
newBitWidth(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;
}
}
/**
* @memberof ConstantVal
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = colors["stroke"];
ctx.fillStyle = colors["fill"];
ctx.lineWidth = correctWidth(1);
const xx = this.x;
const 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 = colors["hover_select"];
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.fillStyle = colors["input_text"];
ctx.textAlign = "center";
const bin = this.state; // dec2bin(this.state,this.bitWidth);
for (let k = 0; k < this.bitWidth; k++) {
fillText(
ctx,
bin[k],
xx - 10 * this.bitWidth + 10 + k * 20,
yy + 5
);
}
ctx.fill();
}
/**
* @memberof ConstantVal
* function to change direction of ConstantVal
* @param {string} dir - new direction
*/
newDirection(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];
}
generateVerilog() {
return `assign ${this.output1.verilogLabel} = ${this.bitWidth}'b${this.state};`;
}
}
/**
* @memberof ConstantVal
* Help Tip
* @type {string}
* @category modules
*/
ConstantVal.prototype.tooltipText =
"Constant ToolTip: Bits are fixed. Double click element to change the bits.";
/**
* @memberof ConstantVal
* Help URL
* @type {string}
* @category modules
*/
ConstantVal.prototype.helplink =
"https://docs.circuitverse.org/#/inputElements?id=constantval";
/**
* @memberof ConstantVal
* @type {number}
* @category modules
*/
ConstantVal.prototype.propagationDelay = 0;
ConstantVal.prototype.objectType = "ConstantVal";

View file

@ -0,0 +1,122 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, lineTo, moveTo, drawCircle2 } from "../canvasApi";
import { changeInputSize } from "../modules";
/**
* @class
* ControlledInverter
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node.
* @category modules
*/
import { colors } from "../themer/themer";
export default class ControlledInverter extends CircuitElement {
constructor(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['ControlledInverter'].push(this);
*/
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");
}
/**
* @memberof ControlledInverter
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [this.direction, this.bitWidth],
nodes: {
output1: findNode(this.output1),
inp1: findNode(this.inp1),
state: findNode(this.state),
},
};
return data;
}
/**
* @memberof ControlledInverter
* function to change bitwidth of the element
* @param {number} bitWidth - new bitwidth
*/
newBitWidth(bitWidth) {
this.inp1.bitWidth = bitWidth;
this.output1.bitWidth = bitWidth;
this.bitWidth = bitWidth;
}
/**
* @memberof ControlledInverter
* resolve output values based on inputData
*/
resolve() {
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;
}
}
/**
* @memberof ControlledInverter
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
ctx.strokeStyle = colors["stroke"];
ctx.lineWidth = correctWidth(3);
const xx = this.x;
const yy = this.y;
ctx.beginPath();
ctx.fillStyle = colors["fill"];
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 = colors["hover_select"];
ctx.fill();
ctx.stroke();
ctx.beginPath();
drawCircle2(ctx, 25, 0, 5, xx, yy, this.direction);
ctx.stroke();
}
generateVerilog() {
return `assign ${this.output1.verilogLabel} = (${this.state.verilogLabel}!=0) ? ~${this.inp1.verilogLabel} : ${this.inp1.verilogLabel};`;
}
}
/**
* @memberof ControlledInverter
* Help Tip
* @type {string}
* @category modules
*/
ControlledInverter.prototype.tooltipText =
"Controlled Inverter ToolTip : Controlled buffer and NOT gate.";
ControlledInverter.prototype.objectType = "ControlledInverter";

View file

@ -0,0 +1,185 @@
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
import { lineTo, moveTo, fillText, correctWidth, rect2 } from '../canvasApi';
import { colors } from '../themer/themer';
/**
* @class
* Counter component.
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {number=} rows - number of rows
* @param {number=} cols - number of columns.
* Counts from zero to a particular maximum value, which is either
* specified by an input pin or determined by the Counter's bitWidth.
* The counter outputs its current value and a flag that indicates
* when the output value is zero and the clock is 1.
* The counter can be reset to zero at any point using the RESET pin.
* @category modules
*/
export default class Counter extends CircuitElement {
constructor(x, y, scope = globalScope, bitWidth = 8) {
super(x, y, scope, "RIGHT", bitWidth);
/* this is done in this.baseSetup() now
this.scope['Counter'].push(this);
*/
this.directionFixed = true;
this.rectangleObject = true;
this.setDimensions(20, 20);
this.maxValue = new Node(-20, -10, 0, this, this.bitWidth, "MaxValue");
this.clock = new Node(-20, +10, 0, this, 1, "Clock");
this.reset = new Node(0, 20, 0, this, 1, "Reset");
this.output = new Node(20, -10, 1, this, this.bitWidth, "Value");
this.zero = new Node(20, 10, 1, this, 1, "Zero");
this.value = 0;
this.prevClockState = undefined;
}
customSave() {
return {
nodes: {
maxValue: findNode(this.maxValue),
clock: findNode(this.clock),
reset: findNode(this.reset),
output: findNode(this.output),
zero: findNode(this.zero),
},
constructorParamaters: [this.bitWidth]
};
}
newBitWidth(bitWidth) {
this.bitWidth = bitWidth;
this.maxValue.bitWidth = bitWidth;
this.output.bitWidth = bitWidth;
}
isResolvable() {
return true;
}
resolve() {
// Max value is either the value in the input pin or the max allowed by the bitWidth.
var maxValue = this.maxValue.value != undefined ? this.maxValue.value : (1 << this.bitWidth) - 1;
var outputValue = this.value;
// Increase value when clock is raised
if (this.clock.value != this.prevClockState && this.clock.value == 1) {
outputValue++;
}
this.prevClockState = this.clock.value;
// Limit to the effective maximum value; this also accounts for bitWidth changes.
outputValue = outputValue % (maxValue + 1);
// Reset to zero if RESET pin is on
if (this.reset.value == 1) {
outputValue = 0;
}
// Output the new value
this.value = outputValue;
if (this.output.value != outputValue) {
this.output.value = outputValue;
simulationArea.simulationQueue.add(this.output);
}
// Output the zero signal
var zeroValue = this.clock.value == 1 && outputValue == 0 ? 1 : 0;
if (this.zero.value != zeroValue) {
this.zero.value = zeroValue;
simulationArea.simulationQueue.add(this.zero);
}
}
customDraw() {
var ctx = simulationArea.context;
var xx = this.x;
var yy = this.y;
ctx.beginPath();
ctx.font = "20px Raleway";
ctx.fillStyle = colors['input_text'];
ctx.textAlign = "center";
fillText(ctx, this.value.toString(16), this.x, this.y + 5);
ctx.fill();
ctx.strokeStyle = colors['stroke'];
ctx.beginPath();
moveTo(ctx, -20, 5, xx, yy, this.direction);
lineTo(ctx, -15, 10, xx, yy, this.direction);
lineTo(ctx, -20, 15, xx, yy, this.direction);
ctx.stroke();
}
// Draws the element in the subcuircuit. Used in layout mode
subcircuitDraw(xOffset = 0, yOffset = 0) {
var ctx = simulationArea.context;
var xx = this.subcircuitMetadata.x + xOffset;
var yy = this.subcircuitMetadata.y + yOffset;
ctx.beginPath();
ctx.font = "20px Raleway";
ctx.fillStyle = "green";
ctx.textAlign = "center";
fillText(ctx, this.value.toString(16), xx + 10, yy + 17);
ctx.fill();
ctx.beginPath();
ctx.lineWidth = correctWidth(1);
rect2(ctx, 0, 0, 20, 20, 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.6)";
ctx.fill();
}
}
static moduleVerilog() {
return `
module Counter(val, zero, max, clk, rst);
parameter WIDTH = 1;
output reg [WIDTH-1:0] val;
output reg zero;
input [WIDTH-1:0] max;
input clk, rst;
initial
val = 0;
always @ (val)
if (val == 0)
zero = 1;
else
zero = 0;
always @ (posedge clk or posedge rst) begin
if (rst)
val <= 0;
else
if (val == max)
val <= 0;
else
val <= val + 1;
end
endmodule`;
}
}
Counter.prototype.tooltipText = "Counter: a binary counter from zero to a given maximum value";
Counter.prototype.helplink = "https://docs.circuitverse.org/#/inputElements?id=counter"; Counter.prototype.objectType = 'Counter';
Counter.prototype.objectType = 'Counter';
Counter.prototype.canShowInSubcircuit = true;
Counter.prototype.layoutProperties = {
rightDimensionX : 20,
leftDimensionX : 0,
upDimensionY : 0,
downDimensionY: 20
}

290
simulator/src/modules/Decoder.js Executable file
View file

@ -0,0 +1,290 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, lineTo, moveTo, rect, fillText } from "../canvasApi";
/**
* @class
* Decoder
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node.
* @category modules
*/
import { colors } from "../themer/themer";
export default class Decoder extends CircuitElement {
constructor(x, y, scope = globalScope, dir = "LEFT", bitWidth = 1) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['Decoder'].push(this);
*/
// 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;
// let 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",
// },
// }
// eslint-disable-next-line no-shadow
this.newBitWidth = function (bitWidth) {
// this.bitWidth = bitWidth;
// for (let 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;
const obj = new Decoder(
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 (let i = 0; i < this.outputsize; i++) {
const 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");
}
/**
* @memberof Decoder
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [this.direction, this.bitWidth],
nodes: {
output1: this.output1.map(findNode),
input: findNode(this.input),
},
};
return data;
}
/**
* @memberof Decoder
* resolve output values based on inputData
*/
resolve() {
for (let i = 0; i < this.output1.length; i++) {
this.output1[i].value = 0;
}
if(this.input.value !== undefined) this.output1[this.input.value].value = 1; // if input is undefined, don't change output
for (let i = 0; i < this.output1.length; i++) {
simulationArea.simulationQueue.add(this.output1[i]);
}
}
/**
* @memberof Decoder
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
const xx = this.x;
const 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 = colors["stroke"];
ctx.lineWidth = correctWidth(4);
ctx.fillStyle = colors["fill"];
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 = colors["hover_select"];
}
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);
for (let 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();
}
verilogBaseType() {
return this.verilogName() + this.output1.length;
}
//this code to generate Verilog
generateVerilog() {
Decoder.selSizes.add(this.bitWidth);
return CircuitElement.prototype.generateVerilog.call(this);
}
static moduleVerilog() {
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
static resetVerilog() {
Decoder.selSizes = new Set();
}
}
/**
* @memberof Decoder
* Help Tip
* @type {string}
* @category modules
*/
Decoder.prototype.tooltipText =
"Decoder ToolTip : Converts coded inputs into coded outputs.";
Decoder.prototype.helplink =
"https://docs.circuitverse.org/#/decodersandplexers?id=decoder";
Decoder.prototype.objectType = "Decoder";

View file

@ -0,0 +1,324 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, lineTo, moveTo, fillText } from "../canvasApi";
/**
* @class
* Demultiplexer
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node.
* @param {number=} controlSignalSize - 1 by default
* @category modules
*/
import { colors } from "../themer/themer";
export default class Demultiplexer extends CircuitElement {
constructor(
x,
y,
scope = globalScope,
dir = "LEFT",
bitWidth = 1,
controlSignalSize = 1
) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['Demultiplexer'].push(this);
*/
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;
const obj = new Demultiplexer(
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: "10",
min: "1",
func: "changeControlSignalSize",
},
};
// eslint-disable-next-line no-shadow
this.newBitWidth = function (bitWidth) {
this.bitWidth = bitWidth;
for (let 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 (let i = 0; i < this.outputsize; i++) {
const 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"
);
}
/**
* @memberof Demultiplexer
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [
this.direction,
this.bitWidth,
this.controlSignalSize,
],
nodes: {
output1: this.output1.map(findNode),
input: findNode(this.input),
controlSignalInput: findNode(this.controlSignalInput),
},
};
return data;
}
/**
* @memberof Demultiplexer
* resolve output values based on inputData
*/
resolve() {
for (let i = 0; i < this.output1.length; i++) {
this.output1[i].value = 0;
}
this.output1[this.controlSignalInput.value].value = this.input.value;
for (let i = 0; i < this.output1.length; i++) {
simulationArea.simulationQueue.add(this.output1[i]);
}
}
/**
* @memberof Demultiplexer
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
const xx = this.x;
const 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 = colors["stroke"];
ctx.lineWidth = correctWidth(4);
ctx.fillStyle = colors["fill"];
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 = colors["hover_select"];
}
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);
for (let 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();
}
verilogBaseType() {
return this.verilogName() + this.output1.length;
}
//this code to generate Verilog
generateVerilog() {
Demultiplexer.selSizes.add(this.controlSignalSize);
return CircuitElement.prototype.generateVerilog.call(this);
}
//generate the needed modules
static moduleVerilog() {
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
static resetVerilog() {
Demultiplexer.selSizes = new Set();
}
}
/**
* @memberof Demultiplexer
* Help Tip
* @type {string}
* @category modules
*/
Demultiplexer.prototype.tooltipText =
"DeMultiplexer ToolTip : Multiple outputs and a single line input.";
Demultiplexer.prototype.helplink =
"https://docs.circuitverse.org/#/decodersandplexers?id=demultiplexer";
Demultiplexer.prototype.objectType = "Demultiplexer";

View file

@ -0,0 +1,174 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, lineTo, moveTo, arc, colorToRGBA, drawCircle2, validColor} from "../canvasApi";
import { changeInputSize } from "../modules";
/**
* @class
* DigitalLed
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} color - color of led
* @category modules
*/
import { colors } from "../themer/themer";
export default class DigitalLed extends CircuitElement {
constructor(x, y, scope = globalScope, color = "Red") {
// Calling base class constructor
super(x, y, scope, "UP", 1);
/* this is done in this.baseSetup() now
this.scope['DigitalLed'].push(this);
*/
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;
const temp = colorToRGBA(this.color);
this.actualColor = `rgba(${temp[0]},${temp[1]},${temp[2]},${0.8})`;
}
/**
* @memberof DigitalLed
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [this.color],
nodes: {
inp1: findNode(this.inp1),
},
};
return data;
}
/**
* @memberof DigitalLed
* function to change color of the led
*/
changeColor(value) {
if (validColor(value)) {
this.color = value;
const temp = colorToRGBA(this.color);
this.actualColor = `rgba(${temp[0]},${temp[1]},${temp[2]},${0.8})`;
}
}
/**
* @memberof DigitalLed
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
const xx = this.x;
const 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 = colors["hover_select"];
ctx.fill();
}
// Draws the element in the subcircuit. Used in layout mode
subcircuitDraw(xOffset = 0, yOffset = 0) {
var ctx = simulationArea.context;
var xx = this.subcircuitMetadata.x + xOffset;
var yy = this.subcircuitMetadata.y + yOffset;
ctx.strokeStyle = "#090a0a";
ctx.fillStyle = ["rgba(227,228,229,0.8)", this.actualColor][this.inp1.value || 0];
ctx.lineWidth = correctWidth(1);
ctx.beginPath();
drawCircle2(ctx, 0, 0, 6, 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();
}
generateVerilog() {
var label = this.label ? this.verilogLabel : this.inp1.verilogLabel;
return `
always @ (*)
$display("DigitalLed:${label}=%d", ${this.inp1.verilogLabel});`;
}
}
/**
* @memberof DigitalLed
* Help Tip
* @type {string}
* @category modules
*/
DigitalLed.prototype.tooltipText =
"Digital Led ToolTip: Digital LED glows high when input is High(1).";
/**
* @memberof DigitalLed
* Help URL
* @type {string}
* @category modules
*/
DigitalLed.prototype.helplink =
"https://docs.circuitverse.org/#/outputs?id=digital-led";
/**
* @memberof DigitalLed
* Mutable properties of the element
* @type {JSON}
* @category modules
*/
DigitalLed.prototype.mutableProperties = {
color: {
name: "Color: ",
type: "text",
func: "changeColor",
},
};
DigitalLed.prototype.objectType = "DigitalLed";
DigitalLed.prototype.canShowInSubcircuit = true;

234
simulator/src/modules/Flag.js Executable file
View file

@ -0,0 +1,234 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, rect2, fillText } from "../canvasApi";
import plotArea from "../plotArea";
import EventQueue from '../eventQueue';
/**
* @class
* Flag
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node.
* @param {string} identifier - id
* @category modules
*/
import { colors } from "../themer/themer";
export default class Flag extends CircuitElement {
constructor(
x,
y,
scope = globalScope,
dir = "RIGHT",
bitWidth = 1,
identifier
) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['Flag'].push(this);
*/
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.flagTimeUnit = 0;
this.inp1 = new Node(40, 0, 0, this);
}
resolve() {
this.flagTimeUnit = simulationArea.simulationQueue.time;
const time = plotArea.getPlotTime(this.flagTimeUnit);
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;
}
this.plotValues.push([time, this.inp1.value]);
}
/**
* @memberof Flag
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [this.direction, this.bitWidth],
nodes: {
inp1: findNode(this.inp1),
},
values: {
identifier: this.identifier,
},
};
return data;
}
/**
* @memberof Flag
* set the flag id
* @param {number} id - identifier for flag
*/
setIdentifier(id = "") {
if (id.length === 0) return;
this.identifier = id;
const len = this.identifier.length;
if (len === 1) this.xSize = 20;
else if (len > 1 && len < 4) this.xSize = 10;
else this.xSize = 0;
}
/**
* @memberof Flag
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = colors["stroke"];
ctx.fillStyle = colors["fill"];
ctx.lineWidth = correctWidth(1);
const xx = this.x;
const 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 = colors["hover_select"];
ctx.fill();
ctx.stroke();
ctx.font = "14px Raleway";
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 Raleway";
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();
}
/**
* @memberof Flag
* function to change direction of Flag
* @param {string} dir - new direction
*/
newDirection(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();
}
}
/**
* @memberof Flag
* Help Tip
* @type {string}
* @category modules
*/
Flag.prototype.tooltipText =
"FLag ToolTip: Use this for debugging and plotting.";
Flag.prototype.helplink =
"https://docs.circuitverse.org/#/timing_diagrams?id=using-flags";
/**
* @memberof Flag
* Help URL
* @type {string}
* @category modules
*/
Flag.prototype.helplink =
"https://docs.circuitverse.org/#/miscellaneous?id=tunnel";
/**
* @memberof Flag
* Mutable properties of the element
* @type {JSON}
* @category modules
*/
Flag.prototype.mutableProperties = {
identifier: {
name: "Debug Flag identifier",
type: "text",
maxlength: "5",
func: "setIdentifier",
},
};
Flag.prototype.objectType = "Flag";
Flag.prototype.propagationDelay = 0;

126
simulator/src/modules/Ground.js Executable file
View file

@ -0,0 +1,126 @@
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
import {
correctWidth, lineTo, moveTo, arc,
} from '../canvasApi';
import { changeInputSize } from '../modules';
/**
* @class
* Ground
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {number=} bitWidth - bit width per node.
* @category modules
*/
import { colors } from '../themer/themer';
export default class Ground extends CircuitElement {
constructor(x, y, scope = globalScope, bitWidth = 1) {
super(x, y, scope, 'RIGHT', bitWidth);
/* this is done in this.baseSetup() now
this.scope['Ground'].push(this);
*/
this.rectangleObject = false;
this.setDimensions(10, 10);
this.directionFixed = true;
this.output1 = new Node(0, -10, 1, this);
}
/**
* @memberof Ground
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
nodes: {
output1: findNode(this.output1),
},
values: {
state: this.state,
},
constructorParamaters: [this.direction, this.bitWidth],
};
return data;
}
/**
* @memberof Ground
* resolve output values based on inputData
*/
resolve() {
this.output1.value = 0;
simulationArea.simulationQueue.add(this.output1);
}
/**
* @memberof Ground
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
nodes: {
output1: findNode(this.output1),
},
constructorParamaters: [this.bitWidth],
};
return data;
}
/**
* @memberof Ground
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
//
ctx.beginPath();
ctx.strokeStyle = [colors['stroke'], 'brown'][((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || simulationArea.multipleObjectSelections.contains(this)) + 0];
ctx.lineWidth = correctWidth(3);
const xx = this.x;
const 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();
}
generateVerilog() {
return `assign ${this.output1.verilogLabel} = ${this.bitWidth}'b0;`;
}
}
/**
* @memberof Ground
* Help Tip
* @type {string}
* @category modules
*/
Ground.prototype.tooltipText = 'Ground: All bits are Low(0).';
/**
* @memberof Ground
* Help URL
* @type {string}
* @category modules
*/
Ground.prototype.helplink = 'https://docs.circuitverse.org/#/inputElements?id=ground';
/**
* @memberof Ground
* @type {number}
* @category modules
*/
Ground.prototype.propagationDelay = 0;
Ground.prototype.objectType = 'Ground';

View file

@ -0,0 +1,276 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, lineTo, moveTo, arc, rect2 } from "../canvasApi";
import { changeInputSize } from "../modules";
/**
* @class
* HexDisplay
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @category modules
*/
import { colors } from "../themer/themer";
export default class HexDisplay extends CircuitElement {
constructor(x, y, scope = globalScope) {
super(x, y, scope, "RIGHT", 4);
/* this is done in this.baseSetup() now
this.scope['HexDisplay'].push(this);
*/
this.directionFixed = true;
this.fixedBitWidth = true;
this.setDimensions(30, 50);
this.inp = new Node(0, -50, 0, this, 4);
this.direction = "RIGHT";
}
/**
* @memberof HexDisplay
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
nodes: {
inp: findNode(this.inp),
},
};
return data;
}
/**
* @memberof HexDisplay
* function to draw element
*/
customDrawSegment(x1, y1, x2, y2, color) {
if (color === undefined) color = "lightgrey";
var ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = color;
ctx.lineWidth = correctWidth(5);
const xx = this.x;
const yy = this.y;
moveTo(ctx, x1, y1, xx, yy, this.direction);
lineTo(ctx, x2, y2, xx, yy, this.direction);
ctx.closePath();
ctx.stroke();
}
/**
* @memberof HexDisplay
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
const xx = this.x;
const yy = this.y;
ctx.strokeStyle = colors["stroke"];
ctx.lineWidth = correctWidth(3);
let a = 0,
b = 0,
c = 0,
d = 0,
e = 0,
f = 0,
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]);
}
subcircuitDrawSegment(x1, y1, x2, y2, color, xxSegment, yySegment) {
if (color == undefined) color = "lightgrey";
var ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = color;
ctx.lineWidth = correctWidth(3);
var xx = xxSegment;
var yy = yySegment;
moveTo(ctx, x1, y1, xx, yy, this.direction);
lineTo(ctx, x2, y2, xx, yy, this.direction);
ctx.closePath();
ctx.stroke();
}
// Draws the element in the subcircuit. Used in layout mode
subcircuitDraw(xOffset = 0, yOffset = 0) {
var ctx = simulationArea.context;
var xx = this.subcircuitMetadata.x + xOffset;
var yy = this.subcircuitMetadata.y + yOffset;
ctx.strokeStyle = "black";
ctx.lineWidth = correctWidth(3);
let a = 0,
b = 0,
c = 0,
d = 0,
e = 0,
f = 0,
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.subcircuitDrawSegment(10, -20, 10, -38, ["lightgrey", "red"][b],xx, yy);
this.subcircuitDrawSegment(10, -17, 10, 1, ["lightgrey", "red"][c],xx, yy);
this.subcircuitDrawSegment(-10, -20, -10, -38, ["lightgrey", "red"][f],xx, yy);
this.subcircuitDrawSegment(-10, -17, -10, 1, ["lightgrey", "red"][e],xx, yy);
this.subcircuitDrawSegment(-8, -38, 8, -38, ["lightgrey", "red"][a],xx, yy);
this.subcircuitDrawSegment(-8, -18, 8, -18, ["lightgrey", "red"][g],xx, yy);
this.subcircuitDrawSegment(-8, 1, 8, 1, ["lightgrey", "red"][d],xx, yy);
ctx.beginPath();
ctx.strokeStyle = "black";
ctx.lineWidth = correctWidth(1);
rect2(ctx, -15, -42, 33, 51, 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.6)";
ctx.fill();
}
}
generateVerilog() {
return `
always @ (*)
$display("HexDisplay:${this.verilogLabel}=%d", ${this.inp.verilogLabel});`;
}
}
/**
* @memberof HexDisplay
* Help Tip
* @type {string}
* @category modules
*/
HexDisplay.prototype.tooltipText =
"Hex Display ToolTip: Inputs a 4 Bit Hex number and displays it.";
/**
* @memberof HexDisplay
* Help URL
* @type {string}
* @category modules
*/
HexDisplay.prototype.helplink =
"https://docs.circuitverse.org/#/outputs?id=hex-display";
HexDisplay.prototype.objectType = "HexDisplay";
HexDisplay.prototype.canShowInSubcircuit = true;
HexDisplay.prototype.layoutProperties = {
rightDimensionX : 20,
leftDimensionX : 15,
upDimensionY : 42,
downDimensionY: 10
}

View file

@ -0,0 +1,225 @@
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
import { correctWidth, rect, fillText, drawImage} from '../canvasApi';
import { colors } from '../themer/themer';
import { promptFile, showMessage, getImageDimensions} from '../utils'
/**
* @class
* Image
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {number=} rows - number of rows
* @param {number=} cols - number of columns.
* @category modules
*/
export default class ImageAnnotation extends CircuitElement {
constructor(x, y, scope = globalScope, rows = 15, cols = 20, imageUrl='') {
super(x, y, scope, 'RIGHT', 1);
this.directionFixed = true;
this.fixedBitWidth = true;
this.imageUrl = imageUrl;
this.cols = cols || parseInt(prompt('Enter cols:'), 10);
this.rows = rows || parseInt(prompt('Enter rows:'), 10);
this.setSize();
this.loadImage();
}
/**
* @memberof Image
* @param {number} size - new size of rows
*/
changeRowSize(size) {
if (size === undefined || size < 5 || size > 1000) return;
if (this.rows === size) return;
this.rows = parseInt(size, 10);
this.setSize();
return this;
}
/**
* @memberof Image
* @param {number} size - new size of columns
*/
changeColSize(size) {
if (size === undefined || size < 5 || size > 1000) return;
if (this.cols === size) return;
this.cols = parseInt(size, 10);
this.setSize();
return this;
}
/**
* @memberof Image
* listener function to change direction of Image
* @param {string} dir - new direction
*/
keyDown3(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); }
}
/**
* @memberof Image
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [this.rows, this.cols, this.imageUrl],
};
return data;
}
/**
* @memberof Image
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
const xx = this.x;
const yy = this.y;
var w = this.elementWidth;
var h = this.elementHeight;
if(this.image && this.image.complete) {
drawImage(ctx, this.image, xx - w / 2, yy - h / 2, w, h);
}
else {
ctx.beginPath();
ctx.strokeStyle = 'rgba(0,0,0,1)';
ctx.setLineDash([5 * globalScope.scale, 5 * globalScope.scale]);
ctx.lineWidth = correctWidth(1.5);
rect(ctx, xx - w / 2, yy - h / 2, w, h);
ctx.stroke();
if (simulationArea.lastSelected === this || simulationArea.multipleObjectSelections.contains(this)) {
ctx.fillStyle = 'rgba(255, 255, 32,0.1)';
ctx.fill();
}
ctx.beginPath();
ctx.textAlign = 'center';
ctx.fillStyle = colors['text'];
fillText(ctx, "Double Click to Insert Image", xx, yy, 10);
ctx.fill();
ctx.setLineDash([]);
}
}
/**
* Procedure if image is double clicked
**/
dblclick() {
if (embed) return;
this.uploadImage();
}
async uploadImage() {
var file = await promptFile("image/*", false);
var apiUrl = 'https://api.imgur.com/3/image';
var apiKey = '9a33b3b370f1054';
var settings = {
crossDomain: true,
processData: false,
contentType: false,
type: 'POST',
url: apiUrl,
headers: {
Authorization: 'Client-ID ' + apiKey,
Accept: 'application/json',
},
mimeType: 'multipart/form-data',
};
var formData = new FormData();
formData.append('image', file);
settings.data = formData;
// Response contains stringified JSON
// Image URL available at response.data.link
showMessage('Uploading Image');
var response = await $.ajax(settings);
showMessage('Image Uploaded');
this.imageUrl = JSON.parse(response).data.link;
this.loadImage();
}
async loadImage() {
if(!this.imageUrl) return;
this.image = new Image;
this.image.crossOrigin="anonymous"
this.image.src = this.imageUrl;
}
/**
* @memberof Image
* function to reset or (internally) set size
*/
setSize() {
this.elementWidth = this.cols * 10;
this.elementHeight = this.rows * 10;
this.upDimensionY = this.elementHeight/2;
this.downDimensionY = this.elementHeight/2;
this.leftDimensionX = this.elementWidth/2;
this.rightDimensionX = this.elementWidth/2;
}
}
/**
* @memberof Image
* Help Tip
* @type {string}
* @category modules
*/
ImageAnnotation.prototype.tooltipText = 'Image ToolTip: Embed an image in the circuit for annotation';
ImageAnnotation.prototype.propagationDelayFixed = true;
/**
* @memberof Image
* Mutable properties of the element
* @type {JSON}
* @category modules
*/
ImageAnnotation.prototype.mutableProperties = {
cols: {
name: 'Columns',
type: 'number',
max: '1000',
min: '5',
func: 'changeColSize',
},
rows: {
name: 'Rows',
type: 'number',
max: '1000',
min: '5',
func: 'changeRowSize',
},
};
ImageAnnotation.prototype.objectType = 'ImageAnnotation';
ImageAnnotation.prototype.rectangleObject = false;
ImageAnnotation.prototype.mutableProperties = {
imageUrl: {
name: 'Upload Image',
type: 'button',
func: 'uploadImage',
},
cols: {
name: 'Columns',
type: 'number',
max: '1000',
min: '5',
func: 'changeColSize',
},
rows: {
name: 'Rows',
type: 'number',
max: '1000',
min: '5',
func: 'changeRowSize',
},
};

194
simulator/src/modules/Input.js Executable file
View file

@ -0,0 +1,194 @@
/* eslint-disable no-unused-expressions */
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
import {
correctWidth, oppositeDirection, fillText,
} from '../canvasApi';
import { getNextPosition } from '../modules';
import { generateId } from '../utils';
/**
* @class
* Input
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node.
* @param {Object=} layoutProperties - x,y and id
* @category modules
*/
import { colors } from '../themer/themer';
function bin2dec(binString) {
return parseInt(binString, 2);
}
function dec2bin(dec, bitWidth = undefined) {
// only for positive nos
var bin = (dec).toString(2);
if (bitWidth == undefined) return bin;
return '0'.repeat(bitWidth - bin.length) + bin;
}
export default class Input extends CircuitElement {
constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1, layoutProperties) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['Input'].push(this);
*/
if (layoutProperties) { this.layoutProperties = layoutProperties; } else {
this.layoutProperties = {};
this.layoutProperties.x = 0;
this.layoutProperties.y = getNextPosition(0, scope);
this.layoutProperties.id = generateId();
}
// Call base class constructor
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
}
/**
* @memberof Input
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
nodes: {
output1: findNode(this.output1),
},
values: {
state: this.state,
},
constructorParamaters: [this.direction, this.bitWidth, this.layoutProperties],
};
return data;
}
/**
* @memberof Input
* resolve output values based on inputData
*/
resolve() {
this.output1.value = this.state;
simulationArea.simulationQueue.add(this.output1);
}
// Check if override is necessary!!
/**
* @memberof Input
* function to change bitwidth of the element
* @param {number} bitWidth - new bitwidth
*/
newBitWidth(bitWidth) {
if (bitWidth < 1) return;
const 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;
}
}
/**
* @memberof Input
* listener function to set selected index
*/
click() { // toggle
let 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;
}
/**
* @memberof Input
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
ctx.beginPath();
ctx.lineWidth = correctWidth(3);
const xx = this.x;
const yy = this.y;
ctx.beginPath();
ctx.fillStyle = colors['input_text'];
ctx.textAlign = 'center';
const bin = dec2bin(this.state, this.bitWidth);
for (let k = 0; k < this.bitWidth; k++) { fillText(ctx, bin[k], xx - 10 * this.bitWidth + 10 + (k) * 20, yy + 5); }
ctx.fill();
}
/**
* @memberof Input
* function to change direction of input
* @param {string} dir - new direction
*/
newDirection(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];
}
/**
* @memberof Input
* function to find position of mouse click
*/
findPos() {
return Math.round((simulationArea.mouseX - this.x + 10 * this.bitWidth) / 20.0);
}
}
/**
* @memberof Input
* Help Tip
* @type {string}
* @category modules
*/
Input.prototype.tooltipText = 'Input ToolTip: Toggle the individual bits by clicking on them.';
/**
* @memberof Input
* Help URL
* @type {string}
* @category modules
*/
Input.prototype.helplink = 'https://docs.circuitverse.org/#/inputElements?id=input';
/**
* @memberof Input
* @type {number}
* @category modules
*/
Input.prototype.propagationDelay = 0;
Input.prototype.objectType = 'Input';

144
simulator/src/modules/LSB.js Executable file
View file

@ -0,0 +1,144 @@
import CircuitElement from "../circuitElement";
import Node, { findNode, dec2bin } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, rect, fillText } from "../canvasApi";
/**
* @class
* LSB
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node.
* @category modules
*/
import { colors } from "../themer/themer";
export default class LSB extends CircuitElement {
constructor(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['LSB'].push(this);
*/
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.intputSize = 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);
}
/**
* @memberof LSB
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
nodes: {
inp1: findNode(this.inp1),
output1: findNode(this.output1),
enable: findNode(this.enable),
},
constructorParamaters: [this.direction, this.bitWidth],
};
return data;
}
/**
* @memberof LSB
* function to change bitwidth of the element
* @param {number} bitWidth - new bitwidth
*/
newBitWidth(bitWidth) {
// this.inputSize = 1 << bitWidth
this.inputSize = bitWidth;
this.inp1.bitWidth = this.inputSize;
this.bitWidth = bitWidth;
this.output1.bitWidth = bitWidth;
}
/**
* @memberof LSB
* resolve output values based on inputData
*/
resolve() {
const inp = dec2bin(this.inp1.value);
let out = 0;
for (let 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);
}
/**
* @memberof LSB
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = colors["stroke"];
ctx.fillStyle = colors["fill"];
ctx.lineWidth = correctWidth(3);
const xx = this.x;
const 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 = colors["hover_select"];
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();
}
generateVerilog() {
return `assign ${this.output1.verilogLabel} = (${this.enable.verilogLabel}!=0) ? ${this.inp1.verilogLabel}[0] : 0;`;
}
}
/**
* @memberof LSB
* Help Tip
* @type {string}
* @category modules
*/
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.objectType = "LSB";

139
simulator/src/modules/MSB.js Executable file
View file

@ -0,0 +1,139 @@
import CircuitElement from "../circuitElement";
import Node, { findNode, dec2bin } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, rect, fillText } from "../canvasApi";
/**
* @class
* MSB
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node.
* @category modules
*/
import { colors } from "../themer/themer";
export default class MSB extends CircuitElement {
constructor(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['MSB'].push(this);
*/
// 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.intputSize = 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);
}
/**
* @memberof MSB
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
nodes: {
inp1: findNode(this.inp1),
output1: findNode(this.output1),
enable: findNode(this.enable),
},
constructorParamaters: [this.direction, this.bitWidth],
};
return data;
}
/**
* @memberof MSB
* function to change bitwidth of the element
* @param {number} bitWidth - new bitwidth
*/
newBitWidth(bitWidth) {
// this.inputSize = 1 << bitWidth
this.inputSize = bitWidth;
this.inp1.bitWidth = this.inputSize;
this.bitWidth = bitWidth;
this.output1.bitWidth = bitWidth;
}
/**
* @memberof MSB
* resolve output values based on inputData
*/
resolve() {
const 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);
}
/**
* @memberof MSB
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = colors["stroke"];
ctx.fillStyle = colors["fill"];
ctx.lineWidth = correctWidth(3);
const xx = this.x;
const 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 = colors["hover_select"];
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();
}
generateVerilog() {
return `assign ${this.output1.verilogLabel} = (${this.enable.verilogLabel}!=0) ? ${this.inp1.verilogLabel}[${this.inp1.bitWidth-1}] : 0;`;
}
}
/**
* @memberof MSB
* Help Tip
* @type {string}
* @category modules
*/
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.objectType = "MSB";

View file

@ -0,0 +1,344 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, lineTo, moveTo, fillText } from "../canvasApi";
import { changeInputSize } from "../modules";
/**
* @class
* Multiplexer
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node.
* @param {number=} controlSignalSize - 1 by default
* @category modules
*/
import { colors } from "../themer/themer";
export default class Multiplexer extends CircuitElement {
constructor(
x,
y,
scope = globalScope,
dir = "RIGHT",
bitWidth = 1,
controlSignalSize = 1
) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['Multiplexer'].push(this);
*/
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 (let i = 0; i < this.inputSize; i++) {
const 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"
);
}
/**
* @memberof Multiplexer
* function to change control signal of the element
*/
changeControlSignalSize(size) {
if (size === undefined || size < 1 || size > 32) return;
if (this.controlSignalSize === size) return;
const obj = new Multiplexer(
this.x,
this.y,
this.scope,
this.direction,
this.bitWidth,
size
);
this.cleanDelete();
simulationArea.lastSelected = obj;
return obj;
}
/**
* @memberof Multiplexer
* function to change bitwidth of the element
* @param {number} bitWidth - bitwidth
*/
newBitWidth(bitWidth) {
this.bitWidth = bitWidth;
for (let i = 0; i < this.inputSize; i++) {
this.inp[i].bitWidth = bitWidth;
}
this.output1.bitWidth = bitWidth;
}
/**
* @memberof Multiplexer
* @type {boolean}
*/
isResolvable() {
if (
this.controlSignalInput.value !== undefined &&
this.inp[this.controlSignalInput.value].value !== undefined
)
return true;
return false;
}
/**
* @memberof Multiplexer
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [
this.direction,
this.bitWidth,
this.controlSignalSize,
],
nodes: {
inp: this.inp.map(findNode),
output1: findNode(this.output1),
controlSignalInput: findNode(this.controlSignalInput),
},
};
return data;
}
/**
* @memberof Multiplexer
* resolve output values based on inputData
*/
resolve() {
if (this.isResolvable() === false) {
return;
}
this.output1.value = this.inp[this.controlSignalInput.value].value;
simulationArea.simulationQueue.add(this.output1);
}
/**
* @memberof Multiplexer
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
const xx = this.x;
const 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 = colors["stroke"];
ctx.fillStyle = colors["fill"];
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 = colors["hover_select"];
}
ctx.fill();
ctx.stroke();
ctx.beginPath();
// ctx.lineWidth = correctWidth(2);
ctx.fillStyle = "black";
ctx.textAlign = "center";
for (let 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();
}
verilogBaseType() {
return this.verilogName() + this.inp.length;
}
//this code to generate Verilog
generateVerilog() {
Multiplexer.selSizes.add(this.controlSignalSize);
return CircuitElement.prototype.generateVerilog.call(this);
}
//generate the needed modules
static moduleVerilog() {
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
static resetVerilog() {
Multiplexer.selSizes = new Set();
}
}
/**
* @memberof Multiplexer
* Help Tip
* @type {string}
* @category modules
*/
Multiplexer.prototype.tooltipText =
"Multiplexer ToolTip : Multiple inputs and a single line output.";
Multiplexer.prototype.helplink =
"https://docs.circuitverse.org/#/decodersandplexers?id=multiplexer";
/**
* @memberof Multiplexer
* multable properties of element
* @type {JSON}
* @category modules
*/
Multiplexer.prototype.mutableProperties = {
controlSignalSize: {
name: "Control Signal Size",
type: "number",
max: "10",
min: "1",
func: "changeControlSignalSize",
},
};
Multiplexer.prototype.objectType = "Multiplexer";

174
simulator/src/modules/NandGate.js Executable file
View file

@ -0,0 +1,174 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, lineTo, moveTo, drawCircle2, arc } from "../canvasApi";
import { changeInputSize } from "../modules";
import { gateGenerateVerilog } from '../utils';
/**
* @class
* NandGate
* @extends CircuitElement
* @param {number} x - x coordinate of nand Gate.
* @param {number} y - y coordinate of nand Gate.
* @param {Scope=} scope - Cirucit on which nand gate is drawn
* @param {string=} dir - direction of nand Gate
* @param {number=} inputLength - number of input nodes
* @param {number=} bitWidth - bit width per node.
* @category modules
*/
import { colors } from "../themer/themer";
export default class NandGate extends CircuitElement {
constructor(
x,
y,
scope = globalScope,
dir = "RIGHT",
inputLength = 2,
bitWidth = 1
) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['NandGate'].push(this);
*/
this.rectangleObject = false;
this.setDimensions(15, 20);
this.inp = [];
this.inputSize = inputLength;
// variable inputLength , node creation
if (inputLength % 2 === 1) {
for (let i = 0; i < inputLength / 2 - 1; i++) {
const a = new Node(-10, -10 * (i + 1), 0, this);
this.inp.push(a);
}
let a = new Node(-10, 0, 0, this);
this.inp.push(a);
for (let i = inputLength / 2 + 1; i < inputLength; i++) {
a = new Node(-10, 10 * (i + 1 - inputLength / 2 - 1), 0, this);
this.inp.push(a);
}
} else {
for (let i = 0; i < inputLength / 2; i++) {
const a = new Node(-10, -10 * (i + 1), 0, this);
this.inp.push(a);
}
for (let i = inputLength / 2; i < inputLength; i++) {
const a = new Node(
-10,
10 * (i + 1 - inputLength / 2),
0,
this
);
this.inp.push(a);
}
}
this.output1 = new Node(30, 0, 1, this);
}
/**
* @memberof NandGate
* fn to create save Json Data of object
* @return {JSON}
*/
// fn to create save Json Data of object
customSave() {
const data = {
constructorParamaters: [
this.direction,
this.inputSize,
this.bitWidth,
],
nodes: {
inp: this.inp.map(findNode),
output1: findNode(this.output1),
},
};
return data;
}
/**
* @memberof NandGate
* resolve output values based on inputData
*/
resolve() {
let result = this.inp[0].value || 0;
if (this.isResolvable() === false) {
return;
}
for (let i = 1; i < this.inputSize; i++)
result &= this.inp[i].value || 0;
result =
((~result >>> 0) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
this.output1.value = result;
simulationArea.simulationQueue.add(this.output1);
}
/**
* @memberof NandGate
* function to draw nand Gate
*/
customDraw() {
var ctx = simulationArea.context;
ctx.beginPath();
ctx.lineWidth = correctWidth(3);
ctx.strokeStyle = colors["stroke"];
ctx.fillStyle = colors["fill"];
const xx = this.x;
const 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 = colors["hover_select"];
ctx.fill();
ctx.stroke();
ctx.beginPath();
drawCircle2(ctx, 25, 0, 5, xx, yy, this.direction);
ctx.stroke();
}
generateVerilog() {
return gateGenerateVerilog.call(this, '&', true);
}
}
/**
* @memberof NandGate
* Help Tip
* @type {string}
* @category modules
*/
NandGate.prototype.tooltipText =
"Nand Gate ToolTip : Combination of AND and NOT gates";
/**
* @memberof NandGate
* @type {boolean}
* @category modules
*/
NandGate.prototype.alwaysResolve = true;
/**
* @memberof NandGate
* function to change input nodes of the gate
* @category modules
*/
NandGate.prototype.changeInputSize = changeInputSize;
/**
* @memberof NandGate
* @type {string}
* @category modules
*/
NandGate.prototype.verilogType = "nand";
NandGate.prototype.helplink =
"https://docs.circuitverse.org/#/gates?id=nand-gate";
NandGate.prototype.objectType = "NandGate";

184
simulator/src/modules/NorGate.js Executable file
View file

@ -0,0 +1,184 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { gateGenerateVerilog } from '../utils';
import {
correctWidth,
bezierCurveTo,
moveTo,
arc2,
drawCircle2,
} from "../canvasApi";
import { changeInputSize } from "../modules";
/**
* @class
* NorGate
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} inputs - number of input nodes
* @param {number=} bitWidth - bit width per node.
* @category modules
*/
import { colors } from "../themer/themer";
export default class NorGate extends CircuitElement {
constructor(
x,
y,
scope = globalScope,
dir = "RIGHT",
inputs = 2,
bitWidth = 1
) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['NorGate'].push(this);
*/
this.rectangleObject = false;
this.setDimensions(15, 20);
this.inp = [];
this.inputSize = inputs;
if (inputs % 2 === 1) {
for (let i = 0; i < inputs / 2 - 1; i++) {
const a = new Node(-10, -10 * (i + 1), 0, this);
this.inp.push(a);
}
let a = new Node(-10, 0, 0, this);
this.inp.push(a);
for (let i = inputs / 2 + 1; i < inputs; i++) {
a = new Node(-10, 10 * (i + 1 - inputs / 2 - 1), 0, this);
this.inp.push(a);
}
} else {
for (let i = 0; i < inputs / 2; i++) {
const a = new Node(-10, -10 * (i + 1), 0, this);
this.inp.push(a);
}
for (let i = inputs / 2; i < inputs; i++) {
const a = new Node(-10, 10 * (i + 1 - inputs / 2), 0, this);
this.inp.push(a);
}
}
this.output1 = new Node(30, 0, 1, this);
}
/**
* @memberof NorGate
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [
this.direction,
this.inputSize,
this.bitWidth,
],
nodes: {
inp: this.inp.map(findNode),
output1: findNode(this.output1),
},
};
return data;
}
/**
* @memberof NorGate
* resolve output values based on inputData
*/
resolve() {
let result = this.inp[0].value || 0;
for (let i = 1; i < this.inputSize; i++)
result |= this.inp[i].value || 0;
result =
((~result >>> 0) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
this.output1.value = result;
simulationArea.simulationQueue.add(this.output1);
}
/**
* @memberof NorGate
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
ctx.strokeStyle = colors["stroke"];
ctx.lineWidth = correctWidth(3);
const xx = this.x;
const yy = this.y;
ctx.beginPath();
ctx.fillStyle = colors["fill"];
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 = colors["hover_select"];
ctx.fill();
ctx.stroke();
ctx.beginPath();
drawCircle2(ctx, 25, 0, 5, xx, yy, this.direction);
ctx.stroke();
// for debugging
}
generateVerilog() {
return gateGenerateVerilog.call(this, '|', true);
}
}
/**
* @memberof NorGate
* Help Tip
* @type {string}
* @category modules
*/
NorGate.prototype.tooltipText =
"Nor Gate ToolTip : Combination of OR gate and NOT gate.";
/**
* @memberof NorGate
* @type {boolean}
* @category modules
*/
NorGate.prototype.alwaysResolve = true;
/**
* @memberof SevenSegDisplay
* function to change input nodes of the element
* @category modules
*/
NorGate.prototype.changeInputSize = changeInputSize;
/**
* @memberof SevenSegDisplay
* @type {string}
* @category modules
*/
NorGate.prototype.verilogType = "nor";
NorGate.prototype.helplink =
"https://docs.circuitverse.org/#/gates?id=nor-gate";
NorGate.prototype.objectType = "NorGate";

108
simulator/src/modules/NotGate.js Executable file
View file

@ -0,0 +1,108 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, lineTo, moveTo, drawCircle2 } from "../canvasApi";
import { changeInputSize } from "../modules";
/**
* @class
* NotGate
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node.
* @category modules
*/
import { colors } from "../themer/themer";
export default class NotGate extends CircuitElement {
constructor(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['NotGate'].push(this);
*/
this.rectangleObject = false;
this.setDimensions(15, 15);
this.inp1 = new Node(-10, 0, 0, this);
this.output1 = new Node(20, 0, 1, this);
}
/**
* @memberof NotGate
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [this.direction, this.bitWidth],
nodes: {
output1: findNode(this.output1),
inp1: findNode(this.inp1),
},
};
return data;
}
/**
* @memberof NotGate
* resolve output values based on inputData
*/
resolve() {
if (this.isResolvable() === false) {
return;
}
this.output1.value =
((~this.inp1.value >>> 0) << (32 - this.bitWidth)) >>>
(32 - this.bitWidth);
simulationArea.simulationQueue.add(this.output1);
}
/**
* @memberof NotGate
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
ctx.strokeStyle = colors["stroke"];
ctx.lineWidth = correctWidth(3);
const xx = this.x;
const yy = this.y;
ctx.beginPath();
ctx.fillStyle = colors["fill"];
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 = colors["hover_select"];
ctx.fill();
ctx.stroke();
ctx.beginPath();
drawCircle2(ctx, 15, 0, 5, xx, yy, this.direction);
ctx.stroke();
}
generateVerilog() {
return "assign " + this.output1.verilogLabel + " = ~" + this.inp1.verilogLabel + ";"
}
}
/**
* @memberof NotGate
* Help Tip
* @type {string}
* @category modules
*/
NotGate.prototype.tooltipText =
"Not Gate Tooltip : Inverts the input digital signal.";
NotGate.prototype.helplink =
"https://docs.circuitverse.org/#/gates?id=not-gate";
NotGate.prototype.objectType = "NotGate";
NotGate.prototype.verilogType = "not";

175
simulator/src/modules/OrGate.js Executable file
View file

@ -0,0 +1,175 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, bezierCurveTo, moveTo, arc2 } from "../canvasApi";
import { changeInputSize } from "../modules";
import { gateGenerateVerilog } from '../utils';
/**
* @class
* OrGate
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} inputs - number of input nodes
* @param {number=} bitWidth - bit width per node.
* @category modules
*/
import { colors } from "../themer/themer";
export default class OrGate extends CircuitElement {
constructor(
x,
y,
scope = globalScope,
dir = "RIGHT",
inputs = 2,
bitWidth = 1
) {
// Calling base class constructor
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['OrGate'].push(this);
*/
this.rectangleObject = false;
this.setDimensions(15, 20);
// Inherit base class prototype
this.inp = [];
this.inputSize = inputs;
if (inputs % 2 === 1) {
for (let i = Math.floor(inputs / 2) - 1; i >= 0; i--) {
const a = new Node(-10, -10 * (i + 1), 0, this);
this.inp.push(a);
}
let a = new Node(-10, 0, 0, this);
this.inp.push(a);
for (let i = 0; i < Math.floor(inputs / 2); i++) {
a = new Node(-10, 10 * (i + 1), 0, this);
this.inp.push(a);
}
} else {
for (let i = inputs / 2 - 1; i >= 0; i--) {
const a = new Node(-10, -10 * (i + 1), 0, this);
this.inp.push(a);
}
for (let i = 0; i < inputs / 2; i++) {
const a = new Node(-10, 10 * (i + 1), 0, this);
this.inp.push(a);
}
}
this.output1 = new Node(20, 0, 1, this);
}
/**
* @memberof OrGate
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [
this.direction,
this.inputSize,
this.bitWidth,
],
nodes: {
inp: this.inp.map(findNode),
output1: findNode(this.output1),
},
};
return data;
}
/**
* @memberof OrGate
* resolve output values based on inputData
*/
resolve() {
let result = this.inp[0].value || 0;
if (this.isResolvable() === false) {
return;
}
for (let i = 1; i < this.inputSize; i++)
result |= this.inp[i].value || 0;
this.output1.value = result >>> 0;
simulationArea.simulationQueue.add(this.output1);
}
/**
* @memberof OrGate
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
ctx.strokeStyle = colors["stroke"];
ctx.lineWidth = correctWidth(3);
const xx = this.x;
const yy = this.y;
ctx.beginPath();
ctx.fillStyle = colors["fill"];
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 = colors["hover_select"];
ctx.fill();
ctx.stroke();
}
generateVerilog(){
return gateGenerateVerilog.call(this, '|');
}
}
/**
* @memberof OrGate
* Help Tip
* @type {string}
* @category modules
*/
OrGate.prototype.tooltipText =
"Or Gate Tooltip : Implements logical disjunction";
/**
* @memberof OrGate
* function to change input nodes of the element
* @category modules
*/
OrGate.prototype.changeInputSize = changeInputSize;
/**
* @memberof SevenSegDisplay
* @type {boolean}
* @category modules
*/
OrGate.prototype.alwaysResolve = true;
/**
* @memberof SevenSegDisplay
* @type {string}
* @category modules
*/
OrGate.prototype.verilogType = "or";
OrGate.prototype.helplink = "https://docs.circuitverse.org/#/gates?id=or-gate";
OrGate.prototype.objectType = "OrGate";

225
simulator/src/modules/Output.js Executable file
View file

@ -0,0 +1,225 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, fillText, rect2, oppositeDirection } from "../canvasApi";
import { getNextPosition } from "../modules";
import { generateId } from "../utils";
import { colors } from "../themer/themer";
function bin2dec(binString) {
return parseInt(binString, 2);
}
function dec2bin(dec, bitWidth = undefined) {
// only for positive nos
var bin = dec.toString(2);
if (bitWidth == undefined) return bin;
return "0".repeat(bitWidth - bin.length) + bin;
}
/**
* @class
* Output
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} inputLength - number of input nodes
* @param {number=} bitWidth - bit width per node.
* @category modules
*/
export default class Output extends CircuitElement {
constructor(
x,
y,
scope = globalScope,
dir = "LEFT",
bitWidth = 1,
layoutProperties
) {
// Calling base class constructor
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['Output'].push(this);
*/
if (layoutProperties) {
this.layoutProperties = layoutProperties;
} else {
this.layoutProperties = {};
this.layoutProperties.x = scope.layout.width;
this.layoutProperties.y = getNextPosition(
scope.layout.width,
scope
);
this.layoutProperties.id = generateId();
}
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);
}
/**
* @memberof Output
* function to generate verilog for output
* @return {string}
*/
generateVerilog() {
return `assign ${this.label} = ${this.inp1.verilogLabel};`;
}
/**
* @memberof Output
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
nodes: {
inp1: findNode(this.inp1),
},
constructorParamaters: [
this.direction,
this.bitWidth,
this.layoutProperties,
],
};
return data;
}
/**
* @memberof Output
* function to change bitwidth of the element
* @param {number} bitWidth - new bitwidth
*/
newBitWidth(bitWidth) {
if (bitWidth < 1) return;
const 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;
}
}
/**
* @memberof Output
* function to draw element
*/
customDraw() {
this.state = this.inp1.value;
var ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = [colors["out_rect"], colors["stroke_alt"]][
+(this.inp1.value === undefined)
];
ctx.fillStyle = colors["fill"];
ctx.lineWidth = correctWidth(3);
const xx = this.x;
const 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 = colors["hover_select"];
}
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.font = "20px Raleway";
ctx.fillStyle = colors["input_text"];
ctx.textAlign = "center";
let bin;
if (this.state === undefined) {
bin = "x".repeat(this.bitWidth);
} else {
bin = dec2bin(this.state, this.bitWidth);
}
for (let k = 0; k < this.bitWidth; k++) {
fillText(
ctx,
bin[k],
xx - 10 * this.bitWidth + 10 + k * 20,
yy + 5
);
}
ctx.fill();
}
/**
* @memberof Output
* function to change direction of Output
* @param {string} dir - new direction
*/
newDirection(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];
}
generateVerilog() {
return "assign " + this.verilogLabel + " = " + this.inp1.verilogLabel + ";"
}
}
/**
* @memberof Output
* Help Tip
* @type {string}
* @category modules
*/
Output.prototype.tooltipText =
"Output ToolTip: Simple output element showing output in binary.";
/**
* @memberof Output
* Help URL
* @type {string}
* @category modules
*/
Output.prototype.helplink = "https://docs.circuitverse.org/#/outputs?id=output";
/**
* @memberof Output
* @type {number}
* @category modules
*/
Output.prototype.propagationDelay = 0;
Output.prototype.objectType = "Output";

146
simulator/src/modules/Power.js Executable file
View file

@ -0,0 +1,146 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, lineTo, moveTo, arc } from "../canvasApi";
import { changeInputSize } from "../modules";
/**
* @class
* Power
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {number=} bitWidth - bit width per node.
* @category modules
*/
import { colors } from "../themer/themer";
export default class Power extends CircuitElement {
constructor(x, y, scope = globalScope, bitWidth = 1) {
super(x, y, scope, "RIGHT", bitWidth);
/* this is done in this.baseSetup() now
this.scope['Power'].push(this);
*/
this.directionFixed = true;
this.rectangleObject = false;
this.setDimensions(10, 10);
this.output1 = new Node(0, 10, 1, this);
}
/**
* @memberof Power
* resolve output values based on inputData
*/
resolve() {
this.output1.value = ~0 >>> (32 - this.bitWidth);
simulationArea.simulationQueue.add(this.output1);
}
/**
* @memberof Power
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
nodes: {
output1: findNode(this.output1),
},
constructorParamaters: [this.bitWidth],
};
return data;
}
/**
* @memberof Power
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
const xx = this.x;
const yy = this.y;
ctx.beginPath();
ctx.strokeStyle = "rgba(0,0,0,1)";
ctx.lineWidth = correctWidth(3);
ctx.fillStyle = colors["fill"];
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 = colors["hover_select"];
ctx.fill();
moveTo(ctx, 0, 0, xx, yy, this.direction);
lineTo(ctx, 0, 10, xx, yy, this.direction);
ctx.stroke();
}
generateVerilog() {
return `assign ${this.output1.verilogLabel} = ~${this.bitWidth}'b0;`;
}
}
/**
* @memberof Power
* Help Tip
* @type {string}
* @category modules
*/
Power.prototype.tooltipText = "Power: All bits are High(1).";
/**
* @memberof Power
* Help URL
* @type {string}
* @category modules
*/
Power.prototype.helplink =
"https://docs.circuitverse.org/#/inputElements?id=power";
/**
* @memberof Power
* @type {number}
* @category modules
*/
Power.prototype.propagationDelay = 0;
function getNextPosition(x = 0, scope = globalScope) {
let possibleY = 20;
const done = {};
for (let i = 0; i < scope.Input.length; i++) {
if (scope.Input[i].layoutProperties.x === x) {
done[scope.Input[i].layoutProperties.y] = 1;
}
}
for (let i = 0; i < scope.Output.length; i++) {
if (scope.Output[i].layoutProperties.x === x) {
done[scope.Output[i].layoutProperties.y] = 1;
}
}
while (done[possibleY] || done[possibleY + 10] || done[possibleY - 10]) {
possibleY += 10;
}
const height = possibleY + 20;
if (height > scope.layout.height) {
const oldHeight = scope.layout.height;
scope.layout.height = height;
for (let i = 0; i < scope.Input.length; i++) {
if (scope.Input[i].layoutProperties.y === oldHeight) {
scope.Input[i].layoutProperties.y = scope.layout.height;
}
}
for (let i = 0; i < scope.Output.length; i++) {
if (scope.Output[i].layoutProperties.y === oldHeight) {
scope.Output[i].layoutProperties.y = scope.layout.height;
}
}
}
return possibleY;
}
Power.prototype.objectType = "Power";

View file

@ -0,0 +1,276 @@
import CircuitElement from "../circuitElement";
import Node, { findNode, dec2bin } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, rect, fillText } from "../canvasApi";
/**
* @class
* PriorityEncoder
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node.
* @category modules
*/
import { colors } from "../themer/themer";
export default class PriorityEncoder extends CircuitElement {
constructor(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['PriorityEncoder'].push(this);
*/
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 (let i = 0; i < this.inputSize; i++) {
const a = new Node(
-10,
+this.yOff * 10 * (i - this.inputSize / 2) + 10,
0,
this,
1
);
this.inp1.push(a);
}
this.output1 = [];
for (let i = 0; i < this.bitWidth; i++) {
const 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
);
}
/**
* @memberof PriorityEncoder
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
nodes: {
inp1: this.inp1.map(findNode),
output1: this.output1.map(findNode),
enable: findNode(this.enable),
},
constructorParamaters: [this.direction, this.bitWidth],
};
return data;
}
/**
* @memberof PriorityEncoder
* function to change bitwidth of the element
* @param {number} bitWidth - new bitwidth
*/
newBitWidth(bitWidth) {
if (bitWidth === undefined || bitWidth < 1 || bitWidth > 32) return;
if (this.bitWidth === bitWidth) return;
this.bitWidth = bitWidth;
const obj = new PriorityEncoder(
this.x,
this.y,
this.scope,
this.direction,
this.bitWidth
);
this.inputSize = 1 << bitWidth;
this.cleanDelete();
simulationArea.lastSelected = obj;
return obj;
}
/**
* @memberof PriorityEncoder
* resolve output values based on inputData
*/
resolve() {
let out = 0;
let temp = 0;
for (let 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 (let i = 0; i < this.bitWidth - 1; i++) {
temp = `0${temp}`;
}
}
if (temp.length !== this.bitWidth) {
for (let i = temp.length; i < this.bitWidth; i++) {
temp = `0${temp}`;
}
}
for (let 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]
);
}
}
/**
* @memberof PriorityEncoder
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = colors["stroke"];
ctx.fillStyle = colors["fill"];
ctx.lineWidth = correctWidth(3);
const xx = this.x;
const 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 = colors["hover_select"];
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.fillStyle = "black";
ctx.textAlign = "center";
for (let i = 0; i < this.inputSize; i++) {
fillText(ctx, String(i), xx, yy + this.inp1[i].y + 2, 10);
}
for (let 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();
}
verilogBaseType() {
return this.verilogName() + this.inp1.length;
}
generateVerilog() {
PriorityEncoder.selSizes.add(this.bitWidth);
return CircuitElement.prototype.generateVerilog.call(this);
}
static moduleVerilog() {
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
static resetVerilog() {
PriorityEncoder.selSizes = new Set
}
}
/**
* @memberof PriorityEncoder
* Help Tip
* @type {string}
* @category modules
*/
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.objectType = "PriorityEncoder";

170
simulator/src/modules/RGBLed.js Executable file
View file

@ -0,0 +1,170 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, lineTo, moveTo, arc, drawCircle2 } from "../canvasApi";
import { changeInputSize } from "../modules";
/**
* @class
* RGBLed
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @category modules
*/
import { colors } from "../themer/themer";
export default class RGBLed extends CircuitElement {
constructor(x, y, scope = globalScope) {
// Calling base class constructor
super(x, y, scope, "UP", 8);
/* this is done in this.baseSetup() now
this.scope['RGBLed'].push(this);
*/
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;
}
/**
* @memberof RGBLed
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
nodes: {
inp1: findNode(this.inp1),
inp2: findNode(this.inp2),
inp3: findNode(this.inp3),
},
};
return data;
}
/**
* @memberof RGBLed
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
const xx = this.x;
const 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();
const a = this.inp1.value;
const b = this.inp2.value;
const 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 = colors["hover_select"];
ctx.fill();
}
// Draws the element in the subcuircuit. Used in layout mode
subcircuitDraw(xOffset = 0, yOffset = 0) {
var ctx = simulationArea.context;
var xx = this.subcircuitMetadata.x + xOffset;
var yy = this.subcircuitMetadata.y + yOffset;
var dimensionSize = 6;
var a = this.inp1.value;
var b = this.inp2.value;
var c = this.inp3.value;
ctx.strokeStyle = "#090a0a";
ctx.fillStyle = ["rgba(" + a + ", " + b + ", " + c + ", 0.8)", "rgba(227, 228, 229, 0.8)"][((a === undefined || b === undefined || c === undefined)) + 0]
ctx.lineWidth = correctWidth(1);
ctx.beginPath();
drawCircle2(ctx, 0, 0, dimensionSize, 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();
}
generateVerilog() {
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});`;
}
}
/**
* @memberof RGBLed
* Help Tip
* @type {string}
* @category modules
*/
RGBLed.prototype.tooltipText =
"RGB Led ToolTip: RGB Led inputs 8 bit values for the colors RED, GREEN and BLUE.";
/**
* @memberof RGBLed
* Help URL
* @type {string}
* @category modules
*/
RGBLed.prototype.helplink =
"https://docs.circuitverse.org/#/outputs?id=rgb-led";
RGBLed.prototype.objectType = "RGBLed";
RGBLed.prototype.canShowInSubcircuit = true;

View file

@ -0,0 +1,327 @@
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
import { correctWidth, rect2, rotate, lineTo, moveTo } from '../canvasApi';
/**
* @class
* RGBLedMatrix
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {number=} rows - number of rows
* @param {number=} cols - number of columns.
* @category modules
*/
export default class RGBLedMatrix extends CircuitElement {
constructor(
x,
y,
scope = globalScope,
{
rows = 8,
columns = 8,
ledSize = 2,
showGrid = true,
colors = [],
} = {}
) {
super(x, y, scope, 'RIGHT', 8);
/* this is done in this.baseSetup() now
this.scope['RGBLedMatrix'].push(this);
*/
this.fixedBitWidth = true;
this.directionFixed = true;
this.rectangleObject = true;
this.alwaysResolve = true;
this.labelDirection = 'UP';
this.leftDimensionX = 0;
this.upDimensionY = 0;
// These pins provide bulk-editing of the colors
this.rowEnableNodes = []; // 1-bit pin for each row, on the left side.
this.columnEnableNodes = []; // 1-bit pin for each column, on the bottom.
this.columnColorNodes = []; // 24-bit pin for each column, on the top.
// These pins provide single-pixel editing; these are on the right side.
this.colorNode = new Node(0, -10, NODE_INPUT, this, 24, 'COLOR');
this.rowNode = new Node(0, 0, NODE_INPUT, this, 1, 'ROW');
this.columnNode = new Node(0, 10, NODE_INPUT, this, 1, 'COLUMN');
this.colors = colors;
this.showGrid = showGrid;
this.changeSize(rows, columns, ledSize, false);
}
toggleGrid() {
this.showGrid = !this.showGrid;
}
changeRows(rows) {
this.changeSize(rows, this.columns, this.ledSize, true);
}
changeColumns(columns) {
this.changeSize(this.rows, columns, this.ledSize, true);
}
changeLedSize(ledSize) {
this.changeSize(this.rows, this.columns, ledSize, true);
}
changeSize(rows, columns, ledSize, move) {
rows = parseInt(rows, 10);
if (isNaN(rows) || rows < 0 || rows > this.maxRows) return;
columns = parseInt(columns, 10);
if (isNaN(columns) || columns < 0 || columns > this.maxColumns) return;
ledSize = parseInt(ledSize, 10);
if (isNaN(ledSize) || ledSize < 0 || ledSize > this.maxLedSize) return;
// The size of an individual LED, in canvas units.
var ledWidth = 10 * ledSize;
var ledHeight = 10 * ledSize;
// The size of the LED matrix, in canvas units.
var gridWidth = ledWidth * columns;
var gridHeight = ledHeight * rows;
// We need to position the element in the 10x10 grid.
// Depending on the size of the leds we need to add different paddings so position correctly.
var padding = ledSize % 2 ? 5 : 10;
// The dimensions of the element, in canvas units.
var halfWidth = gridWidth / 2 + padding;
var halfHeight = gridHeight / 2 + padding;
// Move the element in order to keep the position of the nodes stable so wires don't break.
if (move) {
this.x -= this.leftDimensionX - halfWidth;
this.y -= this.upDimensionY - halfHeight;
}
// Update the dimensions of the element.
this.setDimensions(halfWidth, halfHeight);
// Offset of the nodes in relation to the element's center.
var nodePadding = [10, 20, 20][ledSize - 1];
var nodeOffsetX = nodePadding - halfWidth;
var nodeOffsetY = nodePadding - halfHeight;
// When the led size changes it is better to delete all nodes to break connected the wires.
// Otherwise, wires can end up connected in unexpected ways.
var resetAllNodes = ledSize != this.ledSize;
// Delete unused row-enable nodes, reposition remaining nodes and add new nodes.
this.rowEnableNodes.splice(resetAllNodes ? 0 : rows).forEach(node => node.delete());
this.rowEnableNodes.forEach((node, i) => {
node.x = node.leftx = -halfWidth;
node.y = node.lefty = i * ledHeight + nodeOffsetY;
});
while (this.rowEnableNodes.length < rows) {
this.rowEnableNodes.push(new Node(-halfWidth, this.rowEnableNodes.length * ledHeight + nodeOffsetY, NODE_INPUT, this, 1, 'R' + this.rowEnableNodes.length));
}
// Delete unused column-enable nodes, reposition remaining nodes and add new nodes.
this.columnEnableNodes.splice(resetAllNodes ? 0 : columns).forEach(node => node.delete());
this.columnEnableNodes.forEach((node, i) => {
node.x = node.leftx = i * ledWidth + nodeOffsetX;
node.y = node.lefty = halfHeight;
});
while (this.columnEnableNodes.length < columns) {
this.columnEnableNodes.push(new Node(this.columnEnableNodes.length * ledWidth + nodeOffsetX, halfHeight, NODE_INPUT, this, 1, 'C' + this.columnEnableNodes.length));
}
// Delete unused column color nodes, reposition remaining nodes and add new nodes.
this.columnColorNodes.splice(resetAllNodes ? 0 : columns).forEach(node => node.delete());
this.columnColorNodes.forEach((node, i) => {
node.x = node.leftx = i * ledWidth + nodeOffsetX;
node.y = node.lefty = -halfHeight;
});
while (this.columnColorNodes.length < columns) {
this.columnColorNodes.push(new Node(this.columnColorNodes.length * ledWidth + nodeOffsetX, -halfHeight, NODE_INPUT, this, 24, 'CLR' + this.columnColorNodes.length));
}
// Delete unused color storage and add storage for new rows.
this.colors.splice(rows);
this.colors.forEach(c => c.splice(columns));
while (this.colors.length < rows) {
this.colors.push([]);
}
// Reposition the single-pixel nodes
this.rowNode.bitWidth = Math.ceil(Math.log2(rows));
this.rowNode.label = 'ROW (' + this.rowNode.bitWidth + ' bits)';
this.columnNode.bitWidth = Math.ceil(Math.log2(columns));
this.columnNode.label = 'COLUMN (' + this.columnNode.bitWidth + ' bits)';
var singlePixelNodePadding = rows > 1 ? nodeOffsetY : nodeOffsetY - 10;
var singlePixelNodeDistance = (rows <= 2) ? 10 : ledHeight;
[this.colorNode, this.rowNode, this.columnNode].forEach((node, i) => {
node.x = node.leftx = halfWidth;
node.y = node.lefty = i * singlePixelNodeDistance + singlePixelNodePadding;
});
// Store the new values
this.rows = rows;
this.columns = columns;
this.ledSize = ledSize;
return this;
}
customSave() {
// Save the size of the LED matrix.
// Unlike a read LED matrix, we also persist the color of each pixel.
// This allows circuit preview to show the colors at the time the simulation was saved.
return {
constructorParamaters: [{
rows: this.rows,
columns: this.columns,
ledSize: this.ledSize,
showGrid: this.showGrid,
colors: this.colors
}],
nodes: {
rowEnableNodes: this.rowEnableNodes.map(findNode),
columnEnableNodes: this.columnEnableNodes.map(findNode),
columnColorNodes: this.columnColorNodes.map(findNode),
colorNode: findNode(this.colorNode),
rowNode: findNode(this.rowNode),
columnNode: findNode(this.columnNode),
},
}
}
resolve() {
var colorValue = this.colorNode.value;
var hasColorValue = colorValue != undefined;
var rows = this.rows;
var columns = this.columns;
var rowEnableNodes = this.rowEnableNodes;
var columnEnableNodes = this.columnEnableNodes;
var columnColorNodes = this.columnColorNodes;
var colors = this.colors;
for (var row = 0; row < rows; row++) {
if (rowEnableNodes[row].value === 1) {
for (var column = 0; column < columns; column++) {
// Method 1: set pixel by rowEnable + columnColor pins
var columnColor = columnColorNodes[column].value;
if (columnColor !== undefined) {
colors[row][column] = columnColor;
}
// Method 2: set pixel by rowEnable + columnEnable + color pins
if (hasColorValue && columnEnableNodes[column].value === 1) {
colors[row][column] = colorValue;
}
}
}
}
// Method 3: set pixel by write + pixel index + color pins.
var hasRowNodeValue = this.rowNode.value != undefined || rows == 1;
var hasColumnNodeValue = this.columnNode.value != undefined || columns == 1;
if (hasColorValue && hasRowNodeValue && hasColumnNodeValue) {
var rowNodeValue = this.rowNode.value || 0;
var columnNodeValue = this.columnNode.value || 0;
if (rowNodeValue < rows && columnNodeValue < columns) {
colors[rowNodeValue][columnNodeValue] = colorValue;
}
}
}
customDraw() {
var ctx = simulationArea.context;
var rows = this.rows;
var columns = this.columns;
var colors = this.colors;
var xx = this.x;
var yy = this.y;
var dir = this.direction;
var ledWidth = 10 * this.ledSize;
var ledHeight = 10 * this.ledSize;
var top = this.rowEnableNodes[0].y - ledHeight / 2;
var left = this.columnColorNodes[0].x - ledWidth / 2;
var width = this.columns * ledWidth;
var height = this.rows * ledHeight;
var bottom = top + height;
var right = left + width;
var [w, h] = rotate(ledWidth * globalScope.scale, ledHeight * globalScope.scale, dir);
var xoffset = Math.round(globalScope.ox + xx * globalScope.scale);
var yoffset = Math.round(globalScope.oy + yy * globalScope.scale);
for (var row = 0; row < rows; row++) {
for (var column = 0; column < columns; column++) {
var color = colors[row][column] || 0;
ctx.beginPath();
ctx.fillStyle = 'rgb(' + ((color & 0xFF0000) >> 16) + ',' + ((color & 0xFF00) >> 8) + ',' + (color & 0xFF) + ')';
let x1,y1;
[x1, y1] = rotate(left + column * ledWidth, top + row * ledHeight, dir);
x1 = x1 * globalScope.scale;
y1 = y1 * globalScope.scale;
ctx.rect(xoffset + x1, yoffset + y1, w, h);
ctx.fill();
}
}
if (this.showGrid) {
ctx.beginPath();
ctx.strokeStyle = '#323232';
ctx.lineWidth = correctWidth(1);
rect2(ctx, left, top, width, height, xx, yy, dir);
for (var x = left + ledWidth; x < right; x += ledWidth) {
moveTo(ctx, x, top, xx, yy, dir);
lineTo(ctx, x, bottom, xx, yy, dir);
}
for (var y = top + ledHeight; y < bottom; y += ledHeight) {
moveTo(ctx, left, y, xx, yy, dir);
lineTo(ctx, right, y, xx, yy, dir);
}
ctx.stroke();
}
}
}
RGBLedMatrix.prototype.tooltipText = 'RGB Led Matrix';
// Limit the size of the matrix otherwise the simulation starts to lag.
RGBLedMatrix.prototype.maxRows = 128;
RGBLedMatrix.prototype.maxColumns = 128;
// Let the user choose between 3 sizes of LEDs: small, medium and large.
RGBLedMatrix.prototype.maxLedSize = 3;
RGBLedMatrix.prototype.mutableProperties = {
rows: {
name: 'Rows',
type: 'number',
max: RGBLedMatrix.prototype.maxRows,
min: 1,
func: 'changeRows',
},
columns: {
name: 'Columns',
type: 'number',
max: RGBLedMatrix.prototype.maxColumns,
min: 1,
func: 'changeColumns',
},
ledSize: {
name: 'LED Size',
type: 'number',
max: RGBLedMatrix.prototype.maxLedSize,
min: 1,
func: 'changeLedSize',
},
showGrid: {
name: 'Toggle Grid',
type: 'button',
max: RGBLedMatrix.prototype.maxLedSize,
min: 1,
func: 'toggleGrid',
},
};RGBLedMatrix.prototype.objectType = 'RGBLedMatrix';

View file

@ -0,0 +1,160 @@
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
import { fillText, lineTo, moveTo, correctWidth, rect2 } from '../canvasApi';
/**
* @class
* Random
* Random is used to generate random value.
* It has 2 input node:
* clock and max random output value
* @extends CircuitElement
* @param {number} x - x coord of element
* @param {number} y - y coord of element
* @param {Scope=} scope - the ciruit in which we want the Element
* @param {string=} dir - direcion in which element has to drawn
* @category modules
*/
import { colors } from '../themer/themer';
export default class Random extends CircuitElement {
constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['Random'].push(this);
*/
this.directionFixed = true;
this.setDimensions(20, 20);
this.rectangleObject = true;
this.currentRandomNo = 0;
this.clockInp = new Node(-20, +10, 0, this, 1, 'Clock');
this.maxValue = new Node(-20, -10, 0, this, this.bitWidth, 'MaxValue');
this.output = new Node(20, -10, 1, this, this.bitWidth, 'RandomValue');
this.prevClockState = 0;
this.wasClicked = false;
}
/**
* @memberof Random
* return true if clock is connected and if maxValue is set or unconnected.
*/
isResolvable() {
if (this.clockInp.value != undefined && (this.maxValue.value != undefined || this.maxValue.connections.length == 0)) { return true; }
return false;
}
newBitWidth(bitWidth) {
this.bitWidth = bitWidth;
this.maxValue.bitWidth = bitWidth;
this.output.bitWidth = bitWidth;
}
/**
* @memberof Random
* Edge triggered when the clock state changes a
* Random number is generated less then the maxValue.
*/
resolve() {
var maxValue = this.maxValue.connections.length ? this.maxValue.value + 1 : (2 << (this.bitWidth - 1));
if (this.clockInp.value != undefined) {
if (this.clockInp.value != this.prevClockState) {
if (this.clockInp.value == 1) {
this.currentRandomNo = Math.floor(Math.random() * maxValue);
}
this.prevClockState = this.clockInp.value;
}
}
if (this.output.value != this.currentRandomNo) {
this.output.value = this.currentRandomNo;
simulationArea.simulationQueue.add(this.output);
}
}
customSave() {
var data = {
nodes: {
clockInp: findNode(this.clockInp),
maxValue: findNode(this.maxValue),
output: findNode(this.output),
},
constructorParamaters: [this.direction, this.bitWidth],
};
return data;
}
customDraw() {
var ctx = simulationArea.context;
//
ctx.fillStyle = colors['fill'];
ctx.strokeStyle = colors['stroke'];
ctx.beginPath();
var xx = this.x;
var yy = this.y;
ctx.font = '20px Raleway';
ctx.fillStyle = colors['input_text'];
ctx.textAlign = 'center';
fillText(ctx, this.currentRandomNo.toString(10), this.x, this.y + 5);
ctx.fill();
ctx.beginPath();
moveTo(ctx, -20, 5, xx, yy, this.direction);
lineTo(ctx, -15, 10, xx, yy, this.direction);
lineTo(ctx, -20, 15, xx, yy, this.direction);
ctx.stroke();
}
// Draws the element in the subcircuit. Used in layout mode
subcircuitDraw(xOffset = 0, yOffset = 0) {
var ctx = simulationArea.context;
var xx = this.subcircuitMetadata.x + xOffset;
var yy = this.subcircuitMetadata.y + yOffset;
ctx.beginPath();
ctx.font = "20px Raleway";
ctx.fillStyle = "green";
ctx.textAlign = "center";
fillText(ctx, this.currentRandomNo.toString(16), xx + 10, yy + 17);
ctx.fill();
ctx.beginPath();
ctx.lineWidth = correctWidth(1);
rect2(ctx, 0, 0, 20, 20, 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.6)";
ctx.fill();
}
}
static moduleVerilog() {
return `
module Random(val, clk, max);
parameter WIDTH = 1;
output reg [WIDTH-1:0] val;
input clk;
input [WIDTH-1:0] max;
always @ (posedge clk)
if (^max === 1'bX)
val = $urandom_range(0, {WIDTH{1'b1}});
else
val = $urandom_range(0, max);
endmodule
`;
}
}
Random.prototype.tooltipText = 'Random ToolTip : Random Selected.';
Random.prototype.helplink = 'https://docs.circuitverse.org/#/inputElements?id=random';
Random.prototype.objectType = 'Random';
Random.prototype.canShowInSubcircuit = true
Random.prototype.layoutProperties = {
rightDimensionX : 20,
leftDimensionX : 0,
upDimensionY : 0,
downDimensionY: 20
}

View file

@ -0,0 +1,146 @@
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
import { correctWidth, rect } from '../canvasApi';
/**
* @class
* Rectangle
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {number=} rows - number of rows
* @param {number=} cols - number of columns.
* @category modules
*/
export default class Rectangle extends CircuitElement {
constructor(x, y, scope = globalScope, rows = 15, cols = 20) {
super(x, y, scope, 'RIGHT', 1);
/* this is done in this.baseSetup() now
this.scope['Rectangle'].push(this);
*/
this.directionFixed = true;
this.fixedBitWidth = true;
this.rectangleObject = false;
this.cols = cols || parseInt(prompt('Enter cols:'), 10);
this.rows = rows || parseInt(prompt('Enter rows:'), 10);
this.setSize();
}
/**
* @memberof Rectangle
* @param {number} size - new size of rows
*/
changeRowSize(size) {
if (size === undefined || size < 5 || size > 1000) return;
if (this.rows === size) return;
this.rows = parseInt(size, 10);
this.setSize();
return this;
}
/**
* @memberof Rectangle
* @param {number} size - new size of columns
*/
changeColSize(size) {
if (size === undefined || size < 5 || size > 1000) return;
if (this.cols === size) return;
this.cols = parseInt(size, 10);
this.setSize();
return this;
}
/**
* @memberof Rectangle
* listener function to change direction of rectangle
* @param {string} dir - new direction
*/
keyDown3(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); }
}
/**
* @memberof Rectangle
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [this.rows, this.cols],
};
return data;
}
/**
* @memberof Rectangle
* function to draw element
*/
customDraw() {
var 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);
const xx = this.x;
const 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([]);
}
/**
* @memberof Rectangle
* function to reset or (internally) set size
*/
setSize() {
this.elementWidth = this.cols * 10;
this.elementHeight = this.rows * 10;
this.upDimensionY = 0;
this.leftDimensionX = 0;
this.rightDimensionX = this.elementWidth;
this.downDimensionY = this.elementHeight;
}
}
/**
* @memberof Rectangle
* Help Tip
* @type {string}
* @category modules
*/
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.propagationDelayFixed = true;
/**
* @memberof Rectangle
* Mutable properties of the element
* @type {JSON}
* @category modules
*/
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.objectType = 'Rectangle';

View file

@ -0,0 +1,176 @@
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
import {
correctWidth, lineTo, moveTo, rect, rect2
} from '../canvasApi';
/**
* @class
* SevenSegDisplay
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @category modules
*/
export default class SevenSegDisplay extends CircuitElement {
constructor(x, y, scope = globalScope) {
super(x, y, scope, 'RIGHT', 1);
/* this is done in this.baseSetup() now
this.scope['SevenSegDisplay'].push(this);
*/
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';
}
/**
* @memberof SevenSegDisplay
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const 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),
dot: findNode(this.dot),
},
};
return data;
}
/**
* @memberof SevenSegDisplay
* helper function to create save Json Data of object
*/
customDrawSegment(x1, y1, x2, y2, color) {
if (color === undefined) color = 'lightgrey';
var ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = color;
ctx.lineWidth = correctWidth(5);
const xx = this.x;
const yy = this.y;
moveTo(ctx, x1, y1, xx, yy, this.direction);
lineTo(ctx, x2, y2, xx, yy, this.direction);
ctx.closePath();
ctx.stroke();
}
/**
* @memberof SevenSegDisplay
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
const xx = this.x;
const 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();
const dotColor = ['lightgrey', 'red'][this.dot.value] || 'lightgrey';
ctx.strokeStyle = dotColor;
rect(ctx, xx + 22, yy + 42, 2, 2);
ctx.stroke();
}
subcircuitDrawSegment(x1, y1, x2, y2, color, xxSegment, yySegment) {
if (color == undefined) color = "lightgrey";
var ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = color;
ctx.lineWidth = correctWidth(3);
var xx = xxSegment;
var yy = yySegment;
moveTo(ctx, x1, y1, xx, yy, this.direction);
lineTo(ctx, x2, y2, xx, yy, this.direction);
ctx.closePath();
ctx.stroke();
}
// Draws the element in the subcuircuit. Used in layout mode
subcircuitDraw(xOffset = 0, yOffset = 0) {
var ctx = simulationArea.context;
var xx = this.subcircuitMetadata.x + xOffset;
var yy = this.subcircuitMetadata.y + yOffset;
this.subcircuitDrawSegment(10, -20, 10, -38, ["lightgrey", "red"][this.b.value], xx, yy);
this.subcircuitDrawSegment(10, -17, 10, 1, ["lightgrey", "red"][this.c.value], xx, yy);
this.subcircuitDrawSegment(-10, -20, -10, -38, ["lightgrey", "red"][this.f.value], xx, yy);
this.subcircuitDrawSegment(-10, -17, -10, 1, ["lightgrey", "red"][this.e.value], xx, yy);
this.subcircuitDrawSegment(-8, -38, 8, -38, ["lightgrey", "red"][this.a.value], xx, yy);
this.subcircuitDrawSegment(-8, -18, 8, -18, ["lightgrey", "red"][this.g.value], xx, yy);
this.subcircuitDrawSegment(-8, 1, 8, 1, ["lightgrey", "red"][this.d.value], xx, yy);
ctx.beginPath();
var dotColor = ["lightgrey", "red"][this.dot.value] || "lightgrey"
ctx.strokeStyle = dotColor;
rect(ctx, xx + 13, yy + 5, 1, 1);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = "black";
ctx.lineWidth = correctWidth(1);
rect2(ctx, -15, -42, 33, 51, 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.6)";
ctx.fill();
}
}
generateVerilog(){
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});`;
}
}
/**
* @memberof SevenSegDisplay
* Help Tip
* @type {string}
* @category modules
*/
SevenSegDisplay.prototype.tooltipText = 'Seven Display ToolTip: Consists of 7+1 single bit inputs.';
/**
* @memberof SevenSegDisplay
* Help URL
* @type {string}
* @category modules
*/
SevenSegDisplay.prototype.helplink = 'https://docs.circuitverse.org/#/outputs?id=seven-segment-display';
SevenSegDisplay.prototype.objectType = 'SevenSegDisplay';
SevenSegDisplay.prototype.canShowInSubcircuit = true;
SevenSegDisplay.prototype.layoutProperties = {
rightDimensionX : 20,
leftDimensionX : 15,
upDimensionY : 42,
downDimensionY: 10
}

View file

@ -0,0 +1,217 @@
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
import {
correctWidth, lineTo, moveTo, rect, rect2
} from '../canvasApi';
import { changeInputSize } from '../modules';
/**
* @class
* SixteenSegDisplay
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @category modules
*/
export default class SixteenSegDisplay extends CircuitElement {
constructor(x, y, scope = globalScope) {
super(x, y, scope, 'RIGHT', 16);
/* this is done in this.baseSetup() now
this.scope['SixteenSegDisplay'].push(this);
*/
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';
}
/**
* @memberof SixteenSegDisplay
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
nodes: {
input1: findNode(this.input1),
dot: findNode(this.dot),
},
};
return data;
}
/**
* @memberof SixteenSegDisplay
* function to draw element
*/
customDrawSegment(x1, y1, x2, y2, color) {
if (color === undefined) color = 'lightgrey';
var ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = color;
ctx.lineWidth = correctWidth(4);
const xx = this.x;
const yy = this.y;
moveTo(ctx, x1, y1, xx, yy, this.direction);
lineTo(ctx, x2, y2, xx, yy, this.direction);
ctx.closePath();
ctx.stroke();
}
/**
* @memberof SixteenSegDisplay
* function to draw element
*/
customDrawSegmentSlant(x1, y1, x2, y2, color) {
if (color === undefined) color = 'lightgrey';
var ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = color;
ctx.lineWidth = correctWidth(3);
const xx = this.x;
const yy = this.y;
moveTo(ctx, x1, y1, xx, yy, this.direction);
lineTo(ctx, x2, y2, xx, yy, this.direction);
ctx.closePath();
ctx.stroke();
}
/**
* @memberof SixteenSegDisplay
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
const xx = this.x;
const yy = this.y;
const color = ['lightgrey', 'red'];
const { value } = this.input1;
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();
const dotColor = ['lightgrey', 'red'][this.dot.value] || 'lightgrey';
ctx.strokeStyle = dotColor;
rect(ctx, xx + 22, yy + 42, 2, 2);
ctx.stroke();
}
subcircuitDrawSegment(x1, y1, x2, y2, color, xxSegment, yySegment) {
if (color == undefined) color = "lightgrey";
var ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = color;
ctx.lineWidth = correctWidth(3);
var xx = xxSegment;
var yy = yySegment;
moveTo(ctx, x1, y1, xx, yy, this.direction);
lineTo(ctx, x2, y2, xx, yy, this.direction);
ctx.closePath();
ctx.stroke();
}
subcircuitDrawSegmentSlant(x1, y1, x2, y2, color, xxSegment, yySegment) {
if (color == undefined) color = "lightgrey";
var ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = color;
ctx.lineWidth = correctWidth(2);
var xx = xxSegment;
var yy = yySegment;
moveTo(ctx, x1, y1, xx, yy, this.direction);
lineTo(ctx, x2, y2, xx, yy, this.direction);
ctx.closePath();
ctx.stroke();
}
// Draws the element in the subcircuit. Used in layout mode
subcircuitDraw(xOffset = 0, yOffset = 0) {
var ctx = simulationArea.context;
var xx = this.subcircuitMetadata.x + xOffset;
var yy = this.subcircuitMetadata.y + yOffset;
var color = ["lightgrey", "red"];
var value = this.input1.value;
this.subcircuitDrawSegment(-10, -38, 0, -38, ["lightgrey", "red"][(value >> 15) & 1], xx, yy); //a1
this.subcircuitDrawSegment(10, -38, 0, -38, ["lightgrey", "red"][(value >> 14) & 1], xx, yy); //a2
this.subcircuitDrawSegment(11.5, -19, 11.5, -36, ["lightgrey", "red"][(value >> 13) & 1], xx, yy); //b
this.subcircuitDrawSegment(11.5, 2, 11.5, -15, ["lightgrey", "red"][(value >> 12) & 1], xx, yy); //c
this.subcircuitDrawSegment(-10, 4, 0, 4, ["lightgrey", "red"][(value >> 11) & 1], xx, yy); //d1
this.subcircuitDrawSegment(10, 4, 0, 4, ["lightgrey", "red"][(value >> 10) & 1], xx, yy); //d2
this.subcircuitDrawSegment(-11.5, 2, -11.5, -15, ["lightgrey", "red"][(value >> 9) & 1], xx, yy); //e
this.subcircuitDrawSegment(-11.5, -36, -11.5, -19, ["lightgrey", "red"][(value >> 8) & 1], xx, yy); //f
this.subcircuitDrawSegment(-10, -17, 0, -17, ["lightgrey", "red"][(value >> 7) & 1], xx, yy); //g1
this.subcircuitDrawSegment(10, -17, 0, -17, ["lightgrey", "red"][(value >> 6) & 1], xx, yy); //g2
this.subcircuitDrawSegmentSlant(0, -17, -9, -36, ["lightgrey", "red"][(value >> 5) & 1], xx, yy); //h
this.subcircuitDrawSegment(0, -36, 0, -19, ["lightgrey", "red"][(value >> 4) & 1], xx, yy); //i
this.subcircuitDrawSegmentSlant(0, -17, 9, -36, ["lightgrey", "red"][(value >> 3) & 1], xx, yy); //j
this.subcircuitDrawSegmentSlant(0, -17, 9, 0, ["lightgrey", "red"][(value >> 2) & 1], xx, yy); //k
this.subcircuitDrawSegment(0, -17, 0, 2, ["lightgrey", "red"][(value >> 1) & 1], xx, yy); //l
this.subcircuitDrawSegmentSlant(0, -17, -9, 0, ["lightgrey", "red"][(value >> 0) & 1], xx, yy); //m
ctx.beginPath();
var dotColor = ["lightgrey", "red"][this.dot.value] || "lightgrey";
ctx.strokeStyle = dotColor;
rect(ctx, xx + 13, yy + 5, 1, 1);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = "black";
ctx.lineWidth = correctWidth(1);
rect2(ctx, -15, -42, 33, 51, 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.6)";
ctx.fill();
}
}
generateVerilog() {
return `
always @ (*)
$display("SixteenSegDisplay:{${this.input1.verilogLabel},${this.dot.verilogLabel}} = {%16b,%1b}", ${this.input1.verilogLabel}, ${this.dot.verilogLabel});`;
}
}
/**
* @memberof SixteenSegDisplay
* Help Tip
* @type {string}
* @category modules
*/
SixteenSegDisplay.prototype.tooltipText = 'Sixteen Display ToolTip: Consists of 16+1 bit inputs.';
/**
* @memberof SixteenSegDisplay
* Help URL
* @type {string}
* @category modules
*/
SixteenSegDisplay.prototype.helplink = 'https://docs.circuitverse.org/#/outputs?id=sixteen-segment-display';
SixteenSegDisplay.prototype.objectType = 'SixteenSegDisplay';
SixteenSegDisplay.prototype.canShowInSubcircuit = true;
SixteenSegDisplay.prototype.layoutProperties = {
rightDimensionX : 20,
leftDimensionX : 15,
upDimensionY : 42,
downDimensionY: 10
}

287
simulator/src/modules/Splitter.js Executable file
View file

@ -0,0 +1,287 @@
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
import {
correctWidth, lineTo, moveTo, fillText2,
} from '../canvasApi';
import { colors } from '../themer/themer';
function extractBits(num, start, end) {
return (num << (32 - end)) >>> (32 - (end - start + 1));
}
/**
* @class
* Splitter
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node.
* @param {number=} bitWidthSplit - number of input nodes
* @category modules
*/
export default class Splitter extends CircuitElement {
constructor(
x,
y,
scope = globalScope,
dir = 'RIGHT',
bitWidth = undefined,
bitWidthSplit = undefined,
) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['Splitter'].push(this);
*/
this.rectangleObject = false;
this.bitWidthSplit = bitWidthSplit || prompt('Enter bitWidth Split').split(' ').filter((lambda) => lambda !== '').map((lambda) => parseInt(lambda, 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 (let 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;
}
/**
* @memberof Splitter
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [this.direction, this.bitWidth, this.bitWidthSplit],
nodes: {
outputs: this.outputs.map(findNode),
inp1: findNode(this.inp1),
},
};
return data;
}
/**
* @memberof Splitter
* fn to remove proporgation delay.
* @return {JSON}
*/
removePropagation() {
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;
}
/**
* @memberof Splitter
* Checks if the element is resolvable
* @return {boolean}
*/
isResolvable() {
let resolvable = false;
if (this.inp1.value !== this.prevInpValue) {
if (this.inp1.value !== undefined) return true;
return false;
}
let i;
for (i = 0; i < this.splitCount; i++) { if (this.outputs[i].value === undefined) break; }
if (i === this.splitCount) resolvable = true;
return resolvable;
}
/**
* @memberof Splitter
* resolve output values based on inputData
*/
resolve() {
if (this.isResolvable() === false) {
return;
}
if (this.inp1.value !== undefined && this.inp1.value !== this.prevInpValue) {
let bitCount = 1;
for (let i = 0; i < this.splitCount; i++) {
const 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 {
let n = 0;
for (let 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;
}
/**
* @memberof Splitter
* fn to reset values of splitter
*/
reset() {
this.prevInpValue = undefined;
}
/**
* @memberof Splitter
* fn to process verilog of the element
* @return {JSON}
*/
processVerilog() {
// console.log(this.inp1.verilogLabel +":"+ this.outputs[0].verilogLabel);
if (this.inp1.verilogLabel !== '' && this.outputs[0].verilogLabel === '') {
let bitCount = 0;
for (let i = 0; i < this.splitCount; i++) {
// let bitSplitValue = extractBits(this.inp1.value, bitCount, bitCount + this.bitWidthSplit[i] - 1);
if (this.bitWidthSplit[i] > 1) { const label = `${this.inp1.verilogLabel}[ ${bitCount + this.bitWidthSplit[i] - 1}:${bitCount}]`; } else { const label = `${this.inp1.verilogLabel}[${bitCount}]`; }
if (this.outputs[i].verilogLabel !== label) {
this.outputs[i].verilogLabel = label;
this.scope.stack.push(this.outputs[i]);
}
bitCount += this.bitWidthSplit[i];
}
} else if (this.inp1.verilogLabel === '' && this.outputs[0].verilogLabel !== '') {
const label = `{${this.outputs.map((x) => x.verilogLabel).join(',')}}`;
// console.log("HIT",label)
if (this.inp1.verilogLabel !== label) {
this.inp1.verilogLabel = label;
this.scope.stack.push(this.inp1);
}
}
}
/**
* @memberof Splitter
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
//
ctx.strokeStyle = [colors['splitter'], 'brown'][((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || simulationArea.multipleObjectSelections.contains(this)) + 0];
ctx.lineWidth = correctWidth(3);
const xx = this.x;
const yy = this.y;
ctx.beginPath();
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);
let bitCount = 0;
for (let 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 = colors['text'];
for (let i = this.splitCount - 1; i >= 0; i--) {
var splitLabel;
if (this.bitWidthSplit[this.splitCount - i - 1] == 1)
splitLabel = `${bitCount}`;
else
splitLabel = `${bitCount}:${bitCount + this.bitWidthSplit[this.splitCount - i - 1] - 1}`;
fillText2(ctx, splitLabel, 16, -20 * i + this.yOffset + 10, xx, yy, this.direction);
bitCount += this.bitWidthSplit[this.splitCount - i - 1];
}
ctx.fill();
}
processVerilog() {
// 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
generateVerilog() {
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;
}
}
/**
* @memberof Splitter
* Help Tip
* @type {string}
* @category modules
*/
Splitter.prototype.tooltipText = 'Splitter ToolTip: Split multiBit Input into smaller bitwidths or vice versa.';
/**
* @memberof Splitter
* Help URL
* @type {string}
* @category modules
*/
Splitter.prototype.helplink = 'https://docs.circuitverse.org/#/splitter';
Splitter.prototype.objectType = 'Splitter';

View file

@ -0,0 +1,189 @@
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
import {
correctWidth, lineTo, moveTo, rect2,
} from '../canvasApi';
/**
* @class
* SquareRGBLed
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} pinLength - pins per node.
* @category modules
*/
export default class SquareRGBLed extends CircuitElement {
constructor(x, y, scope = globalScope, dir = 'UP', pinLength = 1) {
super(x, y, scope, dir, 8);
/* this is done in this.baseSetup() now
this.scope['SquareRGBLed'].push(this);
*/
this.rectangleObject = false;
this.setDimensions(15, 15);
this.pinLength = pinLength === undefined ? 1 : pinLength;
const 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;
// eslint-disable-next-line no-shadow
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.
const diff = 10 * (pinLength - this.pinLength);
// eslint-disable-next-line no-nested-ternary
const diffX = this.direction === 'LEFT' ? -diff : this.direction === 'RIGHT' ? diff : 0;
// eslint-disable-next-line no-nested-ternary
const diffY = this.direction === 'UP' ? -diff : this.direction === 'DOWN' ? diff : 0;
// Build a new LED with the new values; preserve label properties too.
const obj = new SquareRGBLed(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',
},
};
}
/**
* @memberof SquareRGBLed
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [this.direction, this.pinLength],
nodes: {
inp1: findNode(this.inp1),
inp2: findNode(this.inp2),
inp3: findNode(this.inp3),
},
};
return data;
}
/**
* @memberof SquareRGBLed
* function to draw element
*/
customDraw() {
const ctx = simulationArea.context;
const xx = this.x;
const yy = this.y;
const r = this.inp1.value;
const g = this.inp2.value;
const b = this.inp3.value;
const colors = ['rgb(174,20,20)', 'rgb(40,174,40)', 'rgb(0,100,255)'];
for (let i = 0; i < 3; i++) {
const x = -10 - 10 * this.pinLength;
const 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();
}
// Draws the element in the subcuircuit. Used in layout mode
subcircuitDraw(xOffset = 0, yOffset = 0) {
var ctx = simulationArea.context;
var xx = this.subcircuitMetadata.x + xOffset;
var yy = this.subcircuitMetadata.y + yOffset;
var r = this.inp1.value;
var g = this.inp2.value;
var b = this.inp3.value;
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, 0, 0, 15, 15, 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();
}
generateVerilog() {
return this.generateVerilog.call(this);
}
}
/**
* @memberof SquareRGBLed
* Help Tip
* @type {string}
* @category modules
*/
SquareRGBLed.prototype.tooltipText = 'Square RGB Led ToolTip: RGB Led inputs 8 bit values for the colors RED, GREEN and BLUE.';
/**
* @memberof SquareRGBLed
* Help URL
* @type {string}
* @category modules
*/
SquareRGBLed.prototype.helplink = 'https://docs.circuitverse.org/#/outputs?id=square-rgb-led';
SquareRGBLed.prototype.objectType = 'SquareRGBLed';
SquareRGBLed.prototype.canShowInSubcircuit = true;
SquareRGBLed.prototype.layoutProperties = {
rightDimensionX : 15,
leftDimensionX : 0,
upDimensionY : 15,
downDimensionY: 0
}

View file

@ -0,0 +1,99 @@
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
import { fillText } from '../canvasApi';
import { changeInputSize } from '../modules';
/**
* @class
* Stepper
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bitwidth of element
* @category modules
*/
import { colors } from '../themer/themer';
export default class Stepper extends CircuitElement {
constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 8) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['Stepper'].push(this);
*/
this.setDimensions(20, 20);
this.output1 = new Node(20, 0, 1, this, bitWidth);
this.state = 0;
}
/**
* @memberof Stepper
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
var data = {
constructorParamaters: [this.direction, this.bitWidth],
nodes: {
output1: findNode(this.output1),
},
values: {
state: this.state,
},
};
return data;
}
/**
* @memberof Stepper
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
ctx.beginPath();
ctx.font = '20px Raleway';
ctx.fillStyle = colors['input_text'];
ctx.textAlign = 'center';
fillText(ctx, this.state.toString(16), this.x, this.y + 5);
ctx.fill();
}
/**
* @memberof Stepper
* resolve output values based on inputData
*/
resolve() {
this.state = Math.min(this.state, (1 << this.bitWidth) - 1);
this.output1.value = this.state;
simulationArea.simulationQueue.add(this.output1);
}
/**
* Listener function for increasing value of state
* @memberof Stepper
* @param {string} key - the key pressed
*/
keyDown2(key) {
if (this.state < (1 << this.bitWidth) && (key === '+' || key === '=')) this.state++;
if (this.state > 0 && (key === '_' || key === '-')) this.state--;
}
}
/**
* @memberof Stepper
* Help Tip
* @type {string}
* @category modules
*/
Stepper.prototype.tooltipText = 'Stepper ToolTip: Increase/Decrease value by selecting the stepper and using +/- keys.';
/**
* @memberof Stepper
* Help URL
* @type {string}
* @category modules
*/
Stepper.prototype.helplink = 'https://docs.circuitverse.org/#/inputElements?id=stepper';
Stepper.prototype.objectType = 'Stepper';

175
simulator/src/modules/Text.js Executable file
View file

@ -0,0 +1,175 @@
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
import { rect2, fillText } from '../canvasApi';
/**
* @class
* Text
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} label - label of element
* @param {number=} fontSize - font size
* @category modules
*/
import { colors } from '../themer/themer';
import { copy, paste } from '../events';
export default class Text extends CircuitElement {
constructor(x, y, scope = globalScope, label = '', fontSize = 14) {
super(x, y, scope, 'RIGHT', 1);
/* this is done in this.baseSetup() now
this.scope['Text'].push(this);
*/
// this.setDimensions(15, 15);
this.fixedBitWidth = true;
this.directionFixed = true;
this.labelDirectionFixed = true;
this.setLabel(label);
this.setFontSize(fontSize);
}
/**
* @memberof Text
* function for setting text inside the element
* @param {string=} str - the label
*/
setLabel(str = '') {
this.label = str;
var ctx = simulationArea.context;
ctx.font = `${this.fontSize}px Raleway`;
this.leftDimensionX = 10;
this.rightDimensionX = ctx.measureText(this.label).width + 10;
this.setTextboxSize();
}
/**
* @memberof Text
* function for setting font size inside the element
* @param {number=} str - the font size
*/
setFontSize(fontSize = 14) {
this.fontSize = fontSize;
var ctx = simulationArea.context;
ctx.font = `${this.fontSize}px Raleway`;
this.setTextboxSize();
}
setTextboxSize() {
this.leftDimensionX = 10;
var maxWidth = 0;
var labels = this.label.split('\n');
var ctx = simulationArea.context;
labels.forEach(l => maxWidth = Math.max(maxWidth, ctx.measureText(l).width));
this.rightDimensionX = maxWidth + 10;
this.downDimensionY = labels.length * this.fontSize;
}
/**
* @memberof Text
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [this.label, this.fontSize],
};
return data;
}
/**
* @memberof Text
* Listener function for Text Box
* @param {string} key - the label
*/
keyDown(key) {
if (simulationArea.controlDown && (key === 'c' || key === 'C')) {
const textToPutOnClipboard = copy([this]);
navigator.clipboard.writeText(textToPutOnClipboard);
localStorage.setItem('clipboardData', textToPutOnClipboard);
} else if (simulationArea.controlDown && (key === 'v' || key === 'V')) {
paste(localStorage.getItem('clipboardData'));
} else 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)); }
} else if (key === 'Enter') {
if (this.label === 'Enter Text Here') { this.setLabel(''); } else { this.setLabel(this.label + '\n'); }
}
$('[name=setLabel]').val(this.label);
}
/**
* @memberof Text
* Function for drawing text box
*/
draw() {
//
if (this.label.length === 0 && simulationArea.lastSelected !== this) this.delete();
var ctx = simulationArea.context;
ctx.strokeStyle = colors['stroke'];
ctx.lineWidth = 1;
const xx = this.x;
const yy = this.y;
if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || simulationArea.multipleObjectSelections.contains(this)) {
ctx.beginPath();
ctx.fillStyle = colors['fill'];
const magicDimension = this.fontSize - 14;
rect2(ctx, -this.leftDimensionX, -this.upDimensionY - magicDimension,
this.leftDimensionX + this.rightDimensionX,
this.upDimensionY + this.downDimensionY + magicDimension, this.x, this.y, 'RIGHT');
ctx.fillStyle = 'rgba(255, 255, 32,0.1)';
ctx.fill();
ctx.stroke();
}
ctx.beginPath();
ctx.textAlign = 'left';
ctx.fillStyle = colors['text'];
var labels = this.label.split('\n');
for(var i = 0; i < labels.length; i++) {
fillText(ctx, labels[i], xx, yy + 5 + i * this.fontSize, this.fontSize);
}
ctx.fill();
}
}
/**
* @memberof Text
* Help Tip
* @type {string}
* @category modules
*/
Text.prototype.tooltipText = 'Text ToolTip: Use this to document your circuit.';
/**
* @memberof Text
* Help URL
* @type {string}
* @category modules
*/
Text.prototype.helplink = 'https://docs.circuitverse.org/#/annotation?id=adding-labels';
/**
* @memberof Text
* Mutable properties of the element
* @type {JSON}
* @category modules
*/
Text.prototype.mutableProperties = {
fontSize: {
name: 'Font size: ',
type: 'number',
max: '84',
min: '14',
func: 'setFontSize',
},
label: {
name: 'Text: ',
type: 'textarea',
func: 'setLabel',
},
};
Text.prototype.disableLabel = true;
Text.prototype.objectType = 'Text';
Text.prototype.propagationDelayFixed = true;

129
simulator/src/modules/TriState.js Executable file
View file

@ -0,0 +1,129 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, lineTo, moveTo, arc } from "../canvasApi";
import { changeInputSize } from "../modules";
/**
* @class
* TriState
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node.
* @category modules
*/
import { colors } from "../themer/themer";
export default class TriState extends CircuitElement {
constructor(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['TriState'].push(this);
*/
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.propagationDelay=10000;
/**
* @memberof TriState
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [this.direction, this.bitWidth],
nodes: {
output1: findNode(this.output1),
inp1: findNode(this.inp1),
state: findNode(this.state),
},
};
return data;
}
/**
* @memberof TriState
* function to change bitwidth of the element
* @param {number} bitWidth - new bitwidth
*/
newBitWidth(bitWidth) {
this.inp1.bitWidth = bitWidth;
this.output1.bitWidth = bitWidth;
this.bitWidth = bitWidth;
}
/**
* @memberof TriState
* resolve output values based on inputData
*/
resolve() {
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);
}
/**
* @memberof TriState
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
ctx.strokeStyle = colors["stroke"];
ctx.lineWidth = correctWidth(3);
const xx = this.x;
const yy = this.y;
ctx.beginPath();
ctx.fillStyle = colors["fill"];
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 = colors["hover_select"];
ctx.fill();
ctx.stroke();
}
generateVerilog() {
return `assign ${this.output1.verilogLabel} = (${this.state.verilogLabel}!=0) ? ${this.inp1.verilogLabel} : ${this.inp1.bitWidth}'b?;`;
}
}
/**
* @memberof TriState
* Help Tip
* @type {string}
* @category modules
*/
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.objectType = "TriState";

343
simulator/src/modules/Tunnel.js Executable file
View file

@ -0,0 +1,343 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, rect2, fillText } from "../canvasApi";
import plotArea from "../plotArea";
import { showError } from "../utils";
/**
* @class
* Tunnel
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node.
* @param {string=} identifier - number of input nodes
* @category modules
*/
import { colors } from "../themer/themer";
export default class Tunnel extends CircuitElement {
constructor(
x,
y,
scope = globalScope,
dir = "LEFT",
bitWidth = 1,
identifier
) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['Tunnel'].push(this);
*/
this.rectangleObject = false;
this.centerElement = true;
this.xSize = 10;
this.plotValues = [];
this.inp1 = new Node(0, 0, 0, this);
this.checked = false; // has this tunnel been checked by another paired tunnel
this.setIdentifier(identifier || "T");
this.setBounds();
// if tunnels with this's identifier exist, then set the bitwidth to that of those tunnels
if(this.scope.tunnelList[this.identifier].length > 0) {
this.newBitWidth(this.scope.tunnelList[this.identifier][0].bitWidth);
}
}
/**
* @memberof Tunnel
* function to change direction of Tunnel
* @param {string} dir - new direction
*/
newDirection(dir) {
if (this.direction === dir) return;
this.direction = dir;
this.setBounds();
}
setBounds() {
let xRotate = 0;
let 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);
// rect2(ctx, -120 + xRotate + this.xSize, -20 + yRotate, 120 - this.xSize, 40, xx, yy, "RIGHT");
}
/**
* @memberof Tunnel
* resolve output values based on inputData
*/
resolve() {
// Don't check for paired tunnels' value if already checked by another paired tunnel (O(n))
if (this.checked) {
this.checked = false;
return;
}
// Check for bitwidth error since it bypasses node's resolve() function which usually checks bitwidths
for (const tunnel of this.scope.tunnelList[this.identifier]) {
if (tunnel.inp1.bitWidth !== this.inp1.bitWidth) {
this.inp1.highlighted = true;
tunnel.inp1.highlighted = true;
showError(`BitWidth Error: ${this.inp1.bitWidth} and ${tunnel.inp1.bitWidth}`);
}
if (tunnel.inp1.value !== this.inp1.value) {
tunnel.inp1.value = this.inp1.value;
simulationArea.simulationQueue.add(tunnel.inp1);
}
if (tunnel !== this) tunnel.checked = true;
}
}
/**
* @memberof Tunnel
* function to set tunnel value
* @param {Scope} scope - tunnel value
*/
updateScope(scope) {
this.scope = scope;
this.inp1.updateScope(scope);
this.setIdentifier(this.identifier);
}
/**
* @memberof Tunnel
* function to set plot value
*/
setPlotValue() {
return;
const 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;
}
this.plotValues.push([time, this.inp1.value]);
}
/**
* @memberof Tunnel
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [
this.direction,
this.bitWidth,
this.identifier,
],
nodes: {
inp1: findNode(this.inp1),
},
values: {
identifier: this.identifier,
},
};
return data;
}
/**
* @memberof Tunnel
* function to set tunnel identifier value
* @param {string=} id - id so that every link is unique
*/
setIdentifier(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];
// Change the bitwidth to be same as the other elements with this.identifier
if (this.scope.tunnelList[this.identifier] && this.scope.tunnelList[this.identifier].length > 1) {
this.bitWidth = this.inp1.bitWidth = this.scope.tunnelList[this.identifier][0].bitWidth;
}
const 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();
}
/**
* @memberof Tunnel
* delete the tunnel element
*/
delete() {
this.scope.Tunnel.clean(this);
this.scope.tunnelList[this.identifier].clean(this);
super.delete();
}
/**
* @memberof Tunnel
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
ctx.beginPath();
ctx.strokeStyle = colors["stroke"];
ctx.fillStyle = colors["fill"];
ctx.lineWidth = correctWidth(1);
const xx = this.x;
const yy = this.y;
let xRotate = 0;
let 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 = colors["hover_select"];
}
ctx.fill();
ctx.stroke();
ctx.font = "14px Raleway";
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 Raleway";
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();
}
/**
* Overridden from CircuitElement. Sets all paired tunnels' bitwidths for syncronization
* @param {number} bitWidth - bitwidth to set to
*/
newBitWidth(bitWidth) {
for (let tunnel of this.scope.tunnelList[this.identifier]) {
if (tunnel.fixedBitWidth) continue;
if (tunnel.bitWidth === undefined) continue;
if (tunnel.bitWidth < 1) continue;
tunnel.bitWidth = bitWidth;
for (let i = 0; i < tunnel.nodeList.length; i++) { tunnel.nodeList[i].bitWidth = bitWidth; }
}
}
}
/**
* @memberof Tunnel
* Help Tip
* @type {string}
* @category modules
*/
Tunnel.prototype.tooltipText = "Tunnel ToolTip : Tunnel Selected.";
Tunnel.prototype.helplink =
"https://docs.circuitverse.org/#/miscellaneous?id=tunnel";
Tunnel.prototype.overrideDirectionRotation = true;
/**
* @memberof Tunnel
* Mutable properties of the element
* @type {JSON}
* @category modules
*/
Tunnel.prototype.mutableProperties = {
identifier: {
name: "Debug Flag identifier",
type: "text",
maxlength: "5",
func: "setIdentifier",
},
};
Tunnel.prototype.objectType = "Tunnel";

View file

@ -0,0 +1,109 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, fillText, drawCircle2 } from "../canvasApi";
import { changeInputSize } from "../modules";
/**
* @class
* TwoComplement
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node.
* @category modules
*/
import { colors } from "../themer/themer";
export default class TwoComplement extends CircuitElement {
constructor(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['TwoComplement'].push(this);
*/
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"
);
}
/**
* @memberof TwoComplement
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [this.direction, this.bitWidth],
nodes: {
output1: findNode(this.output1),
inp1: findNode(this.inp1),
},
};
return data;
}
/**
* @memberof TwoComplement
* resolve output values based on inputData
*/
resolve() {
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);
}
/**
* @memberof TwoComplement
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
ctx.strokeStyle = colors["stroke"];
ctx.lineWidth = correctWidth(3);
const xx = this.x;
const 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 = colors["hover_select"];
ctx.fill();
ctx.beginPath();
drawCircle2(ctx, 5, 0, 15, xx, yy, this.direction);
ctx.stroke();
}
generateVerilog() {
return `assign ${this.output1.verilogLabel} = ~${this.inp1.verilogLabel} + 1;`;
}
}
/**
* @memberof TwoComplement
* Help Tip
* @type {string}
* @category modules
*/
TwoComplement.prototype.tooltipText =
"Two's Complement Tooltip : Calculates the two's complement";
TwoComplement.prototype.objectType = "TwoComplement";

View file

@ -0,0 +1,138 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, lineTo, moveTo, arc, drawCircle2 } from "../canvasApi";
import { changeInputSize } from "../modules";
/**
* @class
* VariableLed
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @category modules
*/
import { colors } from "../themer/themer";
export default class VariableLed extends CircuitElement {
constructor(x, y, scope = globalScope) {
// Calling base class constructor
super(x, y, scope, "UP", 8);
/* this is done in this.baseSetup() now
this.scope['VariableLed'].push(this);
*/
this.rectangleObject = false;
this.setDimensions(10, 20);
this.inp1 = new Node(-40, 0, 0, this, 8);
this.directionFixed = true;
this.fixedBitWidth = true;
}
/**
* @memberof VariableLed
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
nodes: {
inp1: findNode(this.inp1),
},
};
return data;
}
/**
* @memberof VariableLed
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
const xx = this.x;
const 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();
const c = this.inp1.value;
const 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 = colors["hover_select"];
ctx.fill();
}
// Draws the element in the subcuircuit. Used in layout mode
subcircuitDraw(xOffset = 0, yOffset = 0) {
var ctx = simulationArea.context;
var xx = this.subcircuitMetadata.x + xOffset;
var yy = this.subcircuitMetadata.y + yOffset;
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();
drawCircle2(ctx, 0, 0, 6, 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();
}
generateVerilog() {
return `
always @ (*)
$display("VeriableLed:${this.inp1.verilogLabel}=%d", ${this.inp1.verilogLabel});`;
}
}
/**
* @memberof VariableLed
* Help Tip
* @type {string}
* @category modules
*/
VariableLed.prototype.tooltipText =
"Variable Led ToolTip: Variable LED inputs an 8 bit value and glows with a proportional intensity.";
/**
* @memberof VariableLed
* Help URL
* @type {string}
* @category modules
*/
VariableLed.prototype.helplink =
"https://docs.circuitverse.org/#/outputs?id=variable-led";
VariableLed.prototype.objectType = "VariableLed";
VariableLed.prototype.canShowInSubcircuit = true;

199
simulator/src/modules/XnorGate.js Executable file
View file

@ -0,0 +1,199 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import {
correctWidth,
bezierCurveTo,
moveTo,
arc2,
drawCircle2,
} from "../canvasApi";
import { gateGenerateVerilog } from '../utils';
import { changeInputSize } from "../modules";
/**
* @class
* XnorGate
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} inputLength - number of input nodes
* @param {number=} bitWidth - bit width per node.
* @category modules
*/
import { colors } from "../themer/themer";
export default class XnorGate extends CircuitElement {
constructor(
x,
y,
scope = globalScope,
dir = "RIGHT",
inputs = 2,
bitWidth = 1
) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['XnorGate'].push(this);
*/
this.rectangleObject = false;
this.setDimensions(15, 20);
this.inp = [];
this.inputSize = inputs;
if (inputs % 2 === 1) {
for (let i = 0; i < inputs / 2 - 1; i++) {
const a = new Node(-20, -10 * (i + 1), 0, this);
this.inp.push(a);
}
let a = new Node(-20, 0, 0, this);
this.inp.push(a);
for (let i = inputs / 2 + 1; i < inputs; i++) {
a = new Node(-20, 10 * (i + 1 - inputs / 2 - 1), 0, this);
this.inp.push(a);
}
} else {
for (let i = 0; i < inputs / 2; i++) {
const a = new Node(-20, -10 * (i + 1), 0, this);
this.inp.push(a);
}
for (let i = inputs / 2; i < inputs; i++) {
const a = new Node(-20, 10 * (i + 1 - inputs / 2), 0, this);
this.inp.push(a);
}
}
this.output1 = new Node(30, 0, 1, this);
}
/**
* @memberof XnorGate
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [
this.direction,
this.inputSize,
this.bitWidth,
],
nodes: {
inp: this.inp.map(findNode),
output1: findNode(this.output1),
},
};
return data;
}
/**
* @memberof XnorGate
* resolve output values based on inputData
*/
resolve() {
let result = this.inp[0].value || 0;
if (this.isResolvable() === false) {
return;
}
for (let i = 1; i < this.inputSize; i++)
result ^= this.inp[i].value || 0;
result =
((~result >>> 0) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
this.output1.value = result;
simulationArea.simulationQueue.add(this.output1);
}
/**
* @memberof XnorGate
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
ctx.strokeStyle = colors["stroke"];
ctx.lineWidth = correctWidth(3);
const xx = this.x;
const yy = this.y;
ctx.beginPath();
ctx.fillStyle = colors["fill"];
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 = colors["hover_select"];
ctx.fill();
ctx.stroke();
ctx.beginPath();
arc2(
ctx,
-35,
0,
25,
1.7 * Math.PI,
0.3 * Math.PI,
xx,
yy,
this.direction
);
ctx.stroke();
ctx.beginPath();
drawCircle2(ctx, 25, 0, 5, xx, yy, this.direction);
ctx.stroke();
}
generateVerilog() {
return gateGenerateVerilog.call(this,'^', true);
}
}
/**
* @memberof XnorGate
* @type {boolean}
* @category modules
*/
XnorGate.prototype.alwaysResolve = true;
/**
* @memberof XnorGate
* Help Tip
* @type {string}
* @category modules
*/
XnorGate.prototype.tooltipText =
"Xnor Gate ToolTip : Logical complement of the XOR gate";
/**
* @memberof XnorGate
* function to change input nodes of the element
* @category modules
*/
XnorGate.prototype.changeInputSize = changeInputSize;
/**
* @memberof XnorGate
* @type {string}
* @category modules
*/
XnorGate.prototype.verilogType = "xnor";
XnorGate.prototype.helplink =
"https://docs.circuitverse.org/#/gates?id=xnor-gate";
XnorGate.prototype.objectType = "XnorGate";

189
simulator/src/modules/XorGate.js Executable file
View file

@ -0,0 +1,189 @@
import CircuitElement from "../circuitElement";
import Node, { findNode } from "../node";
import simulationArea from "../simulationArea";
import { correctWidth, bezierCurveTo, moveTo, arc2 } from "../canvasApi";
import { changeInputSize } from "../modules";
import { gateGenerateVerilog } from '../utils';
/**
* @class
* XorGate
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} inputs - number of input nodes
* @param {number=} bitWidth - bit width per node.
* @category modules
*/
import { colors } from "../themer/themer";
export default class XorGate extends CircuitElement {
constructor(
x,
y,
scope = globalScope,
dir = "RIGHT",
inputs = 2,
bitWidth = 1
) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['XorGate'].push(this);
*/
this.rectangleObject = false;
this.setDimensions(15, 20);
this.inp = [];
this.inputSize = inputs;
if (inputs % 2 === 1) {
for (let i = 0; i < inputs / 2 - 1; i++) {
const a = new Node(-20, -10 * (i + 1), 0, this);
this.inp.push(a);
}
let a = new Node(-20, 0, 0, this);
this.inp.push(a);
for (let i = inputs / 2 + 1; i < inputs; i++) {
a = new Node(-20, 10 * (i + 1 - inputs / 2 - 1), 0, this);
this.inp.push(a);
}
} else {
for (let i = 0; i < inputs / 2; i++) {
const a = new Node(-20, -10 * (i + 1), 0, this);
this.inp.push(a);
}
for (let i = inputs / 2; i < inputs; i++) {
const a = new Node(-20, 10 * (i + 1 - inputs / 2), 0, this);
this.inp.push(a);
}
}
this.output1 = new Node(20, 0, 1, this);
}
/**
* @memberof XorGate
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [
this.direction,
this.inputSize,
this.bitWidth,
],
nodes: {
inp: this.inp.map(findNode),
output1: findNode(this.output1),
},
};
return data;
}
/**
* @memberof XorGate
* resolve output values based on inputData
*/
resolve() {
let result = this.inp[0].value || 0;
if (this.isResolvable() === false) {
return;
}
for (let i = 1; i < this.inputSize; i++)
result ^= this.inp[i].value || 0;
this.output1.value = result;
simulationArea.simulationQueue.add(this.output1);
}
/**
* @memberof XorGate
* function to draw element
*/
customDraw() {
var ctx = simulationArea.context;
ctx.strokeStyle = colors["stroke"];
ctx.lineWidth = correctWidth(3);
const xx = this.x;
const yy = this.y;
ctx.beginPath();
ctx.fillStyle = colors["fill"];
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 = colors["hover_select"];
ctx.fill();
ctx.stroke();
ctx.beginPath();
arc2(
ctx,
-35,
0,
25,
1.7 * Math.PI,
0.3 * Math.PI,
xx,
yy,
this.direction
);
ctx.stroke();
}
generateVerilog() {
return gateGenerateVerilog.call(this, '^');
}
}
/**
* @memberof XorGate
* Help Tip
* @type {string}
* @category modules
*/
XorGate.prototype.tooltipText =
"Xor Gate Tooltip : Implements an exclusive OR.";
/**
* @memberof XorGate
* @type {boolean}
* @category modules
*/
XorGate.prototype.alwaysResolve = true;
/**
* @memberof XorGate
* function to change input nodes of the element
* @category modules
*/
XorGate.prototype.changeInputSize = changeInputSize;
/**
* @memberof XorGate
* @type {string}
* @category modules
*/
XorGate.prototype.verilogType = "xor";
XorGate.prototype.helplink =
"https://docs.circuitverse.org/#/gates?id=xor-gate";
XorGate.prototype.objectType = "XorGate";

View file

@ -0,0 +1,96 @@
/* eslint-disable no-bitwise */
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
/**
* @class
* verilogDivider
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node. modules
* @category modules
*/
export default class verilogDivider extends CircuitElement {
constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1, outputBitWidth = 1) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['verilogDivider'].push(this);
*/
this.setDimensions(20, 20);
this.outputBitWidth = outputBitWidth;
this.inpA = new Node(-20, -10, 0, this, this.bitWidth, 'A');
this.inpB = new Node(-20, 0, 0, this, this.bitWidth, 'B');
this.quotient = new Node(20, 0, 1, this, this.outputBitWidth, 'Quotient');
this.remainder = new Node(20, 0, 1, this, this.outputBitWidth, 'Remainder');
}
/**
* @memberof verilogDivider
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [this.direction, this.bitWidth, this.outputBitWidth],
nodes: {
inpA: findNode(this.inpA),
inpB: findNode(this.inpB),
quotient: findNode(this.quotient),
remainder: findNode(this.remainder)
},
};
return data;
}
/**
* @memberof verilogDivider
* Checks if the element is resolvable
* @return {boolean}
*/
isResolvable() {
return this.inpA.value !== undefined && this.inpB.value !== undefined;
}
/**
* @memberof verilogDivider
* function to change bitwidth of the element
* @param {number} bitWidth - new bitwidth
*/
newBitWidth(bitWidth) {
this.bitWidth = bitWidth;
this.inpA.bitWidth = bitWidth;
this.inpB.bitWidth = bitWidth;
this.quotient.bitWidth = bitWidth;
this.remainder.bitWidth = bitWidth;
}
/**
* @memberof verilogDivider
* resolve output values based on inputData
*/
resolve() {
if (this.isResolvable() === false) {
return;
}
const quotient = this.inpA.value / this.inpB.value;
const remainder = this.inpA.value % this.inpB.value;
this.remainder.value = ((remainder) << (32 - this.outputBitWidth)) >>> (32 - this.outputBitWidth);
this.quotient.value = ((quotient) << (32 - this.outputBitWidth)) >>> (32 - this.outputBitWidth);
simulationArea.simulationQueue.add(this.quotient);
simulationArea.simulationQueue.add(this.remainder);
}
}
/**
* @memberof verilogDivider
* Help Tip
* @type {string}
* @category modules
*/
verilogDivider.prototype.tooltipText = 'verilogDivider ToolTip : Performs addition of numbers.';
verilogDivider.prototype.helplink = 'https://docs.circuitverse.org/#/miscellaneous?id=verilogDivider';
verilogDivider.prototype.objectType = 'verilogDivider';

View file

@ -0,0 +1,91 @@
/* eslint-disable no-bitwise */
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
/**
* @class
* verilogMultiplier
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node. modules
* @category modules
*/
export default class verilogMultiplier extends CircuitElement {
constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1, outputBitWidth = 1) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['verilogMultiplier'].push(this);
*/
this.setDimensions(20, 20);
this.outputBitWidth = outputBitWidth;
this.inpA = new Node(-20, -10, 0, this, this.bitWidth, 'A');
this.inpB = new Node(-20, 0, 0, this, this.bitWidth, 'B');
this.product = new Node(20, 0, 1, this, this.outputBitWidth, 'Product');
}
/**
* @memberof verilogMultiplier
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [this.direction, this.bitWidth, this.outputBitWidth],
nodes: {
inpA: findNode(this.inpA),
inpB: findNode(this.inpB),
product: findNode(this.product),
},
};
return data;
}
/**
* @memberof verilogMultiplier
* Checks if the element is resolvable
* @return {boolean}
*/
isResolvable() {
return this.inpA.value !== undefined && this.inpB.value !== undefined;
}
/**
* @memberof verilogMultiplier
* function to change bitwidth of the element
* @param {number} bitWidth - new bitwidth
*/
newBitWidth(bitWidth) {
this.bitWidth = bitWidth;
this.inpA.bitWidth = bitWidth;
this.inpB.bitWidth = bitWidth;
this.product.bitWidth = bitWidth;
}
/**
* @memberof verilogMultiplier
* resolve output values based on inputData
*/
resolve() {
if (this.isResolvable() === false) {
return;
}
const product = this.inpA.value * this.inpB.value;
this.product.value = ((product) << (32 - this.outputBitWidth)) >>> (32 - this.outputBitWidth);
simulationArea.simulationQueue.add(this.product);
}
}
/**
* @memberof verilogMultiplier
* Help Tip
* @type {string}
* @category modules
*/
verilogMultiplier.prototype.tooltipText = 'verilogMultiplier ToolTip : Performs addition of numbers.';
verilogMultiplier.prototype.helplink = 'https://docs.circuitverse.org/#/miscellaneous?id=verilogMultiplier';
verilogMultiplier.prototype.objectType = 'verilogMultiplier';

View file

@ -0,0 +1,91 @@
/* eslint-disable no-bitwise */
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
/**
* @class
* verilogPower
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node. modules
* @category modules
*/
export default class verilogPower extends CircuitElement {
constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1, outputBitWidth = 1) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['verilogPower'].push(this);
*/
this.setDimensions(20, 20);
this.outputBitWidth = outputBitWidth;
this.inpA = new Node(-20, -10, 0, this, this.bitWidth, 'A');
this.inpB = new Node(-20, 0, 0, this, this.bitWidth, 'B');
this.answer = new Node(20, 0, 1, this, this.outputBitWidth, 'Answer');
}
/**
* @memberof verilogPower
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [this.direction, this.bitWidth, this.outputBitWidth],
nodes: {
inpA: findNode(this.inpA),
inpB: findNode(this.inpB),
answer: findNode(this.answer),
},
};
return data;
}
/**
* @memberof verilogPower
* Checks if the element is resolvable
* @return {boolean}
*/
isResolvable() {
return this.inpA.value !== undefined && this.inpB.value !== undefined;
}
/**
* @memberof verilogPower
* function to change bitwidth of the element
* @param {number} bitWidth - new bitwidth
*/
newBitWidth(bitWidth) {
this.bitWidth = bitWidth;
this.inpA.bitWidth = bitWidth;
this.inpB.bitWidth = bitWidth;
this.answer.bitWidth = bitWidth;
}
/**
* @memberof verilogPower
* resolve output values based on inputData
*/
resolve() {
if (this.isResolvable() === false) {
return;
}
const answer = Math.pow(this.inpA.value, this.inpB.value);
this.answer.value = ((answer) << (32 - this.outputBitWidth)) >>> (32 - this.outputBitWidth);
simulationArea.simulationQueue.add(this.answer);
}
}
/**
* @memberof verilogPower
* Help Tip
* @type {string}
* @category modules
*/
verilogPower.prototype.tooltipText = 'verilogPower ToolTip : Performs addition of numbers.';
verilogPower.prototype.helplink = 'https://docs.circuitverse.org/#/miscellaneous?id=verilogPower';
verilogPower.prototype.objectType = 'verilogPower';

View file

@ -0,0 +1,91 @@
/* eslint-disable no-bitwise */
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
/**
* @class
* verilogShiftLeft
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node. modules
* @category modules
*/
export default class verilogShiftLeft extends CircuitElement {
constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1, outputBitWidth = 1) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['verilogShiftLeft'].push(this);
*/
this.setDimensions(20, 20);
this.outputBitWidth = outputBitWidth;
this.inp1 = new Node(-20, -10, 0, this, this.bitWidth, 'Input');
this.shiftInp = new Node(-20, 0, 0, this, this.bitWidth, 'ShiftInput');
this.output1 = new Node(20, 0, 1, this, this.outputBitWidth, 'Output');
}
/**
* @memberof verilogShiftLeft
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [this.direction, this.bitWidth, this.outputBitWidth],
nodes: {
inp1: findNode(this.inp1),
shiftInp: findNode(this.shiftInp),
output1: findNode(this.output1),
},
};
return data;
}
/**
* @memberof verilogShiftLeft
* Checks if the element is resolvable
* @return {boolean}
*/
isResolvable() {
return this.inp1.value !== undefined && this.shiftInp.value !== undefined;
}
/**
* @memberof verilogShiftLeft
* function to change bitwidth of the element
* @param {number} bitWidth - new bitwidth
*/
newBitWidth(bitWidth) {
this.bitWidth = bitWidth;
this.inp1.bitWidth = bitWidth;
this.shiftInp.bitWidth = bitWidth;
this.output1.bitWidth = bitWidth;
}
/**
* @memberof verilogShiftLeft
* resolve output values based on inputData
*/
resolve() {
if (this.isResolvable() === false) {
return;
}
const output1 = this.inp1.value << this.shiftInp.value;
this.output1.value = ((output1) << (32 - this.outputBitWidth)) >>> (32 - this.outputBitWidth);
simulationArea.simulationQueue.add(this.output1);
}
}
/**
* @memberof verilogShiftLeft
* Help Tip
* @type {string}
* @category modules
*/
verilogShiftLeft.prototype.tooltipText = 'verilogShiftLeft ToolTip : Performs addition of numbers.';
verilogShiftLeft.prototype.helplink = 'https://docs.circuitverse.org/#/miscellaneous?id=verilogShiftLeft';
verilogShiftLeft.prototype.objectType = 'verilogShiftLeft';

View file

@ -0,0 +1,91 @@
/* eslint-disable no-bitwise */
import CircuitElement from '../circuitElement';
import Node, { findNode } from '../node';
import simulationArea from '../simulationArea';
/**
* @class
* verilogShiftRight
* @extends CircuitElement
* @param {number} x - x coordinate of element.
* @param {number} y - y coordinate of element.
* @param {Scope=} scope - Cirucit on which element is drawn
* @param {string=} dir - direction of element
* @param {number=} bitWidth - bit width per node. modules
* @category modules
*/
export default class verilogShiftRight extends CircuitElement {
constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1, outputBitWidth = 1) {
super(x, y, scope, dir, bitWidth);
/* this is done in this.baseSetup() now
this.scope['verilogShiftRight'].push(this);
*/
this.setDimensions(20, 20);
this.outputBitWidth = outputBitWidth;
this.inp1 = new Node(-20, -10, 0, this, this.bitWidth, 'Input');
this.shiftInp = new Node(-20, 0, 0, this, this.bitWidth, 'ShiftInput');
this.output1 = new Node(20, 0, 1, this, this.outputBitWidth, 'Output');
}
/**
* @memberof verilogShiftRight
* fn to create save Json Data of object
* @return {JSON}
*/
customSave() {
const data = {
constructorParamaters: [this.direction, this.bitWidth, this.outputBitWidth],
nodes: {
inp1: findNode(this.inp1),
shiftInp: findNode(this.shiftInp),
output1: findNode(this.output1),
},
};
return data;
}
/**
* @memberof verilogShiftRight
* Checks if the element is resolvable
* @return {boolean}
*/
isResolvable() {
return this.inp1.value !== undefined && this.shiftInp.value !== undefined;
}
/**
* @memberof verilogShiftRight
* function to change bitwidth of the element
* @param {number} bitWidth - new bitwidth
*/
newBitWidth(bitWidth) {
this.bitWidth = bitWidth;
this.inp1.bitWidth = bitWidth;
this.shiftInp.bitWidth = bitWidth;
this.output1.bitWidth = bitWidth;
}
/**
* @memberof verilogShiftRight
* resolve output values based on inputData
*/
resolve() {
if (this.isResolvable() === false) {
return;
}
const output1 = this.inp1.value >> this.shiftInp.value;
this.output1.value = ((output1) << (32 - this.outputBitWidth)) >>> (32 - this.outputBitWidth);
simulationArea.simulationQueue.add(this.output1);
}
}
/**
* @memberof verilogShiftRight
* Help Tip
* @type {string}
* @category modules
*/
verilogShiftRight.prototype.tooltipText = 'verilogShiftRight ToolTip : Performs addition of numbers.';
verilogShiftRight.prototype.helplink = 'https://docs.circuitverse.org/#/miscellaneous?id=verilogShiftRight';
verilogShiftRight.prototype.objectType = 'verilogShiftRight';