161 lines
5.2 KiB
JavaScript
161 lines
5.2 KiB
JavaScript
|
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
|
||
|
}
|