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
|
|
@ -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
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in a new issue