UNPKG

hdl-js

Version:

Hardware definition language (HDL) and Hardware simulator

155 lines (117 loc) 5.73 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 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;