hdl-js
Version:
Hardware definition language (HDL) and Hardware simulator
307 lines (244 loc) • 7.29 kB
JavaScript
/**
* 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;