hdl-js
Version:
Hardware definition language (HDL) and Hardware simulator
338 lines (280 loc) • 11 kB
JavaScript
/**
* The MIT License (MIT)
* Copyright (c) 2017-present Dmitry Soshnikov <dmitry.soshnikov@gmail.com>
*/
;
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
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 Gate = require('./Gate');
/**
* A gate consisting of several sub-parts implementation
* (usually a user-defined gate).
*/
var CompositeGate = function (_Gate) {
_inherits(CompositeGate, _Gate);
/**
* Creates a gate instance with the given name.
*/
function CompositeGate() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
_ref$name = _ref.name,
name = _ref$name === undefined ? null : _ref$name,
_ref$inputPins = _ref.inputPins,
inputPins = _ref$inputPins === undefined ? [] : _ref$inputPins,
_ref$outputPins = _ref.outputPins,
outputPins = _ref$outputPins === undefined ? [] : _ref$outputPins,
_ref$internalPins = _ref.internalPins,
internalPins = _ref$internalPins === undefined ? [] : _ref$internalPins,
_ref$parts = _ref.parts,
parts = _ref$parts === undefined ? [] : _ref$parts,
_ref$ast = _ref.ast,
ast = _ref$ast === undefined ? null : _ref$ast,
_ref$manualClock = _ref.manualClock,
manualClock = _ref$manualClock === undefined ? false : _ref$manualClock;
_classCallCheck(this, CompositeGate);
var _this = _possibleConstructorReturn(this, (CompositeGate.__proto__ || Object.getPrototypeOf(CompositeGate)).call(this, {
name: name,
inputPins: inputPins,
outputPins: outputPins,
manualClock: manualClock
}));
_this._internalPins = internalPins;
_this._parts = parts;
// If a composite gate is created from AST,
// it directly provides it:
_this._ast = ast;
// Rebuild map to consider internal pins.
_this._buildNamesToPinsMap();
return _this;
}
/**
* Returns internal pins of this gate.
*/
_createClass(CompositeGate, [{
key: 'getInternalPins',
value: function getInternalPins() {
return this._internalPins;
}
/**
* Returns implementation parts (gates) of this gate..
*/
}, {
key: 'getParts',
value: function getParts() {
return this._parts;
}
/**
* Evaluates this gate.
*/
}, {
key: 'eval',
value: function _eval() {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = this._parts[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var part = _step.value;
part.eval();
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
/**
* Whether this gate is clocked.
*/
}, {
key: 'clockUp',
/**
* Handler for the rising edge of the clock: updates internal state,
* outputs are not updated ("latched").
*/
value: function clockUp() {
if (!this.getClass().isClocked()) {
throw new TypeError('Gate#clockUp: "' + this._name + '" is not clocked.');
}
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = this._parts[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var part = _step2.value;
part.tick();
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
/**
* Handler for the falling edge of the clock: commits the internal state,
* values to the output.
*/
}, {
key: 'clockDown',
value: function clockDown() {
if (!this.getClass().isClocked()) {
throw new TypeError('Gate#clockDown: "' + this._name + '" is not clocked.');
}
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = this._parts[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var part = _step3.value;
part.tock();
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
}
/**
* Transforms this composite gate instance to the AST format.
* The AST then can be fed to the code generator, and be
* exported to an HDL file.
*/
}, {
key: 'toAST',
value: function toAST() {
// If the composite gate instance is created from AST
// it directly provides it. Or if we already calculated it,
// directly return.
if (this._ast) {
return this._ast;
}
var pinToNode = function pinToNode(pin) {
var nameNode = {
type: 'Name',
value: pin.getName()
};
if (pin.getSize() !== 1) {
nameNode.size = pin.getSize();
}
return nameNode;
};
var inputs = this.getInputPins().map(pinToNode);
var outputs = this.getOutputPins().map(pinToNode);
// E.g. And(a=a[0], b=b[0], out=out[0]);
// The index/range is stored in the `connectInfo`:
var parts = this.getParts().map(function (part) {
var callArguments = [];
// a, b:
part.getInputPins().forEach(function (pin) {
var connectInfo = pin.getSourcePin().getListeningPinsMap().get(pin);
var name = Object.assign({
type: 'Name',
value: pin.getName()
}, connectInfo.destinationSpec);
var value = Object.assign({
type: 'Name',
value: pin.getSourcePin().getName()
}, connectInfo.sourceSpec);
callArguments.push({
type: 'Argument',
name: name,
value: value
});
});
// Several pins can listen to the output pins:
part.getOutputPins().forEach(function (pin) {
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _iterator4 = pin.getListeningPinsMap()[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var _ref2 = _step4.value;
var _ref3 = _slicedToArray(_ref2, 2);
var destPin = _ref3[0];
var connectInfo = _ref3[1];
var name = Object.assign({
type: 'Name',
value: pin.getName()
}, connectInfo.sourceSpec);
var value = Object.assign({
type: 'Name',
value: destPin.getName()
}, connectInfo.destinationSpec);
callArguments.push({
type: 'Argument',
name: name,
value: value
});
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
});
return {
type: 'ChipCall',
name: part.getName(),
arguments: callArguments
};
});
return this._ast = {
type: 'Chip',
name: this.getName(),
inputs: inputs,
outputs: outputs,
parts: parts,
builtins: [],
clocked: []
};
}
}], [{
key: 'isClocked',
value: function isClocked() {
// This default value is overridden in the child classes
// created from HDL files.
return false;
}
}]);
return CompositeGate;
}(Gate);
module.exports = CompositeGate;