Enabled smooth scrolling, connected SerialPort UART transmitter status to the ChipSet FLAGS buffer (matching how the Keyboard UART transmitter status is connected), enabled binding of terminal I/O to the Control Panel output window (if any), and added simulation of received data at the programmed baud rate (but a better solution has been noted and needs to be implemented)
This commit is contained in:
parent
f9e3c55224
commit
cf24023d5d
8 changed files with 609 additions and 477 deletions
|
|
@ -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]);
|
||||
|
|
@ -555,31 +556,31 @@ ChipSet.prototype.restore = function(data)
|
|||
if (data && (a = data[0]) && a.length) {
|
||||
switch(this.config.MODEL) {
|
||||
case ChipSet.SI1978.MODEL:
|
||||
this.bStatus0 = a[0];
|
||||
this.bStatus1 = a[1];
|
||||
this.bStatus2 = a[2];
|
||||
this.wShiftData = a[3];
|
||||
this.bShiftCount = a[4];
|
||||
this.bSound1 = a[5];
|
||||
this.bSound2 = a[6];
|
||||
this.bStatus0 = a[0];
|
||||
this.bStatus1 = a[1];
|
||||
this.bStatus2 = a[2];
|
||||
this.wShiftData = a[3];
|
||||
this.bShiftCount = a[4];
|
||||
this.bSound1 = a[5];
|
||||
this.bSound2 = a[6];
|
||||
return true;
|
||||
case ChipSet.VT100.MODEL:
|
||||
this.bBrightness = a[0];
|
||||
this.bFlagsBuffer = a[1];
|
||||
this.bBrightness = a[0];
|
||||
this.bFlags = a[1];
|
||||
a = data[1];
|
||||
this.bDC011Cols = a[0];
|
||||
this.bDC011Rate = a[1];
|
||||
this.bDC011Cols = a[0];
|
||||
this.bDC011Rate = a[1];
|
||||
a = data[2];
|
||||
this.bDC012Scroll = a[0];
|
||||
this.bDC012Blink = a[1];
|
||||
this.bDC012Scroll = a[0];
|
||||
this.bDC012Blink = a[1];
|
||||
this.bDC012Reverse = a[2];
|
||||
this.bDC012Attr = a[3];
|
||||
this.bDC012Attr = a[3];
|
||||
a = data[3];
|
||||
this.dNVRAddr = a[0]; // 20-bit address
|
||||
this.wNVRData = a[1]; // 14-bit word
|
||||
this.bNVRLatch = a[2]; // 1 byte
|
||||
this.bNVROut = a[3]; // 1 bit
|
||||
this.aNVRWords = a[4]; // 100 14-bit words
|
||||
this.dNVRAddr = a[0]; // 20-bit address
|
||||
this.wNVRData = a[1]; // 14-bit word
|
||||
this.bNVRLatch = a[2]; // 1 byte
|
||||
this.bNVROut = a[3]; // 1 bit
|
||||
this.aNVRWords = a[4]; // 100 14-bit words
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
@ -115,6 +114,15 @@ 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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -146,7 +154,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 +185,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 +208,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 +226,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 +281,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 +293,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 +326,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).
|
||||
*/
|
||||
|
|
@ -444,7 +453,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 +473,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,15 +515,31 @@ 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));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -548,6 +592,19 @@ SerialPort.prototype.echoByte = function(b)
|
|||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
};
|
||||
|
||||
/**
|
||||
* inData(port, addrFrom)
|
||||
*
|
||||
|
|
@ -561,7 +618,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 +648,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.echoByte(bOut)) {
|
||||
this.bStatus |= (SerialPort.UART8251.STATUS.XMIT_READY | SerialPort.UART8251.STATUS.XMIT_EMPTY);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -622,17 +682,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 +710,7 @@ SerialPort.aPortInput = {
|
|||
SerialPort.aPortOutput = {
|
||||
0x0: SerialPort.prototype.outData,
|
||||
0x1: SerialPort.prototype.outControl,
|
||||
0x2: SerialPort.prototype.outBaudRate
|
||||
0x2: SerialPort.prototype.outBaudRates
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue