把前端从CircuitVerse中拆了出来
This commit is contained in:
commit
5bf1284599
2182 changed files with 189323 additions and 0 deletions
188
simulator/src/modules/ALU.js
Executable file
188
simulator/src/modules/ALU.js
Executable 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
106
simulator/src/modules/Adder.js
Executable 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
174
simulator/src/modules/AndGate.js
Executable 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
84
simulator/src/modules/Arrow.js
Executable 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";
|
173
simulator/src/modules/BitSelector.js
Executable file
173
simulator/src/modules/BitSelector.js
Executable 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
128
simulator/src/modules/Buffer.js
Executable 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
173
simulator/src/modules/Button.js
Executable 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;
|
214
simulator/src/modules/ConstantVal.js
Executable file
214
simulator/src/modules/ConstantVal.js
Executable 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";
|
122
simulator/src/modules/ControlledInverter.js
Executable file
122
simulator/src/modules/ControlledInverter.js
Executable 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";
|
185
simulator/src/modules/Counter.js
Normal file
185
simulator/src/modules/Counter.js
Normal 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
290
simulator/src/modules/Decoder.js
Executable 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";
|
324
simulator/src/modules/Demultiplexer.js
Executable file
324
simulator/src/modules/Demultiplexer.js
Executable 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";
|
174
simulator/src/modules/DigitalLed.js
Executable file
174
simulator/src/modules/DigitalLed.js
Executable 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
234
simulator/src/modules/Flag.js
Executable 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
126
simulator/src/modules/Ground.js
Executable 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';
|
276
simulator/src/modules/HexDisplay.js
Executable file
276
simulator/src/modules/HexDisplay.js
Executable 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
|
||||
}
|
225
simulator/src/modules/ImageAnnotation.js
Normal file
225
simulator/src/modules/ImageAnnotation.js
Normal 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
194
simulator/src/modules/Input.js
Executable 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
144
simulator/src/modules/LSB.js
Executable 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
139
simulator/src/modules/MSB.js
Executable 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";
|
344
simulator/src/modules/Multiplexer.js
Executable file
344
simulator/src/modules/Multiplexer.js
Executable 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
174
simulator/src/modules/NandGate.js
Executable 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
184
simulator/src/modules/NorGate.js
Executable 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
108
simulator/src/modules/NotGate.js
Executable 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
175
simulator/src/modules/OrGate.js
Executable 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
225
simulator/src/modules/Output.js
Executable 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
146
simulator/src/modules/Power.js
Executable 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";
|
276
simulator/src/modules/PriorityEncoder.js
Executable file
276
simulator/src/modules/PriorityEncoder.js
Executable 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
170
simulator/src/modules/RGBLed.js
Executable 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;
|
327
simulator/src/modules/RGBLedMatrix.js
Normal file
327
simulator/src/modules/RGBLedMatrix.js
Normal 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';
|
160
simulator/src/modules/Random.js
Normal file
160
simulator/src/modules/Random.js
Normal 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
|
||||
}
|
146
simulator/src/modules/Rectangle.js
Executable file
146
simulator/src/modules/Rectangle.js
Executable 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';
|
176
simulator/src/modules/SevenSegDisplay.js
Executable file
176
simulator/src/modules/SevenSegDisplay.js
Executable 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
|
||||
}
|
217
simulator/src/modules/SixteenSegDisplay.js
Executable file
217
simulator/src/modules/SixteenSegDisplay.js
Executable 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
287
simulator/src/modules/Splitter.js
Executable 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';
|
189
simulator/src/modules/SquareRGBLed.js
Executable file
189
simulator/src/modules/SquareRGBLed.js
Executable 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
|
||||
}
|
99
simulator/src/modules/Stepper.js
Executable file
99
simulator/src/modules/Stepper.js
Executable 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
175
simulator/src/modules/Text.js
Executable 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
129
simulator/src/modules/TriState.js
Executable 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
343
simulator/src/modules/Tunnel.js
Executable 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";
|
109
simulator/src/modules/TwoComplement.js
Executable file
109
simulator/src/modules/TwoComplement.js
Executable 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";
|
138
simulator/src/modules/VariableLed.js
Executable file
138
simulator/src/modules/VariableLed.js
Executable 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
199
simulator/src/modules/XnorGate.js
Executable 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
189
simulator/src/modules/XorGate.js
Executable 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";
|
96
simulator/src/modules/verilogDivider.js
Normal file
96
simulator/src/modules/verilogDivider.js
Normal 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';
|
91
simulator/src/modules/verilogMultiplier.js
Normal file
91
simulator/src/modules/verilogMultiplier.js
Normal 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';
|
91
simulator/src/modules/verilogPower.js
Normal file
91
simulator/src/modules/verilogPower.js
Normal 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';
|
91
simulator/src/modules/verilogShiftLeft.js
Normal file
91
simulator/src/modules/verilogShiftLeft.js
Normal 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';
|
91
simulator/src/modules/verilogShiftRight.js
Normal file
91
simulator/src/modules/verilogShiftRight.js
Normal 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';
|
Loading…
Add table
Add a link
Reference in a new issue