CircuitOnline/simulator/src/modules/Counter.js

185 lines
No EOL
5.9 KiB
JavaScript

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
}