hdl-js
Version:
Hardware definition language (HDL) and Hardware simulator
155 lines (117 loc) • 5.73 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 RAM = require('./RAM');
var _require = require('../../../util/numbers'),
int16Table = _require.int16Table,
getBitAt = _require.getBitAt,
setBitAt = _require.setBitAt;
/**
* Canonical truth table for the `Screen` gate.
*/
// prettier-ignore
var TRUTH_TABLE = int16Table([{ $clock: -0, in: 0, load: 0, address: 0, out: 0 }, { $clock: +0, in: 21, load: 1, address: 0, out: 0 }, { $clock: -1, in: 1, load: 0, address: 0, out: 21 }, { $clock: +1, in: 21, load: 0, address: 0, out: 21 }, { $clock: -2, in: 21, load: 0, address: 0, out: 21 }, { $clock: +2, in: 53781, load: 1, address: 2, out: 0 }, { $clock: -3, in: 53781, load: 0, address: 2, out: 53781 }, { $clock: +3, in: 65535, load: 1, address: 8191, out: 0 }, { $clock: -4, in: 0, load: 1, address: 8191, out: 65535 }, { $clock: +4, in: 0, load: 1, address: 8191, out: 65535 }, { $clock: -5, in: 0, load: 0, address: 8191, out: 0 }]);
var WORD_SIZE = 16;
var ROWS = 256;
var COLUMNS = 512;
var WORDS_IN_ROW = COLUMNS / WORD_SIZE;
/**
* A 256 x 512 screen, implemented with 8K registers, each register
* represents 16 pixels.
*
* 256 rows, each row contains 32 words (512 / 16).
*
* The output is the value stored at the memory location specified by address.
* If load=1, loads the input into the memory location specified by address.
*/
var Screen = function (_RAM) {
_inherits(Screen, _RAM);
function Screen(options) {
_classCallCheck(this, Screen);
return _possibleConstructorReturn(this, (Screen.__proto__ || Object.getPrototypeOf(Screen)).call(this, Object.assign({ size: ROWS * WORDS_IN_ROW }, options)));
}
/**
* Clears the screen.
*/
_createClass(Screen, [{
key: 'clear',
value: function clear() {
this.reset();
return this;
}
/**
* Returns a value of a pixel at (row, column) position.
*
* word = Screen[32 * row + column / 16]
* bit number: column / 16
*/
}, {
key: 'getPixelAt',
value: function getPixelAt(row, column) {
var word = this.getWordForLocation(row, column);
return getBitAt(word, column % WORD_SIZE);
}
/**
* Sets a value of a pixel at (row, column) coordinates.
*/
}, {
key: 'setPixelAt',
value: function setPixelAt(row, column, value) {
var address = this.getAddressForLocation(row, column);
var word = this.getValueAt(address);
word = setBitAt(word, column % WORD_SIZE, value);
this.setValueAt(address, word);
return this;
}
/**
* Returns a word corresponding to row, and column.
*
* Screen[32 * row + column / 16]
*/
}, {
key: 'getWordForLocation',
value: function getWordForLocation(row, column) {
return this._storage[this.getAddressForLocation(row, column)];
}
/**
* Returns absolute address corresponding to location.
*/
}, {
key: 'getAddressForLocation',
value: function getAddressForLocation(row, column) {
this._checkLocation(row, column);
return WORDS_IN_ROW * row + Math.trunc(column / WORD_SIZE);
}
/**
* Validates locations.
*/
}, {
key: '_checkLocation',
value: function _checkLocation(row, column) {
if (row < 0 || row > ROWS - 1) {
throw new TypeError('Screen: invalid row ' + row + ', max row is ' + (ROWS - 1) + '.');
}
if (column < 0 || column > COLUMNS - 1) {
throw new TypeError('Screen: invalid column ' + column + ', max column is ' + (COLUMNS - 1) + '.');
}
}
}]);
return Screen;
}(RAM);
/**
* Specification of the `Screen` gate.
*/
Screen.Spec = {
name: 'Screen',
description: 'A 256 x 512 screen, implemented with 8K registers, each register\nrepresents 16 pixels.\n\n256 rows, each row contains 32 words (512 / 16).\n\nThe output is the value stored at the memory location specified by address.\nIf load=1, loads the input into the memory location specified by address.',
inputPins: [{ name: 'in', size: 16 }, { name: 'load', size: 1 }, { name: 'address', size: 13 }],
outputPins: [{ name: 'out', size: 16 }],
truthTable: TRUTH_TABLE
};
module.exports = Screen;