diff --git a/src/simulator/src/metadata.ts b/src/simulator/src/metadata.ts index 5d99084ca..c8391a1d9 100644 --- a/src/simulator/src/metadata.ts +++ b/src/simulator/src/metadata.ts @@ -38,6 +38,7 @@ export const circuitElementList = [ "TTY", "Keyboard", "Clock", + "ClockDivider", "DigitalLed", "Stepper", "VariableLed", @@ -85,6 +86,7 @@ export const inputList = [ "ConstantVal", "Input", "Clock", + "ClockDivider", "Button", "Counter" ] @@ -101,6 +103,7 @@ export const subCircuitInputList = [ "Power", "ConstantVal", "Clock", + "ClockDivider", "Button", "Counter" ] @@ -158,6 +161,7 @@ export const elementHierarchy: Record = { { name: "TTY", label: "TTY" }, { name: "Keyboard", label: "Keyboard" }, { name: "Clock", label: "Clock" }, + { name: "ClockDivider", label: "Clock Divider" }, { name: "Rom", label: "ROM" }, { name: "RAM", label: "RAM" }, { name: "verilogRAM", label: "Verilog RAM" }, diff --git a/src/simulator/src/moduleSetup.js b/src/simulator/src/moduleSetup.js index fb75f6a8e..07daa6a16 100644 --- a/src/simulator/src/moduleSetup.js +++ b/src/simulator/src/moduleSetup.js @@ -7,6 +7,7 @@ import ImageAnnotation from './modules/ImageAnnotation' import BitSelector from './modules/BitSelector' import Buffer from './modules/Buffer' import Button from './modules/Button' +import ClockDivider from './modules/ClockDivider' import ConstantVal from './modules/ConstantVal' import ControlledInverter from './modules/ControlledInverter' import Counter from './modules/Counter' @@ -123,6 +124,7 @@ export default function setupModules() { TTY, Keyboard, Clock, + ClockDivider, Rom, EEPROM, RAM, diff --git a/src/simulator/src/modules/ClockDivider.js b/src/simulator/src/modules/ClockDivider.js new file mode 100644 index 000000000..2f354866c --- /dev/null +++ b/src/simulator/src/modules/ClockDivider.js @@ -0,0 +1,117 @@ +import CircuitElement from '../circuitElement' +import Node, { findNode } from '../node' +import { simulationArea } from '../simulationArea' +import { correctWidth, rect2, fillText } from '../canvasApi' +import { colors } from '../themer/themer' + +/** + * @class + * ClockDivider + * @extends CircuitElement + * @param {number} x - x coordinate of element. + * @param {number} y - y coordinate of element. + * @param {Scope=} scope - Circuit on which element is drawn + * @param {number=} divideFactor - The factor to divide the clock by (default 2) + * @category modules + */ +export default class ClockDivider extends CircuitElement { + constructor(x, y, scope = globalScope, divideFactor = 2) { + super(x, y, scope, 'RIGHT', 1) + this.divideFactor = divideFactor || 2 + this.counter = 0 + this.prevClockState = undefined + this.setDimensions(15, 15) + this.rectangleObject = true + + this.clock = new Node(-15, 0, 0, this, 1, 'Clock') + this.output = new Node(15, 0, 1, this, 1, 'Out') + this.mutableProperties = { + divideFactor: { + name: 'Divide Factor', + type: 'number', + max: '100', + min: '2', + func: 'setDivideFactor', + }, + } + } + + setDivideFactor(value) { + let factor = parseInt(value, 10) + if (isNaN(factor)) return + + // Clamp to UI-advertised range + factor = Math.max(2, Math.min(100, factor)) + + if (factor !== this.divideFactor) { + this.divideFactor = factor + this.counter = 0 // Reset counter when factor changes + } + } + + /** + * @memberof ClockDivider + * fn to create save Json Data of object + * @return {JSON} + */ + customSave() { + const data = { + constructorParameters: [this.divideFactor], + nodes: { + clock: findNode(this.clock), + output: findNode(this.output), + }, + } + return data + } + + /** + * @memberof ClockDivider + * resolve output values based on inputData + */ + resolve() { + if (this.clock.value !== this.prevClockState && this.clock.value === 1) { + this.counter++ + } + this.prevClockState = this.clock.value + + if (this.counter >= this.divideFactor) { + this.counter = 0 + } + + const outputValue = (this.counter % this.divideFactor) < (this.divideFactor / 2) ? 1 : 0 + + if (this.output.value !== outputValue) { + this.output.value = outputValue + simulationArea.simulationQueue.add(this.output) + } + } + + /** + * @memberof ClockDivider + * function to draw element + */ + customDraw() { + var ctx = simulationArea.context + var xx = this.x + var yy = this.y + + ctx.strokeStyle = colors['stroke'] + ctx.fillStyle = colors['fill'] + ctx.lineWidth = correctWidth(3) + + ctx.beginPath() + rect2(ctx, -15, -15, 30, 30, xx, yy, this.direction) + ctx.fill() + ctx.stroke() + + ctx.font = '14px Raleway' + ctx.fillStyle = colors['input_text'] + ctx.textAlign = 'center' + fillText(ctx, 'รท' + this.divideFactor, xx, yy + 5, 14) + } +} + +ClockDivider.prototype.tooltipText = 'Clock Divider: Divides the input clock frequency' +ClockDivider.prototype.helplink = 'https://docs.circuitverse.org/' // Placeholder as per instructions to not add extras +ClockDivider.prototype.objectType = 'ClockDivider'