Merge branch 'master' into gh-pages

This commit is contained in:
Jeff Parsons 2016-08-16 11:50:59 -07:00
commit 7d298b17f4
12 changed files with 719 additions and 497 deletions

View file

@ -10,5 +10,7 @@ PC8080 Machine Configurations
The following 8080-based machines are currently available:
* [8080 Exerciser](exerciser/)
* [Space Invaders (1978)](invaders/)
* [DEC VT100 Terminal](vt100/)
* [Space Invaders (1978)](invaders/) (with [Debugger](invaders/debugger/))
* [DEC VT100 Terminal](vt100/) (with [Debugger](vt100/debugger/))
And check out the [Dual VT100 Terminals](vt100/dual/) for a demo of two PCjs machines communicating over a *virtual* serial connection.

View file

@ -3,9 +3,8 @@ layout: page
title: DEC VT100 Terminal
permalink: /devices/pc8080/machine/vt100/
machines:
- type: pc8080
id: vt100
debugger: true
- id: vt100
type: pc8080
---
DEC VT100 Terminal

View file

@ -3,8 +3,8 @@ layout: page
title: DEC VT100 Terminal with Debugger
permalink: /devices/pc8080/machine/vt100/debugger/
machines:
- type: pc8080
id: vt100
- id: vt100
type: pc8080
debugger: true
---
@ -51,6 +51,36 @@ keys. The following keys have special meaning inside SET-UP Mode.
- SHIFT-S: Save SET-UP Features
- SHIFT-R: Restore SET-UP Features
### SET-UP B Options
#### Block 1
- 1---: Smooth scroll
- -1--: Auto-Repeat
- --1-: Light Screen Background
- ---1: Block Cursor
#### Block 2
- 1---: Margin Bell
- -1--: Key-click
- --1-: ANSI
- ---1: Auto-XON/XOFF
#### Block 3
- 1---: UK Pound Symbol
- -1--: Wrap-Around
- --1-: New Line
- ---1: Interlace
#### Block 4
- 1---: Even Parity
- -1--: Parity Enable
- --1-: 8 Data Bits
- ---1: 50Hz Power
VT100 Memory Usage
------------------

View file

@ -27,7 +27,7 @@
<keyboard id="keyboard" model="VT100">
<control type="button" binding="setup" padleft="8px">SET-UP</control>
</keyboard>
<serial id="serial0" adapter="0">
<serial id="serialPort" adapter="0" binding="print">
<control type="button" binding="test" value="HELLO WORLD!\r\n" padleft="8px">TEST RECEIVER</control>
</serial>
<panel ref="/devices/pc8080/panel/wide.xml"/>

View file

@ -0,0 +1,27 @@
---
layout: page
title: Dual VT100 Terminals
permalink: /devices/pc8080/machine/vt100/dual/
machines:
- id: vt100a
type: pc8080
config: /devices/pc8080/machine/vt100/machine.xml
connection: serialPort=vt100b.serialPort
- id: vt100b
type: pc8080
config: /devices/pc8080/machine/vt100/machine.xml
connection: serialPort=vt100a.serialPort
---
Dual VT100 Terminals
--------------------
This is a test of two [VT100 Terminals](../) whose serial ports are *virtually* connected, so anything you type in the first
terminal should appear on the screen of the second, and vice versa. Click or tap on the screen of the desired terminal before
you begin typing.
If either terminal becomes LOCKED, press the SET-UP key (mapped to your F9 function key) twice to unlock it.
{% include machine.html id="vt100a" %}
{% include machine.html id="vt100b" %}

View file

@ -27,7 +27,7 @@
<keyboard id="keyboard" model="VT100">
<control type="button" binding="setup" padleft="8px" padbottom="8px">SET-UP</control>
</keyboard>
<serial id="serial0" adapter="0">
<serial id="serialPort" adapter="0">
<control type="button" binding="test" value="HELLO WORLD!\r\n" padleft="8px" padbottom="8px">TEST RECEIVER</control>
</serial>
</machine>

View file

@ -220,16 +220,16 @@ ChipSet.SI1978 = {
*/
ChipSet.VT100 = {
MODEL: 100.0,
FLAGS_BUFFER: {
FLAGS: {
PORT: 0x42, // read-only
XMIT: 0x01, // PUSART transmit buffer empty if SET
UART_XMIT: 0x01, // PUSART transmit buffer empty if SET
NO_AVO: 0x02, // AVO present if CLEAR
NO_GFX: 0x04, // VT125 graphics board present if CLEAR
OPTION: 0x08, // OPTION present if SET
NO_EVEN: 0x10, // EVEN FIELD active if CLEAR
NVR_DATA: 0x20, // NVR DATA if SET
NVR_CLK: 0x40, // NVR CLOCK if SET
KBD_XMIT: 0x80 // KBD XMIT BUFFER empty if SET
KBD_XMIT: 0x80 // KBD transmit buffer empty if SET
},
BRIGHTNESS: {
PORT: 0x42, // write-only
@ -424,6 +424,7 @@ ChipSet.prototype.initBus = function(cmp, bus, cpu, dbg)
this.dbg = dbg;
this.cmp = cmp;
this.kbd = /** @type {Keyboard} */ (cmp.getMachineComponent("Keyboard"));
this.serial = /** @type {SerialPort} */ (cmp.getMachineComponent("SerialPort"));
this.video = /** @type {Video} */ (cmp.getMachineComponent("Video"));
bus.addPortInputTable(this, this.config.portsInput);
bus.addPortOutputTable(this, this.config.portsOutput);
@ -474,7 +475,7 @@ ChipSet.SI1978.INIT = [
ChipSet.VT100.INIT = [
[
ChipSet.VT100.BRIGHTNESS.INIT,
ChipSet.VT100.FLAGS_BUFFER.NO_AVO | ChipSet.VT100.FLAGS_BUFFER.NO_GFX
ChipSet.VT100.FLAGS.NO_AVO | ChipSet.VT100.FLAGS.NO_GFX
],
[
ChipSet.VT100.DC011.INITCOLS,
@ -531,7 +532,7 @@ ChipSet.prototype.save = function()
state.set(0, [this.bStatus0, this.bStatus1, this.bStatus2, this.wShiftData, this.bShiftCount, this.bSound1, this.bSound2]);
break;
case ChipSet.VT100.MODEL:
state.set(0, [this.bBrightness, this.bFlagsBuffer]);
state.set(0, [this.bBrightness, this.bFlags]);
state.set(1, [this.bDC011Cols, this.bDC011Rate]);
state.set(2, [this.bDC012Scroll, this.bDC012Blink, this.bDC012Reverse, this.bDC012Attr]);
state.set(3, [this.dNVRAddr, this.wNVRData, this.bNVRLatch, this.bNVROut, this.aNVRWords]);
@ -565,7 +566,7 @@ ChipSet.prototype.restore = function(data)
return true;
case ChipSet.VT100.MODEL:
this.bBrightness = a[0];
this.bFlagsBuffer = a[1];
this.bFlags = a[1];
a = data[1];
this.bDC011Cols = a[0];
this.bDC011Rate = a[1];
@ -883,36 +884,40 @@ ChipSet.prototype.doNVRCommand = function()
};
/**
* inVT100FlagsBuffer(port, addrFrom)
* inVT100Flags(port, addrFrom)
*
* @this {ChipSet}
* @param {number} port (0x42)
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
* @return {number} simulated port value
*/
ChipSet.prototype.inVT100FlagsBuffer = function(port, addrFrom)
ChipSet.prototype.inVT100Flags = function(port, addrFrom)
{
/*
* The NVR_CLK bit is driven by LBA7 (ie, bit 7 from Line Buffer Address generation); see the DC011 discussion above.
*/
var b = this.bFlagsBuffer;
b &= ~ChipSet.VT100.FLAGS_BUFFER.NVR_CLK;
var b = this.bFlags;
b &= ~ChipSet.VT100.FLAGS.NVR_CLK;
if (this.getVT100LBA(7)) {
b |= ChipSet.VT100.FLAGS_BUFFER.NVR_CLK;
if (b != this.bFlagsBuffer) {
b |= ChipSet.VT100.FLAGS.NVR_CLK;
if (b != this.bFlags) {
this.doNVRCommand();
}
}
b &= ~ChipSet.VT100.FLAGS_BUFFER.NVR_DATA;
b &= ~ChipSet.VT100.FLAGS.NVR_DATA;
if (this.bNVROut) {
b |= ChipSet.VT100.FLAGS_BUFFER.NVR_DATA;
b |= ChipSet.VT100.FLAGS.NVR_DATA;
}
b &= ~ChipSet.VT100.FLAGS_BUFFER.KBD_XMIT;
if (this.kbd && !this.kbd.checkBusy()) {
b |= ChipSet.VT100.FLAGS_BUFFER.KBD_XMIT;
b &= ~ChipSet.VT100.FLAGS.KBD_XMIT;
if (this.kbd && this.kbd.isTransmitterReady()) {
b |= ChipSet.VT100.FLAGS.KBD_XMIT;
}
this.bFlagsBuffer = b;
this.printMessageIO(port, null, addrFrom, "FLAGS.BUFFER", b);
b &= ~ChipSet.VT100.FLAGS.UART_XMIT;
if (this.serial && this.serial.isTransmitterReady()) {
b |= ChipSet.VT100.FLAGS.UART_XMIT;
}
this.bFlags = b;
this.printMessageIO(port, null, addrFrom, "FLAGS", b);
return b;
};
@ -967,6 +972,7 @@ ChipSet.prototype.outVT100DC012 = function(port, b, addrFrom)
break;
case 0x1:
this.bDC012Scroll = (this.bDC012Scroll & ~0xC) | (bOpt << 2);
if (this.video) this.video.updateScrollOffset(this.bDC012Scroll);
break;
case 0x2:
switch(bOpt) {
@ -1013,7 +1019,7 @@ ChipSet.prototype.outVT100DC011 = function(port, b, addrFrom)
this.bDC011Cols = b;
if (this.video) {
var nCols = (this.bDC011Cols == ChipSet.VT100.DC011.COLS132? 132 : 80);
var nRows = (nCols > 80 && (this.bFlagsBuffer & ChipSet.VT100.FLAGS_BUFFER.NO_AVO)? 14 : 24);
var nRows = (nCols > 80 && (this.bFlags & ChipSet.VT100.FLAGS.NO_AVO)? 14 : 24);
this.video.updateDimensions(nCols, nRows);
}
}
@ -1039,7 +1045,7 @@ ChipSet.SI1978.portsOutput = {
};
ChipSet.VT100.portsInput = {
0x42: ChipSet.prototype.inVT100FlagsBuffer
0x42: ChipSet.prototype.inVT100Flags
};
ChipSet.VT100.portsOutput = {

View file

@ -870,17 +870,17 @@ Keyboard.prototype.checkSoftKeysToRelease = function()
};
/**
* checkBusy()
* isTransmitterReady()
*
* Called whenever a ChipSet circuit needs the keyboard's UART status.
* Currently, we have no busy conditions (our virtual keyboard is infinitely fast).
* Called whenever a ChipSet circuit needs the Keyboard UART's transmitter status.
* Currently, we have no busy conditions (our virtual keyboard transmitter is infinitely fast).
*
* @this {Keyboard}
* @return {boolean}
* @return {boolean} (true if ready, false if not)
*/
Keyboard.prototype.checkBusy = function()
Keyboard.prototype.isTransmitterReady = function()
{
return false;
return true;
};
/**

View file

@ -36,7 +36,6 @@ if (NODE) {
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var Messages = require("./messages");
var ChipSet = require("./chipset");
var State = require("./state");
}
@ -86,7 +85,7 @@ function SerialPort(parmsSerial) {
this.consoleOutput = null;
/**
* controlIOBuffer is a DOM element, if any, bound to the port (currently used for output only; see echoByte()).
* controlIOBuffer is a DOM element bound to the port (currently used for output only; see transmitByte()).
*
* @type {Object}
*/
@ -94,7 +93,7 @@ function SerialPort(parmsSerial) {
/*
* If controlIOBuffer is being used AND 'tabSize' is set, then we make an attempt to monitor the characters
* being echoed via echoByte(), maintain a logical column position, and convert any tabs into the appropriate
* being echoed via transmitByte(), maintain a logical column position, and convert any tabs into the appropriate
* number of spaces.
*
* charBOL, if nonzero, is a character to automatically output at the beginning of every line. This probably
@ -115,6 +114,27 @@ function SerialPort(parmsSerial) {
*/
Component.bindExternalControl(this, sBinding, SerialPort.sIOBuffer);
}
/*
* Define a setTimeout() function that receiveData() can use when there's more data to receive.
*/
this.fnCheckDataReceived = function(serial) {
return function() {
serial.receiveData();
}
}(this);
/*
* No connection until initBus() invokes initConnection().
*/
this.connection = this.sendByte = null;
/*
* Export all functions required by initConnection(); currently, this is the bare minimum, with no flow control.
*/
this['exports'] = {
'receiveByte': this.receiveByte
};
}
/*
@ -122,7 +142,7 @@ function SerialPort(parmsSerial) {
* property {number} iAdapter
* property {number} portBase
* property {number} nIRQ
* property {Object} controlIOBuffer is a DOM element, if any, bound to the port (for rudimentary output; see echoByte())
* property {Object} controlIOBuffer is a DOM element bound to the port (for rudimentary output; see transmitByte())
*
* NOTE: This class declaration started as a way of informing the code inspector of the controlIOBuffer property,
* which remained undefined until a setBinding() call set it later, but I've since decided that explicitly
@ -146,7 +166,7 @@ SerialPort.UART8251 = {
PARITY_ENABLE: 0x10,
EVEN_PARITY: 0x20,
STOP_BITS: 0xC0, // 00=invalid, 01=1, 10=1.5, 11=2
INIT: 0x8E // 16x baudrate, 8 data bits, no parity, 1.5 stop bits
INIT: 0x8E // 16x baud rate, 8 data bits, no parity, 1.5 stop bits
},
/*
* Format of COMMAND byte written to CONTROL port 0x1
@ -177,9 +197,10 @@ SerialPort.UART8251 = {
INIT: 0x85 // XMIT_READY | XMIT_EMPTY | DSR
},
/*
* Format of BAUDRATE byte written to port 0x2
* Format of BAUDRATES byte written to port 0x2
*
* Each nibble is an index (0x0-0xF) into a set internal CPU clock divisors that yield the following baud rates:
* Each nibble is an index (0x0-0xF) into a set of internal CPU clock divisors that yield the
* following baud rates:
*
* Index Divisor Baud Rate
* ----- ------- ---------
@ -199,15 +220,15 @@ SerialPort.UART8251 = {
* 0xD 36 4800
* 0xE 18 9600 (default)
* 0xF 9 19200
*
* TODO: I'm not really sure at this point which nibble is for the XMIT rate and which is for the RECV
* rate; I just made a random guess.
*/
BAUDRATE: {
XMIT_RATE: 0x0F,
RECV_RATE: 0xF0,
BAUDRATES: {
RECV_RATE: 0x0F,
XMIT_RATE: 0xF0,
INIT: 0xEE // default to 9600 (0xE) for both XMIT and RECV
}
},
BAUDTABLE: [
50, 75, 110, 134.5, 150, 200, 300, 600, 1200, 1800, 2000, 2400, 3600, 4800, 9600, 19200
]
};
SerialPort.UART8251.INIT = [
@ -217,7 +238,7 @@ SerialPort.UART8251.INIT = [
SerialPort.UART8251.STATUS.INIT,
SerialPort.UART8251.MODE.INIT,
SerialPort.UART8251.COMMAND.INIT,
SerialPort.UART8251.BAUDRATE.INIT
SerialPort.UART8251.BAUDRATES.INIT
];
/*
@ -272,7 +293,7 @@ SerialPort.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
if (keyCode === 0x08 || event.ctrlKey && keyCode >= 0x41 && keyCode <= 0x5A) {
if (event.preventDefault) event.preventDefault();
if (keyCode > 0x40) keyCode -= 0x40;
serial.sendByteIn(keyCode);
serial.receiveByte(keyCode);
}
return true;
};
@ -284,7 +305,7 @@ SerialPort.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
*/
event = event || window.event;
var keyCode = event.which || event.keyCode;
// serial.sendRBR([keyCode]);
serial.receiveByte(keyCode);
/*
* Since we're going to remove the "readonly" attribute from the <textarea> control
* (so that the soft keyboard activates on iOS), instead of calling preventDefault() for
@ -317,8 +338,8 @@ SerialPort.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
*/
sValue = sValue.replace(/\\n/g, "\n").replace(/\\r/g, "\r");
control.onclick = function onClickTest(event) {
serial.sDataIn = sValue;
serial.sendDataIn();
serial.sDataReceived = sValue;
serial.receiveData();
/*
* Give focus back to the machine (since clicking the button takes focus away).
*/
@ -350,9 +371,47 @@ SerialPort.prototype.initBus = function(cmp, bus, cpu, dbg)
this.chipset = /** @type {ChipSet} */ (cmp.getMachineComponent("ChipSet"));
bus.addPortInputTable(this, SerialPort.aPortInput, this.portBase);
bus.addPortOutputTable(this, SerialPort.aPortOutput, this.portBase);
this.initConnection();
this.setReady();
};
/**
* initConnection()
*
* If a machine 'connection' parameter exists of the form "<sourcePort>=<targetMachine>.<targetPort>",
* and "<sourcePort>" matches our idComponent, then look for a component with id "<targetMachine>.<targetPort>".
*
* If the target component is found, then verify that it has exported functions with the following names:
*
* receiveByte(b): called by us when we have a byte to transmit; aliased internally to sendByte(b)
*
* For now, we're not going to worry about communication in the other direction, because when the target component
* performs its own initConnection(), it will find our receiveByte(b) function, at which point communication in both
* directions should be established.
*
* @this {SerialPort}
*/
SerialPort.prototype.initConnection = function()
{
var sConnection = this.cmp.getMachineParm("connection");
if (sConnection) {
var asParts = sConnection.split('=');
if (asParts.length == 2) {
var sSourceID = str.trim(asParts[0]);
var sTargetID = str.trim(asParts[1]);
if (sSourceID == this.idComponent) {
this.connection = Component.getComponentByID(sTargetID);
if (this.connection) {
var exports = this.connection['exports'];
if (exports) {
this.sendByte = exports['receiveByte'];
}
}
}
}
}
};
/**
* powerUp(data, fRepower)
*
@ -444,7 +503,7 @@ SerialPort.prototype.initState = function(data)
this.bStatus = data[i++];
this.bMode = data[i++];
this.bCommand = data[i++];
this.bBaudRate = data[i];
this.bBaudRates = data[i];
return true;
};
@ -464,18 +523,37 @@ SerialPort.prototype.saveRegisters = function()
data[i++] = this.bStatus;
data[i++] = this.bMode;
data[i++] = this.bCommand;
data[i] = this.bBaudRate;
data[i] = this.bBaudRates;
return data;
};
/**
* sendByteIn(b)
* getBaudTimeout(maskRate)
*
* @this {SerialPort}
* @param {number} maskRate (either SerialPort.UART8251.BAUDRATES.RECV_RATE or SerialPort.UART8251.BAUDRATES.XMIT_RATE)
* @return {number} (number of milliseconds per byte)
*/
SerialPort.prototype.getBaudTimeout = function(maskRate)
{
var indexRate = (this.bBaudRates & maskRate);
if (!(maskRate & 0xf)) indexRate >>= 4;
var nBaud = SerialPort.UART8251.BAUDTABLE[indexRate];
var nBits = ((this.bMode & SerialPort.UART8251.MODE.DATA_BITS) >> 2) + 6; // includes an extra +1 for start bit
if (this.bMode & SerialPort.UART8251.MODE.PARITY_ENABLE) nBits++;
nBits += ((((this.bMode & SerialPort.UART8251.MODE.STOP_BITS) >> 6) + 1) >> 1);
var nBytesPerSecond = Math.round(nBaud / nBits);
return 1000 / nBytesPerSecond;
};
/**
* receiveByte(b)
*
* @this {SerialPort}
* @param {number} b
* @return {boolean}
*/
SerialPort.prototype.sendByteIn = function(b)
SerialPort.prototype.receiveByte = function(b)
{
if (!(this.bStatus & SerialPort.UART8251.STATUS.RECV_FULL)) {
this.bDataIn = b;
@ -487,28 +565,52 @@ SerialPort.prototype.sendByteIn = function(b)
};
/**
* sendDataIn()
* receiveData()
*
* @this {SerialPort}
*/
SerialPort.prototype.sendDataIn = function()
SerialPort.prototype.receiveData = function()
{
if (this.sDataIn) {
if (this.sendByteIn(this.sDataIn.charCodeAt(0))) {
this.sDataIn = this.sDataIn.substr(1);
if (this.sDataReceived) {
if (this.receiveByte(this.sDataReceived.charCodeAt(0))) {
this.sDataReceived = this.sDataReceived.substr(1);
}
/*
* TODO: If data has become undeliverable for some reason (eg, the Debugger has paused execution),
* we should stop setting timeouts, and add one or more notification mechanisms to kickstart it again.
*/
if (this.sDataReceived) {
/*
* TODO: setTimeout() is a less-than-ideal solution, because it's too slow; timeouts won't fire until
* the end of a CPU burst. So instead of calculating a number of milliseconds, we should calculate a
* number of CPU cycles, and create a CPU notification mechanism that calls us back after that many cycles
* have elapsed (and which will automatically shorten the current CPU burst as needed).
*
* This will also solve the other issue noted above, because if the CPU has been halted, it won't be
* generating any notifications either.
*/
setTimeout(this.fnCheckDataReceived, this.getBaudTimeout(SerialPort.UART8251.BAUDRATES.RECV_RATE));
}
}
};
/**
* echoByte(b)
* transmitByte(b)
*
* @this {SerialPort}
* @param {number} b
* @return {boolean} true if echoed, false if not
* @return {boolean} true if transmitted, false if not
*/
SerialPort.prototype.echoByte = function(b)
SerialPort.prototype.transmitByte = function(b)
{
var fTransmitted = false;
if (this.sendByte) {
if (this.sendByte.call(this.connection, b)) {
fTransmitted = true;
}
}
if (this.controlIOBuffer) {
if (b == 0x0D) {
this.iLogicalCol = 0;
@ -533,9 +635,9 @@ SerialPort.prototype.echoByte = function(b)
this.controlIOBuffer.scrollTop = this.controlIOBuffer.scrollHeight;
this.iLogicalCol += nChars;
}
return true;
fTransmitted = true;
}
if (this.consoleOutput != null) {
else if (this.consoleOutput != null) {
if (b == 0x0A || this.consoleOutput.length >= 1024) {
this.println(this.consoleOutput);
this.consoleOutput = "";
@ -543,9 +645,23 @@ SerialPort.prototype.echoByte = function(b)
if (b != 0x0A) {
this.consoleOutput += String.fromCharCode(b);
}
return true;
fTransmitted = true;
}
return false;
return fTransmitted;
};
/**
* isTransmitterReady()
*
* Called whenever a ChipSet circuit needs the SerialPort UART's transmitter status.
*
* @this {SerialPort}
* @return {boolean} (true if ready, false if not)
*/
SerialPort.prototype.isTransmitterReady = function()
{
return !!(this.bStatus & SerialPort.UART8251.STATUS.XMIT_READY);
};
/**
@ -561,7 +677,6 @@ SerialPort.prototype.inData = function(port, addrFrom)
var b = this.bDataIn;
this.printMessageIO(port, null, addrFrom, "DATA", b);
this.bStatus &= ~SerialPort.UART8251.STATUS.RECV_FULL;
this.sendDataIn(); // if there is still queued incoming data, send another byte
return b;
};
@ -592,6 +707,10 @@ SerialPort.prototype.outData = function(port, bOut, addrFrom)
{
this.printMessageIO(port, bOut, addrFrom, "DATA");
this.bDataOut = bOut;
this.bStatus &= ~(SerialPort.UART8251.STATUS.XMIT_READY | SerialPort.UART8251.STATUS.XMIT_EMPTY);
if (this.transmitByte(bOut)) {
this.bStatus |= (SerialPort.UART8251.STATUS.XMIT_READY | SerialPort.UART8251.STATUS.XMIT_EMPTY);
}
};
/**
@ -622,17 +741,17 @@ SerialPort.prototype.outControl = function(port, bOut, addrFrom)
};
/**
* outBaudRate(port, bOut, addrFrom)
* outBaudRates(port, bOut, addrFrom)
*
* @this {SerialPort}
* @param {number} port (0x2)
* @param {number} bOut
* @param {number} [addrFrom] (not defined whenever the Debugger tries to write the specified port)
*/
SerialPort.prototype.outBaudRate = function(port, bOut, addrFrom)
SerialPort.prototype.outBaudRates = function(port, bOut, addrFrom)
{
this.printMessageIO(port, bOut, addrFrom, "BAUDRATE");
this.bBaudRate = bOut;
this.printMessageIO(port, bOut, addrFrom, "BAUDRATES");
this.bBaudRates = bOut;
};
/*
@ -650,7 +769,7 @@ SerialPort.aPortInput = {
SerialPort.aPortOutput = {
0x0: SerialPort.prototype.outData,
0x1: SerialPort.prototype.outControl,
0x2: SerialPort.prototype.outBaudRate
0x2: SerialPort.prototype.outBaudRates
};
/**

View file

@ -154,7 +154,10 @@ function Video(parmsVideo, canvas, context, textarea, container)
* Now that we've finished using nRowsBuffer to help define the screen size, we add one more
* row for text modes, to account for the VT100's scroll line buffer (used for smooth scrolling).
*/
if (this.cyCell > 1) this.nRowsBuffer++;
if (this.cyCell > 1) {
this.nRowsBuffer++;
this.bScrollOffset = 0;
}
/*
* Support for disabling (or, less commonly, enabling) image smoothing, which all browsers
@ -762,6 +765,23 @@ Video.prototype.updateRate = function(nRate)
this.rateMonitor = nRate;
};
/**
* updateScrollOffset(bScroll)
*
* Called from the ChipSet component whenever the screen scroll offset has been dynamically altered.
*
* @this {Video}
* @param {number} bScroll
*/
Video.prototype.updateScrollOffset = function(bScroll)
{
this.printMessage("updateScrollOffset(" + bScroll + ")");
if (this.bScrollOffset !== bScroll) {
this.bScrollOffset = bScroll;
this.updateScreen(-1);
}
};
/**
* doFullScreen()
*
@ -1091,6 +1111,8 @@ Video.prototype.updateVT100 = function(fForced)
nRows++;
}
this.fCellCacheValid = true;
this.assert(font < 0 || iCell === this.nCellCache);
if (MAXDEBUG && !fForced) {
@ -1103,14 +1125,23 @@ Video.prototype.updateVT100 = function(fForced)
this.printMessage("updateVT100(): update #" + this.nUpdateNumber + " at " +this.nUpdateSeconds + " corner=" + str.toHexByte(this.aCellCache[1]) + " cycles=" + this.nCyclesPrev + " delta=" + this.nCyclesDelta);
}
this.fCellCacheValid = true;
if (cUpdated && this.contextBuffer) {
if ((cUpdated || fForced) && this.contextBuffer) {
/*
* NOTE: We must subtract cyCell from cyBuffer to avoid displaying the extra "scroll line" that we normally
* buffer to support smooth-scrolling.
* We must subtract cyCell from cyBuffer to avoid displaying the extra "scroll line" that we normally
* buffer, in support of smooth scrolling. Speaking of which, we must also add bScrollOffset to ySrc
* (well, ySrc is always relative to zero, so no add is actually required).
*/
this.contextScreen.drawImage(this.canvasBuffer, 0, 0, this.cxBuffer, this.cyBuffer - this.cyCell, this.xScreenOffset, this.yScreenOffset, this.cxScreenOffset, this.cyScreenOffset);
this.contextScreen.drawImage(
this.canvasBuffer,
0, // xSrc
this.bScrollOffset, // ySrc
this.cxBuffer, // cxSrc
this.cyBuffer - this.cyCell, // cySrc
this.xScreenOffset, // xDst
this.yScreenOffset, // yDst
this.cxScreenOffset, // cxDst
this.cyScreenOffset // cyDst
);
}
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long