/* * 6502 Based Virtual Computer * Copyright (C) 2011 Scott C. Duensing * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ // Our display adapter object. function textDisplay() { // This display adapter can render text in 16 foreground colors // on 16 background colors. A simple "BIOS" is available by // writing command data into the byte directly following the // display memory and then the command into the byte after that. // You may also write directly to display RAM. // --- Private variables. var self = this; // Memory Information. var MEMORY = null; var MEMORY_START = 0; var DATA_BYTE = 0; var DATA_LSB = 0; var DATA_BYTE_ADDRESS = 0; var COMMAND_BYTE_ADDRESS = 0; // Font size. var FONT_SIZE = 12; // Default character cell size. var CELL_WIDTH = 8; var CELL_HEIGHT = 12; // Default display size. var WIDTH = 80; var HEIGHT = 25; // Is this a color display? var IS_COLOR = true; // Cursor position. var CURSOR_X = 0; var CURSOR_Y = 0; // Current color attribute. Boring white on black. (LSN=FG, MSN=BG) var COLOR_VALUE = 7; // --- Private methods. // Clear the screen to the current color attributes. var clearDisplay = function() { var byte = MEMORY_START; for (var y=0; y 0) x--; } else if (c == 9) { // TAB x = (x + 8) & ~7; } else if (c == 10) { // Line Feed y++; } else if (c == 13) { // Carriage Return x = 0; } else { // Other characters. MEMORY.writeByte(byte++, c); if (IS_COLOR) MEMORY.writeByte(byte++, COLOR_VALUE); self.refresh(x, y); x++; } // Line wrap? if (x >= WIDTH - 1) { x = 0; y++; } // Scroll required? var didScroll = false; while (y >= HEIGHT) { didScroll = true; byte = MEMORY_START; for (var i=0; i<(HEIGHT - 1) * WIDTH; i++) { MEMORY.writeByte(byte, MEMORY.readByte(byte + WIDTH * color)); byte++; if (IS_COLOR) { MEMORY.writeByte(byte, MEMORY.readByte(byte + WIDTH * color)); byte++; } } //byte = MEMORY_START + WIDTH * (HEIGHT - 1) * color; for (var i=0; i"; for (var w=0; w "; } html += ""; } html += ""; document.getElementById(divId).innerHTML = html; DATA_BYTE_ADDRESS = byte++; COMMAND_BYTE_ADDRESS = byte++; moveCursor(0, 0); this.refreshAll(); // Set up memory mapped hardware ports. MEMORY.addWriteCallback(MEMORY_START, MEMORY_START + this.getMemoryNeeded() - 1, null, function(address, value, data){ MEMORY.callbacksEnabled(false); var offset = address - MEMORY_START; // Is this a write to one of the command ports or direct to video memory? if (address >= DATA_BYTE_ADDRESS) { // Command byte? if (address == COMMAND_BYTE_ADDRESS) { if (value == 0) DATA_LSB = DATA_BYTE; if (value == 1) clearDisplay(); if (value == 2) moveCursor(DATA_BYTE, CURSOR_Y); if (value == 3) moveCursor(CURSOR_X, DATA_BYTE); if (value == 4) MEMORY.writeByte(DATA_BYTE_ADDRESS, CURSOR_X); if (value == 5) MEMORY.writeByte(DATA_BYTE_ADDRESS, CURSOR_Y); if (value == 6) COLOR_VALUE = DATA_BYTE; if (value == 7) drawCharacter(DATA_BYTE); if (value == 8) drawString((DATA_BYTE << 8) + DATA_LSB); } else { // Data byte. DATA_BYTE = value; } } else { if (IS_COLOR) { // Is this the character byte or the color byte? if (offset % 2 == 0) offset = offset / 2; // Character. else offset = ((offset + 1) / 2) - 1; // Color. } var y = Math.floor(offset / monitor.getWidth()); var x = offset - y * monitor.getWidth(); monitor.refresh(x, y); } MEMORY.callbacksEnabled(true); }); }; // Refresh a single character cell. this.refresh = function(x, y) { // These are good old PC DOS colors. // black, dark red, dark green, brown, dark blue, dark magenta, dark cyan, gray // dim gray, red, green, yellow, blue, magenta, cyan, white var colors = ["#000000", "#8B0000", "#006400", "#8B8B00", "#00008B", "#8B008B", "#008B8B", "#808080", "#696969", "#FF0000", "#00FF00", "#FFFF00", "#0000FF", "#FF00FF", "#00FFFF", "#FFFFFF"]; var byte = MEMORY_START + (y * WIDTH + x) * (IS_COLOR ? 2 : 1); var foreground = colors[7]; var background = colors[0]; if (IS_COLOR) { // LSN=FG, MSN=BG var value = MEMORY.readByte(byte + 1); var LSN = value & 0x0f; var MSN = (value & 0xf0) >> 4; foreground = colors[LSN]; background = colors[MSN]; } var element = document.getElementById("cc" + x + "x" + y); var style = element.style; var html = ""; html += String.fromCharCode(MEMORY.readByte(byte)); html += ""; element.innerHTML = html; style.background = background; }; // Refresh the entire display. this.refreshAll = function() { for (var h=0; h