UNPKG

hdl-js

Version:

Hardware definition language (HDL) and Hardware simulator

307 lines (244 loc) 7.29 kB
/** * The MIT License (MIT) * Copyright (c) 2017-present Dmitry Soshnikov <dmitry.soshnikov@gmail.com> */ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var EventEmitter = require('events'); var _require = require('../../util/numbers'), isNegativeZero = _require.isNegativeZero; /** * The system clock is used to synchronize handling of all * the "clocked chips" (such as data storage, etc). * * The clocked gates update their internal state when clock goes up * (aka the "rising edge"), and commit the changes to the output pins, * when clock goes down (aka the "falling edge"). * * The low * * A rising edge followed by a falling edge is a "Clock Cycle". * * A clock operates with a "Clock Rate" -- a number of clock * cycles per second, measured in Hz (default is 1Hz -- 1 cycle per second). */ var Clock = function (_EventEmitter) { _inherits(Clock, _EventEmitter); /** * Creates a clock instance. */ function Clock() { var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, _ref$rate = _ref.rate, rate = _ref$rate === undefined ? 1 : _ref$rate, _ref$value = _ref.value, value = _ref$value === undefined ? -0 : _ref$value; _classCallCheck(this, Clock); var _this = _possibleConstructorReturn(this, (Clock.__proto__ || Object.getPrototypeOf(Clock)).call(this)); _this.setRate(rate); _this.setValue(value); // Tracks the halfs in a cycle, to emit full 'cycle' event // from tick, followed by tock. _this._halfs = 0; // There might be more than 11 (default in Node) listeners of the clock. _this.setMaxListeners(Infinity); return _this; } /** * Resets the clock. * * Initial clock value is -0. Each tick: set positive sign, * each tock: increase, set negative sign back. */ _createClass(Clock, [{ key: 'reset', value: function reset() { this.setValue(-0); return this; } /** * Sets clock value. */ }, { key: 'setValue', value: function setValue(value) { this._value = value; // Next full 'cycle' event will be relatively // this set value, so reset the halfs counter. this._halfs = 0; this.emit('change', this._value); return this; } /** * Returns clock value. */ }, { key: 'getValue', value: function getValue() { return this._value; } /** * Sets the clock rate. */ }, { key: 'setRate', value: function setRate(rate) { this._rate = rate; return this; } /** * Returns the clock rate. */ }, { key: 'getRate', value: function getRate() { return this._rate; } /** * Starts the clock, and continues running it, * executing number of cycles withing 1 second. */ }, { key: 'start', value: function start() { var _this2 = this; this.cyclesForRate(); this._timeoutID = setTimeout(function () { return _this2.start(); }, 1000); return this; } /** * Stops the clock. */ }, { key: 'stop', value: function stop() { clearTimeout(this._timeoutID); return this; } /** * Rising edge (aka "tick"), half-cycle. * * Goes from -0 to +0, from -1 to +1, etc; * notifies the clocked gates. */ }, { key: 'tick', value: function tick() { // setValue resets `halfs`, so save it. var halfs = this._halfs; this.setValue(-this._value); this.emit('tick', this._value); this._halfs = halfs; this._emitHalfsEvent(); return this; } /** * Falling edge (aka "tock"), half-cycle. * * Goes from +0 to -1, from +1 to -2, etc; * notifies the clocked gates. */ }, { key: 'tock', value: function tock() { // setValue resets `halfs`, so save it. var halfs = this._halfs; this.setValue(-(Math.abs(this._value) + 1)); this.emit('tock', this._value); this._halfs = halfs; this._emitHalfsEvent(); return this; } /** * Emits full cycle after tick -> tock. */ }, { key: '_emitHalfsEvent', value: function _emitHalfsEvent() { this._halfs++; if (this._halfs > 0) { this.emit('next', this._value); } if (this._halfs === 2) { this.emit('cycle', this._value); this._halfs = 0; } } /** * Next half-cycle (tick or tock). */ }, { key: 'next', value: function next() { if (this.isDown()) { this.tick(); } else { this.tock(); } return this; } /** * One full cycle. */ }, { key: 'cycle', value: function cycle() { if (this.isDown()) { this.tick(); this.tock(); } else { this.tock(); this.tick(); } return this; } /** * Runs several cycles. */ }, { key: 'cycles', value: function cycles(n) { for (var i = 0; i < n; i++) { this.cycle(); } return this; } /** * Runs several cycles, according to the clock rate. */ }, { key: 'cyclesForRate', value: function cyclesForRate() { this.cycles(this._rate); return this; } /** * Whether the clock is up. */ }, { key: 'isUp', value: function isUp() { return !this.isDown(); } /** * Whether the clock is down. */ }, { key: 'isDown', value: function isDown() { return isNegativeZero(this._value) || this._value < 0; } }]); return Clock; }(EventEmitter); /** * Default System clock, so all chips * cat subscribe to it. */ Clock.SystemClock = new Clock({ rate: 1 }); module.exports = Clock;