Merge branch 'next-release'
This commit is contained in:
commit
c349a56218
13 changed files with 962 additions and 559 deletions
|
|
@ -235,24 +235,52 @@ ChipSet.VT100 = {
|
|||
PORT: 0x42, // write-only
|
||||
INIT: 0x00 // for lack of a better guess
|
||||
},
|
||||
NVR: {
|
||||
LATCH: {
|
||||
PORT: 0x62 // write-only
|
||||
},
|
||||
CMD: {
|
||||
ACCEPT_DATA: 0x0,
|
||||
ACCEPT_ADDR: 0x1,
|
||||
SHIFT_OUT: 0x2,
|
||||
WRITE: 0x4,
|
||||
ERASE: 0x5,
|
||||
READ: 0x6,
|
||||
STANDBY: 0x7
|
||||
},
|
||||
WORDMASK: 0x3fff // NVR words are 14-bit
|
||||
/*
|
||||
* The Technical Manual, p. 4-18, also notes that "Early VT100s can disable the receiver interrupt by
|
||||
* programming D4 in the NVR latch. However, this is never used by the VT100."
|
||||
*/
|
||||
/*
|
||||
* DC011 is referred to as a Timing Chip.
|
||||
*
|
||||
* As p. 4-55 (105) of the VT100 Technical Manual (July 1982) explains:
|
||||
*
|
||||
* The DCO11 is a custom designed bipolar circuit that provides most of the timing signals required by the
|
||||
* video processor. Internal counters divide the output of a 24.0734 MHz oscillator (located elsewhere on the
|
||||
* terminal controller module) into the lower frequencies that define dot, character, scan, and frame timing.
|
||||
* The counters are programmable through various input pins to control the number of characters per line,
|
||||
* the frequency at which the screen is refreshed, and whether the display is interlaced or noninterlaced.
|
||||
* These parameters can be controlled through SET-UP mode or by the host.
|
||||
*
|
||||
* Table 4-6-1: Video Mode Selection (Write Address 0xC2)
|
||||
*
|
||||
* D5 D4 Configuration
|
||||
* -- -- -------------
|
||||
* 0 0 80-column mode, interlaced
|
||||
* 0 1 132-column mode, interlaced
|
||||
* 1 0 60Hz, non-interlaced
|
||||
* 1 1 50Hz, non-interlaced
|
||||
*
|
||||
* On p. 4-56, the DC011 Block Diagram shows 8 outputs labeled LBA0 through LBA7. From p. 4-61:
|
||||
*
|
||||
* Several of the LBAs are used as general purpose clocks in the VT100. LBA 3 and LBA 4 are used to generate
|
||||
* timing for the keyboard. These signals satisfy the keyboard's requirement of two square-waves, one twice the
|
||||
* frequency of the other, even though every 16th transition is delayed (the second stage of the horizontal
|
||||
* counter divides by 17, not 16). LBA 7 is used by the nonvolatile RAM.
|
||||
*
|
||||
* And on p. 4-62, timings are provided for the LBA0 through LBA7 when the VT100 is in 80-column mode; in particular:
|
||||
*
|
||||
* LBA6: 16.82353us (when LBA6 is low, for a period of 33.64706us)
|
||||
* LBA7: 31.77778us (when LBA7 is high, for a period of 63.55556us)
|
||||
*
|
||||
* If we assume that the CPU cycle count increments once every 361.69ns, it will increment roughly 88 times every
|
||||
* time LBA7 toggles. So we can divide the CPU cycle count by 88 and set LBA to the low bit of that truncated
|
||||
* result. An even faster (but less accurate) solution would be to mask bit 6 of the CPU cycle count, which will
|
||||
* doesn't change until the count has been incremented 64 times. See getVT100LBA() for the chosen implementation.
|
||||
*/
|
||||
DC011: { // generates Line Buffer Addresses (LBAs) for the Video Processor
|
||||
PORT: 0xC2, // write-only
|
||||
COLS80: 0x00,
|
||||
COLS132: 0x10,
|
||||
RATE60: 0x20,
|
||||
RATE50: 0x30,
|
||||
INITCOLS: 0x00, // ie, COLS80
|
||||
INITRATE: 0x20 // ie, RATE60
|
||||
},
|
||||
/*
|
||||
* DC012 is referred to as a Control Chip.
|
||||
|
|
@ -302,40 +330,33 @@ ChipSet.VT100 = {
|
|||
*/
|
||||
DC012: { // generates scan counts for the Video Processor
|
||||
PORT: 0xA2, // write-only
|
||||
INIT: 0x00 // for lack of a better guess
|
||||
SCROLL_LO: 0x00,
|
||||
INITSCROLL: 0x00,
|
||||
INITBLINK: 0x00,
|
||||
INITREVERSE:0x00,
|
||||
INITATTR: 0x00
|
||||
},
|
||||
/*
|
||||
* DC011 is referred to as a Timing Chip.
|
||||
*
|
||||
* As p. 4-55 (105) of the VT100 Technical Manual (July 1982) explains:
|
||||
*
|
||||
* The DCO11 is a custom designed bipolar circuit that provides most of the timing signals required by the
|
||||
* video processor. Internal counters divide the output of a 24.0734 MHz oscillator (located elsewhere on the
|
||||
* terminal controller module) into the lower frequencies that define dot, character, scan, and frame timing.
|
||||
* The counters are programmable through various input pins to control the number of characters per line,
|
||||
* the frequency at which the screen is refreshed, and whether the display is interlaced or noninterlaced.
|
||||
* These parameters can be controlled through SET-UP mode or by the host.
|
||||
*
|
||||
* On p. 4-56, the DC011 Block Diagram shows 8 outputs labeled LBA0 through LBA7. From p. 4-61:
|
||||
*
|
||||
* Several of the LBAs are used as general purpose clocks in the VT100. LBA 3 and LBA 4 are used to generate
|
||||
* timing for the keyboard. These signals satisfy the keyboard's requirement of two square-waves, one twice the
|
||||
* frequency of the other, even though every 16th transition is delayed (the second stage of the horizontal
|
||||
* counter divides by 17, not 16). LBA 7 is used by the nonvolatile RAM.
|
||||
*
|
||||
* And on p. 4-62, timings are provided for the LBA0 through LBA7 when the VT100 is in 80-column mode; in particular:
|
||||
*
|
||||
* LBA6: 16.82353us (when LBA6 is low, for a period of 33.64706us)
|
||||
* LBA7: 31.77778us (when LBA7 is high, for a period of 63.55556us)
|
||||
*
|
||||
* If we assume that the CPU cycle count increments once every 361.69ns, it will increment roughly 88 times every
|
||||
* time LBA7 toggles. So we can divide the CPU cycle count by 88 and set LBA to the low bit of that truncated
|
||||
* result. An even faster (but less accurate) solution would be to mask bit 6 of the CPU cycle count, which will
|
||||
* doesn't change until the count has been incremented 64 times. See getVT100LBA() for the chosen implementation.
|
||||
* ER1400 Non-Volatile RAM (NVR) Chip Definitions
|
||||
*/
|
||||
DC011: { // generates Line Buffer Addresses (LBAs) for the Video Processor
|
||||
PORT: 0xC2, // write-only
|
||||
INIT: 0x00 // for lack of a better guess
|
||||
NVR: {
|
||||
LATCH: {
|
||||
PORT: 0x62 // write-only
|
||||
},
|
||||
CMD: {
|
||||
ACCEPT_DATA: 0x0,
|
||||
ACCEPT_ADDR: 0x1,
|
||||
SHIFT_OUT: 0x2,
|
||||
WRITE: 0x4,
|
||||
ERASE: 0x5,
|
||||
READ: 0x6,
|
||||
STANDBY: 0x7
|
||||
},
|
||||
WORDMASK: 0x3fff // NVR words are 14-bit
|
||||
/*
|
||||
* The Technical Manual, p. 4-18, also notes that "Early VT100s can disable the receiver interrupt by
|
||||
* programming D4 in the NVR latch. However, this is never used by the VT100."
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -402,7 +423,8 @@ ChipSet.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
this.cpu = cpu;
|
||||
this.dbg = dbg;
|
||||
this.cmp = cmp;
|
||||
this.kbd = cmp.getMachineComponent("Keyboard");
|
||||
this.kbd = /** @type {Keyboard} */ (cmp.getMachineComponent("Keyboard"));
|
||||
this.video = /** @type {Video} */ (cmp.getMachineComponent("Video"));
|
||||
bus.addPortInputTable(this, this.config.portsInput);
|
||||
bus.addPortOutputTable(this, this.config.portsOutput);
|
||||
};
|
||||
|
|
@ -452,9 +474,17 @@ ChipSet.SI1978.INIT = [
|
|||
ChipSet.VT100.INIT = [
|
||||
[
|
||||
ChipSet.VT100.BRIGHTNESS.INIT,
|
||||
ChipSet.VT100.FLAGS_BUFFER.NO_AVO | ChipSet.VT100.FLAGS_BUFFER.NO_GFX,
|
||||
ChipSet.VT100.DC012.INIT,
|
||||
ChipSet.VT100.DC011.INIT
|
||||
ChipSet.VT100.FLAGS_BUFFER.NO_AVO | ChipSet.VT100.FLAGS_BUFFER.NO_GFX
|
||||
],
|
||||
[
|
||||
ChipSet.VT100.DC011.INITCOLS,
|
||||
ChipSet.VT100.DC011.INITRATE
|
||||
],
|
||||
[
|
||||
ChipSet.VT100.DC012.INITSCROLL,
|
||||
ChipSet.VT100.DC012.INITBLINK,
|
||||
ChipSet.VT100.DC012.INITREVERSE,
|
||||
ChipSet.VT100.DC012.INITATTR
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0,
|
||||
|
|
@ -501,8 +531,10 @@ 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, this.bDC012, this.bDC011]);
|
||||
state.set(1, [this.dNVRAddr, this.wNVRData, this.bNVRLatch, this.bNVROut, this.aNVRWords]);
|
||||
state.set(0, [this.bBrightness, this.bFlagsBuffer]);
|
||||
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]);
|
||||
break;
|
||||
}
|
||||
return state.data();
|
||||
|
|
@ -534,9 +566,15 @@ ChipSet.prototype.restore = function(data)
|
|||
case ChipSet.VT100.MODEL:
|
||||
this.bBrightness = a[0];
|
||||
this.bFlagsBuffer = a[1];
|
||||
this.bDC012 = a[2];
|
||||
this.bDC011 = a[3];
|
||||
a = data[1];
|
||||
this.bDC011Cols = a[0];
|
||||
this.bDC011Rate = a[1];
|
||||
a = data[2];
|
||||
this.bDC012Scroll = a[0];
|
||||
this.bDC012Blink = a[1];
|
||||
this.bDC012Reverse = a[2];
|
||||
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
|
||||
|
|
@ -909,9 +947,8 @@ ChipSet.prototype.outVT100NVRLatch = function(port, b, addrFrom)
|
|||
/**
|
||||
* outVT100DC012(port, b, addrFrom)
|
||||
*
|
||||
* TODO: Consider whether we should disable any interrupts (eg, vertical retrace) until the
|
||||
* this port is initialized at runtime. We initialize it ourselves at start-up, but our initial
|
||||
* value is just a guess.
|
||||
* TODO: Consider whether we should disable any interrupts (eg, vertical retrace) until
|
||||
* this port is initialized at runtime.
|
||||
*
|
||||
* @this {ChipSet}
|
||||
* @param {number} port (0xA2)
|
||||
|
|
@ -921,7 +958,34 @@ ChipSet.prototype.outVT100NVRLatch = function(port, b, addrFrom)
|
|||
ChipSet.prototype.outVT100DC012 = function(port, b, addrFrom)
|
||||
{
|
||||
this.printMessageIO(port, b, addrFrom, "DC012");
|
||||
this.bDC012 = b;
|
||||
|
||||
var bOpt = b & 0x3;
|
||||
var bCmd = (b >> 2) & 0x3;
|
||||
switch(bCmd) {
|
||||
case 0x0:
|
||||
this.bDC012Scroll = (this.bDC012Scroll & ~0x3) | bOpt;
|
||||
break;
|
||||
case 0x1:
|
||||
this.bDC012Scroll = (this.bDC012Scroll & ~0xC) | (bOpt << 2);
|
||||
break;
|
||||
case 0x2:
|
||||
switch(bOpt) {
|
||||
case 0x0:
|
||||
this.bDC012Blink = ~this.bDC012Blink;
|
||||
break;
|
||||
case 0x1:
|
||||
// TODO: Clear vertical frequency interrupt
|
||||
break;
|
||||
case 0x2:
|
||||
case 0x3:
|
||||
this.bDC012Reverse = 0x3 - bOpt;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x3:
|
||||
this.bDC012Attr = bOpt;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -935,7 +999,25 @@ ChipSet.prototype.outVT100DC012 = function(port, b, addrFrom)
|
|||
ChipSet.prototype.outVT100DC011 = function(port, b, addrFrom)
|
||||
{
|
||||
this.printMessageIO(port, b, addrFrom, "DC011");
|
||||
this.bDC011 = b;
|
||||
if (b & ChipSet.VT100.DC011.RATE60) {
|
||||
b &= ChipSet.VT100.DC011.RATE50;
|
||||
if (this.bDC011Rate != b) {
|
||||
this.bDC011Rate = b;
|
||||
if (this.video) {
|
||||
this.video.updateRate(this.bDC011Rate == ChipSet.VT100.DC011.RATE50? 50 : 60);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
b &= ChipSet.VT100.DC011.COLS132;
|
||||
if (this.bDC011Cols != b) {
|
||||
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);
|
||||
this.video.updateDimensions(nCols, nRows);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -176,13 +176,13 @@ CPU.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
/*
|
||||
* We need to know the refresh rate (and corresponding interrupt rate, if any) of the Video component.
|
||||
*/
|
||||
var video = cmp.getMachineComponent("Video");
|
||||
var video = /** @type {Video} */ (cmp.getMachineComponent("Video"));
|
||||
this.refreshRate = video && video.getRefreshRate() || CPU.VIDEO_UPDATES_PER_SECOND;
|
||||
|
||||
/*
|
||||
* Attach the ChipSet component to the CPU so that it can be notified whenever the CPU stops and starts.
|
||||
*/
|
||||
this.chipset = cmp.getMachineComponent("ChipSet");
|
||||
this.chipset = /** @type {ChipSet} */ (cmp.getMachineComponent("ChipSet"));
|
||||
|
||||
/*
|
||||
* We've already saved the parmsCPU 'autoStart' setting, but there may be a machine (or URL) override.
|
||||
|
|
|
|||
|
|
@ -72,9 +72,9 @@ Component.subclass(Keyboard);
|
|||
/**
|
||||
* Alphanumeric and other common (printable) ASCII codes.
|
||||
*
|
||||
* TODO: Determine what we can do to get ALL constants like these inlined (enum doesn't seem to
|
||||
* get the job done); the problem seems to be limited to property references that use quotes, which
|
||||
* is why I've 'unquoted' as many of them as possible.
|
||||
* TODO: Determine what we can do to get ALL constants like these inlined by the Closure Compiler
|
||||
* (enum doesn't seem to get the job done); the problem seems to be limited to property references
|
||||
* that use quotes, which is why I've 'unquoted' as many of them as possible.
|
||||
*
|
||||
* @enum {number}
|
||||
*/
|
||||
|
|
@ -101,8 +101,8 @@ Keyboard.ASCII = {
|
|||
*
|
||||
* keyCodes for most common ASCII keys can simply use the appropriate ASCII code above.
|
||||
*
|
||||
* Most of these represent non-ASCII keys (eg, the LEFT arrow key), yet for some reason, browsers defined
|
||||
* them using ASCII codes (eg, the LEFT arrow key uses the ASCII code for '%' or 37).
|
||||
* Most of these represent non-ASCII characters (eg, the LEFT arrow key), yet for some reason, browsers
|
||||
* defined them using ASCII codes (eg, the LEFT arrow key uses 37, which is the ASCII code for '%').
|
||||
*
|
||||
* @enum {number}
|
||||
*/
|
||||
|
|
@ -282,13 +282,15 @@ Keyboard.VT100 = {
|
|||
KEYMAP: {},
|
||||
ALTCODES: {},
|
||||
LEDCODES: {},
|
||||
SOFTCODES: {},
|
||||
SOFTCODES: {
|
||||
'setup': Keyboard.KEYCODE.F9
|
||||
},
|
||||
/*
|
||||
* Reading port 0x82 returns a key address from the VT100 keyboard's UART data output.
|
||||
*
|
||||
* Every time a keyboard scan is initiated (by setting the START bit of the status byte),
|
||||
* an internal address index is reset to zero, and an interrupt is generated for each entry
|
||||
* in the aKeysActive array, along with a final interrupt for KEYLAST.
|
||||
* our internal address index (iKeyNext) is set to zero, and an interrupt is generated for
|
||||
* each entry in the aKeysActive array, along with a final interrupt for KEYLAST.
|
||||
*/
|
||||
ADDRESS: {
|
||||
PORT: 0x82,
|
||||
|
|
@ -320,9 +322,12 @@ Keyboard.VT100 = {
|
|||
CLICK: 0x80,
|
||||
INIT: 0x00
|
||||
},
|
||||
KEYLAST: 0x7F
|
||||
KEYLAST: 0x7F // special end-of-scan key address (all valid key addresses are < KEYLAST)
|
||||
};
|
||||
|
||||
/*
|
||||
* Table to map host key codes to VT100 key addresses (ie, unique 7-bit values representing key positions on the VT100)
|
||||
*/
|
||||
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.DEL] = 0x03;
|
||||
Keyboard.VT100.KEYMAP[Keyboard.ASCII.P] = 0x05;
|
||||
Keyboard.VT100.KEYMAP[Keyboard.ASCII.O] = 0x06;
|
||||
|
|
@ -486,16 +491,25 @@ Keyboard.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
|||
default:
|
||||
if (this.config.SOFTCODES && this.config.SOFTCODES[sBinding] !== undefined) {
|
||||
this.bindings[id] = control;
|
||||
var fnDown = function(kbd, sSoftCode) {
|
||||
return function onMouseOrTouchDownKeyboard(event) {
|
||||
kbd.onSoftKeyDown(sSoftCode, true);
|
||||
var fnDown = function(kbd, softCode) {
|
||||
return function onKeyboardBindingDown(event) {
|
||||
kbd.onSoftKeyDown(softCode, true);
|
||||
/*
|
||||
* I'm assuming we only need to give focus back on the "up" event...
|
||||
*
|
||||
* if (kbd.cmp) kbd.cmp.updateFocus();
|
||||
*/
|
||||
};
|
||||
}(this, sBinding);
|
||||
var fnUp = function (kbd, sSoftCode) {
|
||||
return function onMouseOrTouchUpKeyboard(event) {
|
||||
kbd.onSoftKeyDown(sSoftCode, false);
|
||||
}(this, this.config.SOFTCODES[sBinding]);
|
||||
var fnUp = function (kbd, softCode) {
|
||||
return function onKeyboardBindingUp(event) {
|
||||
kbd.onSoftKeyDown(softCode, false);
|
||||
/*
|
||||
* Give focus back to the machine (since clicking the button takes focus away).
|
||||
*/
|
||||
if (kbd.cmp) kbd.cmp.updateFocus();
|
||||
};
|
||||
}(this, sBinding);
|
||||
}(this, this.config.SOFTCODES[sBinding]);
|
||||
if ('ontouchstart' in window) {
|
||||
control.ontouchstart = fnDown;
|
||||
control.ontouchend = fnUp;
|
||||
|
|
@ -522,9 +536,10 @@ Keyboard.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
|||
*/
|
||||
Keyboard.prototype.initBus = function(cmp, bus, cpu, dbg)
|
||||
{
|
||||
this.cmp = cmp;
|
||||
this.cpu = cpu;
|
||||
this.dbg = dbg; // NOTE: The "dbg" property must be set for the message functions to work
|
||||
this.chipset = cmp.getMachineComponent("ChipSet");
|
||||
this.chipset = /** @type {ChipSet} */ (cmp.getMachineComponent("ChipSet"));
|
||||
bus.addPortInputTable(this, this.config.portsInput);
|
||||
bus.addPortOutputTable(this, this.config.portsOutput);
|
||||
};
|
||||
|
|
@ -873,8 +888,8 @@ Keyboard.prototype.checkBusy = function()
|
|||
*
|
||||
* We take our cue from iKeyNext. If it's -1 (default), we simply return the last value latched
|
||||
* in bVT100Address. Otherwise, if iKeyNext is a valid index into aKeysActive, we look up the key
|
||||
* in the VT100.KEYMAP, latch it, and increment iKeyNext, else we latch Keyboard.VT100.KEYLAST
|
||||
* and set iKeyNext to -1 again.
|
||||
* in the VT100.KEYMAP, latch it, and increment iKeyNext. Failing that, we latch Keyboard.VT100.KEYLAST
|
||||
* and reset iKeyNext to -1.
|
||||
*
|
||||
* @this {Keyboard}
|
||||
* @param {number} port (0x82)
|
||||
|
|
@ -893,8 +908,8 @@ Keyboard.prototype.inVT100UARTAddress = function(port, addrFrom)
|
|||
/*
|
||||
* In MAXDEBUG builds, this code removes the key as soon as it's been reported, because
|
||||
* when debugging, it's easy for the window to lose focus and never receive the keyUp event,
|
||||
* thereby leaving us with a stuck key. However, this causes more problems than it solves,
|
||||
* and seems to illustrate that key presses need to be persist for more than a single poll.
|
||||
* thereby leaving us with a stuck key. However, this may cause more problems than it solves,
|
||||
* because the VT100's ROM seems to require that key presses persist for more than a single poll.
|
||||
*/
|
||||
this.aKeysActive.splice(this.iKeyNext, 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ Panel.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
this.bus = bus;
|
||||
this.cpu = cpu;
|
||||
this.dbg = dbg;
|
||||
this.kbd = cmp.getMachineComponent("Keyboard");
|
||||
this.kbd = /** @type {Keyboard} */ (cmp.getMachineComponent("Keyboard"));
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -136,6 +136,90 @@ function SerialPort(parmsSerial) {
|
|||
|
||||
Component.subclass(SerialPort);
|
||||
|
||||
SerialPort.UART8251 = {
|
||||
/*
|
||||
* Format of MODE byte written to CONTROL port 0x1
|
||||
*/
|
||||
MODE: {
|
||||
BAUD_FACTOR: 0x03, // 00=SYNC, 01=1x, 10=16x, 11=64x
|
||||
DATA_BITS: 0x0C, // 00=5, 01=6, 10=7, 11=8
|
||||
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
|
||||
},
|
||||
/*
|
||||
* Format of COMMAND byte written to CONTROL port 0x1
|
||||
*/
|
||||
COMMAND: {
|
||||
XMIT_ENABLE: 0x01,
|
||||
DTR: 0x02, // Data Terminal Ready
|
||||
RECV_ENABLE: 0x04,
|
||||
SEND_BREAK: 0x08,
|
||||
ERROR_RESET: 0x10,
|
||||
RTS: 0x20, // Request To Send
|
||||
INTERNAL_RESET: 0x40,
|
||||
HUNT_MODE: 0x80,
|
||||
INIT: 0x27 // XMIT_ENABLE | DTR | RECV_ENABLE | RTS
|
||||
},
|
||||
/*
|
||||
* Format of STATUS byte read from CONTROL port 0x1
|
||||
*/
|
||||
STATUS: {
|
||||
XMIT_READY: 0x01,
|
||||
RECV_FULL: 0x02,
|
||||
XMIT_EMPTY: 0x04,
|
||||
PARITY_ERROR: 0x08,
|
||||
OVERRUN_ERROR: 0x10,
|
||||
FRAMING_ERROR: 0x20,
|
||||
BREAK_DETECT: 0x40,
|
||||
DSR: 0x80, // Data Set Ready
|
||||
INIT: 0x85 // XMIT_READY | XMIT_EMPTY | DSR
|
||||
},
|
||||
/*
|
||||
* Format of BAUDRATE 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:
|
||||
*
|
||||
* Index Divisor Baud Rate
|
||||
* ----- ------- ---------
|
||||
* 0x0 3456 50
|
||||
* 0x1 2304 75
|
||||
* 0x2 1571 110
|
||||
* 0x3 1285 134.5
|
||||
* 0x4 1152 150
|
||||
* 0x5 864 200
|
||||
* 0x6 576 300
|
||||
* 0x7 288 600
|
||||
* 0x8 144 1200
|
||||
* 0x9 96 1800
|
||||
* 0xA 86 2000
|
||||
* 0xB 72 2400
|
||||
* 0xC 48 3600
|
||||
* 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,
|
||||
INIT: 0xEE // default to 9600 (0xE) for both XMIT and RECV
|
||||
}
|
||||
};
|
||||
|
||||
SerialPort.UART8251.INIT = [
|
||||
false,
|
||||
0,
|
||||
0,
|
||||
SerialPort.UART8251.STATUS.INIT,
|
||||
SerialPort.UART8251.MODE.INIT,
|
||||
SerialPort.UART8251.COMMAND.INIT,
|
||||
SerialPort.UART8251.BAUDRATE.INIT
|
||||
];
|
||||
|
||||
/*
|
||||
* Internal name used for the I/O buffer control, if any, that we bind to the SerialPort.
|
||||
*
|
||||
|
|
@ -188,7 +272,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.sendRBR([keyCode]);
|
||||
serial.sendByteIn(keyCode);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
|
@ -218,10 +302,31 @@ SerialPort.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
|||
* so that the soft keyboard will activate, but it shouldn't hurt to remove the attribute for all browsers.
|
||||
*/
|
||||
control.removeAttribute("readonly");
|
||||
|
||||
return true;
|
||||
|
||||
default:
|
||||
if (sValue) {
|
||||
/*
|
||||
* Instead of just having a dedicated "test" control, we now treat any unrecognized control with
|
||||
* a "value" attribute as a test control. The only caveat is that such controls must have binding IDs
|
||||
* that do not conflict with predefined controls (which, of course, is the only way you can get here).
|
||||
*/
|
||||
this.bindings[sBinding] = control;
|
||||
/*
|
||||
* Convert any "backslashed" sequences into the appropriate control characters.
|
||||
*/
|
||||
sValue = sValue.replace(/\\n/g, "\n").replace(/\\r/g, "\r");
|
||||
control.onclick = function onClickTest(event) {
|
||||
serial.sDataIn = sValue;
|
||||
serial.sendDataIn();
|
||||
/*
|
||||
* Give focus back to the machine (since clicking the button takes focus away).
|
||||
*/
|
||||
if (serial.cmp) serial.cmp.updateFocus();
|
||||
return true;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -238,10 +343,11 @@ SerialPort.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
|||
*/
|
||||
SerialPort.prototype.initBus = function(cmp, bus, cpu, dbg)
|
||||
{
|
||||
this.cmp = cmp;
|
||||
this.bus = bus;
|
||||
this.cpu = cpu;
|
||||
this.dbg = dbg;
|
||||
this.chipset = cmp.getMachineComponent("ChipSet");
|
||||
this.chipset = /** @type {ChipSet} */ (cmp.getMachineComponent("ChipSet"));
|
||||
bus.addPortInputTable(this, SerialPort.aPortInput, this.portBase);
|
||||
bus.addPortOutputTable(this, SerialPort.aPortOutput, this.portBase);
|
||||
this.setReady();
|
||||
|
|
@ -330,11 +436,15 @@ SerialPort.prototype.initState = function(data)
|
|||
{
|
||||
var i = 0;
|
||||
if (data === undefined) {
|
||||
data = [0, 0, 0];
|
||||
data = SerialPort.UART8251.INIT;
|
||||
}
|
||||
this.bData = data[i++];
|
||||
this.bCommand = data[i++];
|
||||
this.bBaudRate = data[i++];
|
||||
this.fReady = data[i++];
|
||||
this.bDataIn = data[i++];
|
||||
this.bDataOut = data[i++];
|
||||
this.bStatus = data[i++];
|
||||
this.bMode = data[i++];
|
||||
this.bCommand = data[i++];
|
||||
this.bBaudRate = data[i];
|
||||
return true;
|
||||
};
|
||||
|
||||
|
|
@ -348,82 +458,46 @@ SerialPort.prototype.saveRegisters = function()
|
|||
{
|
||||
var i = 0;
|
||||
var data = [];
|
||||
data[i++] = this.bData;
|
||||
data[i++] = this.fReady;
|
||||
data[i++] = this.bDataIn;
|
||||
data[i++] = this.bDataOut;
|
||||
data[i++] = this.bStatus;
|
||||
data[i++] = this.bMode;
|
||||
data[i++] = this.bCommand;
|
||||
data[i++] = this.bBaudRate;
|
||||
data[i] = this.bBaudRate;
|
||||
return data;
|
||||
};
|
||||
|
||||
/**
|
||||
* inData(port, addrFrom)
|
||||
* sendByteIn(b)
|
||||
*
|
||||
* @this {SerialPort}
|
||||
* @param {number} port (0x0)
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||
* @return {number} simulated port value
|
||||
* @param {number} b
|
||||
* @return {boolean}
|
||||
*/
|
||||
SerialPort.prototype.inData = function(port, addrFrom)
|
||||
SerialPort.prototype.sendByteIn = function(b)
|
||||
{
|
||||
var b = this.bData;
|
||||
this.printMessageIO(port, null, addrFrom, "DATA", b);
|
||||
return b;
|
||||
if (!(this.bStatus & SerialPort.UART8251.STATUS.RECV_FULL)) {
|
||||
this.bDataIn = b;
|
||||
this.bStatus |= SerialPort.UART8251.STATUS.RECV_FULL;
|
||||
this.cpu.requestINTR(this.nIRQ);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* inCommand(port, addrFrom)
|
||||
* sendDataIn()
|
||||
*
|
||||
* @this {SerialPort}
|
||||
* @param {number} port (0x1)
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||
* @return {number} simulated port value
|
||||
*/
|
||||
SerialPort.prototype.inCommand = function(port, addrFrom)
|
||||
SerialPort.prototype.sendDataIn = function()
|
||||
{
|
||||
var b = this.bCommand;
|
||||
this.printMessageIO(port, null, addrFrom, "COMMAND", b);
|
||||
return b;
|
||||
};
|
||||
|
||||
/**
|
||||
* outData(port, bOut, addrFrom)
|
||||
*
|
||||
* @this {SerialPort}
|
||||
* @param {number} port (0x0)
|
||||
* @param {number} bOut
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to write the specified port)
|
||||
*/
|
||||
SerialPort.prototype.outData = function(port, bOut, addrFrom)
|
||||
{
|
||||
this.printMessageIO(port, bOut, addrFrom, "DATA");
|
||||
this.bData = bOut;
|
||||
};
|
||||
|
||||
/**
|
||||
* outCommand(port, bOut, addrFrom)
|
||||
*
|
||||
* @this {SerialPort}
|
||||
* @param {number} port (0x1)
|
||||
* @param {number} bOut
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to write the specified port)
|
||||
*/
|
||||
SerialPort.prototype.outCommand = function(port, bOut, addrFrom)
|
||||
{
|
||||
this.printMessageIO(port, bOut, addrFrom, "COMMAND");
|
||||
this.bCommand = bOut;
|
||||
};
|
||||
|
||||
/**
|
||||
* outBaudRate(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)
|
||||
{
|
||||
this.printMessageIO(port, bOut, addrFrom, "BAUDRATE");
|
||||
this.bBaudRate = bOut;
|
||||
if (this.sDataIn) {
|
||||
if (this.sendByteIn(this.sDataIn.charCodeAt(0))) {
|
||||
this.sDataIn = this.sDataIn.substr(1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -474,12 +548,99 @@ SerialPort.prototype.echoByte = function(b)
|
|||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* inData(port, addrFrom)
|
||||
*
|
||||
* @this {SerialPort}
|
||||
* @param {number} port (0x0)
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||
* @return {number} simulated port value
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* inControl(port, addrFrom)
|
||||
*
|
||||
* @this {SerialPort}
|
||||
* @param {number} port (0x1)
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||
* @return {number} simulated port value
|
||||
*/
|
||||
SerialPort.prototype.inControl = function(port, addrFrom)
|
||||
{
|
||||
var b = this.bStatus;
|
||||
this.printMessageIO(port, null, addrFrom, "STATUS", b);
|
||||
return b;
|
||||
};
|
||||
|
||||
/**
|
||||
* outData(port, bOut, addrFrom)
|
||||
*
|
||||
* @this {SerialPort}
|
||||
* @param {number} port (0x0)
|
||||
* @param {number} bOut
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to write the specified port)
|
||||
*/
|
||||
SerialPort.prototype.outData = function(port, bOut, addrFrom)
|
||||
{
|
||||
this.printMessageIO(port, bOut, addrFrom, "DATA");
|
||||
this.bDataOut = bOut;
|
||||
};
|
||||
|
||||
/**
|
||||
* outControl(port, bOut, addrFrom)
|
||||
*
|
||||
* Writes to the CONTROL port (0x1) are either MODE or COMMAND bytes. If the device has just
|
||||
* been powered or reset, it is in a "not ready" state and is waiting for a MODE byte. Once it
|
||||
* has received that initial byte, the device is marked "ready", and all further bytes are
|
||||
* interpreted as COMMAND bytes (until/unless a COMMAND byte with the INTERNAL_RESET bit is set).
|
||||
*
|
||||
* @this {SerialPort}
|
||||
* @param {number} port (0x1)
|
||||
* @param {number} bOut
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to write the specified port)
|
||||
*/
|
||||
SerialPort.prototype.outControl = function(port, bOut, addrFrom)
|
||||
{
|
||||
this.printMessageIO(port, bOut, addrFrom, "CONTROL");
|
||||
if (!this.fReady) {
|
||||
this.bMode = bOut;
|
||||
this.fReady = true;
|
||||
} else {
|
||||
this.bCommand = bOut;
|
||||
if (this.bCommand & SerialPort.UART8251.COMMAND.INTERNAL_RESET) {
|
||||
this.fReady = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* outBaudRate(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)
|
||||
{
|
||||
this.printMessageIO(port, bOut, addrFrom, "BAUDRATE");
|
||||
this.bBaudRate = bOut;
|
||||
};
|
||||
|
||||
/*
|
||||
* Port input notification table
|
||||
*/
|
||||
SerialPort.aPortInput = {
|
||||
0x0: SerialPort.prototype.inData,
|
||||
0x1: SerialPort.prototype.inCommand
|
||||
0x1: SerialPort.prototype.inControl
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -488,7 +649,7 @@ SerialPort.aPortInput = {
|
|||
*/
|
||||
SerialPort.aPortOutput = {
|
||||
0x0: SerialPort.prototype.outData,
|
||||
0x1: SerialPort.prototype.outCommand,
|
||||
0x1: SerialPort.prototype.outControl,
|
||||
0x2: SerialPort.prototype.outBaudRate
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ 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 simplify smooth-scrolling down the road.
|
||||
* row for text modes, to account for the VT100's scroll line buffer (used for smooth scrolling).
|
||||
*/
|
||||
if (this.cyCell > 1) this.nRowsBuffer++;
|
||||
|
||||
|
|
@ -292,6 +292,9 @@ Video.VT100 = {
|
|||
|
||||
/**
|
||||
* initBuffers()
|
||||
*
|
||||
* @this {Video}
|
||||
* @return {boolean}
|
||||
*/
|
||||
Video.prototype.initBuffers = function()
|
||||
{
|
||||
|
|
@ -308,10 +311,11 @@ Video.prototype.initBuffers = function()
|
|||
cyBuffer = this.cxBuffer;
|
||||
}
|
||||
|
||||
this.sizeBuffer = ((this.cxBuffer * this.nBitsPerPixel) >> 3) * this.cyBuffer;
|
||||
this.sizeBuffer = 0;
|
||||
if (!this.fUseRAM) {
|
||||
this.sizeBuffer = ((this.cxBuffer * this.nBitsPerPixel) >> 3) * this.cyBuffer;
|
||||
if (!this.bus.addMemory(this.addrBuffer, this.sizeBuffer, Memory.TYPE.VIDEO)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -319,15 +323,15 @@ Video.prototype.initBuffers = function()
|
|||
* imageBuffer is only used for graphics modes. For text modes, we create a canvas
|
||||
* for each font and draw characters by drawing from the font canvas to the target canvas.
|
||||
*/
|
||||
if (this.cxCell > 1) {
|
||||
if (this.sizeBuffer) {
|
||||
this.imageBuffer = this.contextScreen.createImageData(cxBuffer, cyBuffer);
|
||||
this.nPixelsPerCell = (16 / this.nBitsPerPixel)|0;
|
||||
this.initCellCache(this.sizeBuffer >> 1);
|
||||
} else {
|
||||
/*
|
||||
* We add an extra column per row to store the visible line length at the start of every row.
|
||||
*/
|
||||
this.initCellCache((this.nColsBuffer + 1) * this.nRowsBuffer);
|
||||
} else {
|
||||
this.imageBuffer = this.contextScreen.createImageData(cxBuffer, cyBuffer);
|
||||
this.nPixelsPerCell = (16 / this.nBitsPerPixel)|0;
|
||||
this.initCellCache(this.sizeBuffer >> 1);
|
||||
}
|
||||
|
||||
this.canvasBuffer = document.createElement("canvas");
|
||||
|
|
@ -383,6 +387,7 @@ Video.prototype.initBuffers = function()
|
|||
|
||||
this.abLineBuffer = new Array(this.nColsBuffer);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -410,7 +415,7 @@ Video.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
* If we have an associated keyboard, then ensure that the keyboard will be notified
|
||||
* whenever the canvas gets focus and receives input.
|
||||
*/
|
||||
this.kbd = cmp.getMachineComponent("Keyboard");
|
||||
this.kbd = /** @type {Keyboard} */ (cmp.getMachineComponent("Keyboard"));
|
||||
if (this.kbd) {
|
||||
for (var s in this.ledBindings) {
|
||||
this.kbd.setBinding("led", s, this.ledBindings[s]);
|
||||
|
|
@ -461,7 +466,8 @@ Video.prototype.doneLoad = function(sURL, sFontData, nErrorCode)
|
|||
* Minimal font data validation, just to make sure we're not getting garbage from the server.
|
||||
*/
|
||||
if (abFontData.length == 2048) {
|
||||
this.createFonts(abFontData);
|
||||
this.abFontData = abFontData;
|
||||
this.createFonts();
|
||||
}
|
||||
else {
|
||||
this.notice("Unrecognized font data length (" + abFontData.length + ")");
|
||||
|
|
@ -484,30 +490,33 @@ Video.prototype.doneLoad = function(sURL, sFontData, nErrorCode)
|
|||
};
|
||||
|
||||
/**
|
||||
* createFonts(abFontData)
|
||||
* createFonts()
|
||||
*
|
||||
* @this {Video}
|
||||
* @param {Array.<number>} abFontData
|
||||
* @return {boolean}
|
||||
*/
|
||||
Video.prototype.createFonts = function(abFontData)
|
||||
Video.prototype.createFonts = function()
|
||||
{
|
||||
/*
|
||||
* We retain abFontData in case we have to rebuild the fonts (eg, when we switch from 80 to 132 columns)
|
||||
*/
|
||||
this.abFontData = abFontData;
|
||||
this.fDotStretcher = (this.nFormat == Video.FORMAT.VT100);
|
||||
this.aFonts[Video.VT100.FONT.NORML] = [
|
||||
this.createFontVariation(this.cxCell, this.cyCell),
|
||||
this.createFontVariation(this.cxCell, this.cyCell, this.fUnderline)
|
||||
];
|
||||
this.aFonts[Video.VT100.FONT.DWIDE] = [
|
||||
this.createFontVariation(this.cxCell*2, this.cyCell),
|
||||
this.createFontVariation(this.cxCell*2, this.cyCell, this.fUnderline)
|
||||
];
|
||||
this.aFonts[Video.VT100.FONT.DHIGH] = this.aFonts[Video.VT100.FONT.DHIGH_BOT] = [
|
||||
this.createFontVariation(this.cxCell*2, this.cyCell*2),
|
||||
this.createFontVariation(this.cxCell*2, this.cyCell*2, this.fUnderline)
|
||||
];
|
||||
if (this.abFontData) {
|
||||
this.fDotStretcher = (this.nFormat == Video.FORMAT.VT100);
|
||||
this.aFonts[Video.VT100.FONT.NORML] = [
|
||||
this.createFontVariation(this.cxCell, this.cyCell),
|
||||
this.createFontVariation(this.cxCell, this.cyCell, this.fUnderline)
|
||||
];
|
||||
this.aFonts[Video.VT100.FONT.DWIDE] = [
|
||||
this.createFontVariation(this.cxCell*2, this.cyCell),
|
||||
this.createFontVariation(this.cxCell*2, this.cyCell, this.fUnderline)
|
||||
];
|
||||
this.aFonts[Video.VT100.FONT.DHIGH] = this.aFonts[Video.VT100.FONT.DHIGH_BOT] = [
|
||||
this.createFontVariation(this.cxCell*2, this.cyCell*2),
|
||||
this.createFontVariation(this.cxCell*2, this.cyCell*2, this.fUnderline)
|
||||
];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -712,6 +721,47 @@ Video.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
|||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* updateDimensions(nCols, nRows)
|
||||
*
|
||||
* Called from the ChipSet component whenever the screen dimensions have been dynamically altered.
|
||||
*
|
||||
* @this {Video}
|
||||
* @param {number} nCols (should be either 80 or 132; 80 is the default)
|
||||
* @param {number} nRows (should be either 24 or 14; 24 is the default)
|
||||
*/
|
||||
Video.prototype.updateDimensions = function(nCols, nRows)
|
||||
{
|
||||
this.printMessage("updateDimensions(" + nCols + "," + nRows + ")");
|
||||
this.nColsBuffer = nCols;
|
||||
/*
|
||||
* Even when the number of effective rows is 14 (or 15 counting the scroll line buffer), we want
|
||||
* to leave the number of rows at 24 (or 25 counting the scroll line buffer), because the VT100 doesn't
|
||||
* actually change character height (only character width).
|
||||
*
|
||||
* this.nRowsBuffer = nRows+1; // +1 for scroll line buffer
|
||||
*/
|
||||
this.cxCell = this.cxCellDefault;
|
||||
if (nCols > 80) this.cxCell--; // VT100 font cells are 9x10 instead of 10x10 in 132-column mode
|
||||
if (this.initBuffers()) {
|
||||
this.createFonts();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* updateRate(nRate)
|
||||
*
|
||||
* Called from the ChipSet component whenever the monitor refresh rate has been dynamically altered.
|
||||
*
|
||||
* @this {Video}
|
||||
* @param {number} nRate (should be either 50 or 60; 60 is the default)
|
||||
*/
|
||||
Video.prototype.updateRate = function(nRate)
|
||||
{
|
||||
this.printMessage("updateRate(" + nRate + ")");
|
||||
this.rateMonitor = nRate;
|
||||
};
|
||||
|
||||
/**
|
||||
* doFullScreen()
|
||||
*
|
||||
|
|
@ -796,7 +846,7 @@ Video.prototype.notifyFullScreen = function(fFullScreen)
|
|||
this.canvasScreen.style.width = this.canvasScreen.style.height = "";
|
||||
}
|
||||
}
|
||||
this.printMessage("notifyFullScreen(" + fFullScreen + ")", true);
|
||||
this.printMessage("notifyFullScreen(" + fFullScreen + ")");
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1057,8 +1107,8 @@ Video.prototype.updateVT100 = function(fForced)
|
|||
|
||||
if (cUpdated && this.contextBuffer) {
|
||||
/*
|
||||
* NOTE: We must subtract cyCell from cyBuffer to avoid displaying the extra row that we normally buffer
|
||||
* in support of smooth-scrolling.
|
||||
* NOTE: We must subtract cyCell from cyBuffer to avoid displaying the extra "scroll line" that we normally
|
||||
* buffer to support smooth-scrolling.
|
||||
*/
|
||||
this.contextScreen.drawImage(this.canvasBuffer, 0, 0, this.cxBuffer, this.cyBuffer - this.cyCell, this.xScreenOffset, this.yScreenOffset, this.cxScreenOffset, this.cyScreenOffset);
|
||||
}
|
||||
|
|
@ -1111,9 +1161,10 @@ Video.prototype.updateScreen = function(n)
|
|||
}
|
||||
|
||||
/*
|
||||
* Since this is not a forced update, if our cell cache is valid AND the buffer is clean, then do nothing.
|
||||
* Since this is not a forced update, if our cell cache is valid AND we allocated our own buffer AND the buffer
|
||||
* is clean, then there's nothing to do.
|
||||
*/
|
||||
if (fUpdate && this.fCellCacheValid) {
|
||||
if (fUpdate && this.fCellCacheValid && this.sizeBuffer) {
|
||||
if ((fClean = this.bus.cleanMemory(this.addrBuffer, this.sizeBuffer))) {
|
||||
fUpdate = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1220,7 +1220,7 @@ Keyboard.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
|||
if (Keyboard.CLICKCODES[sCode] !== undefined && sHTMLType == "button") {
|
||||
this.bindings[id] = control;
|
||||
control.onclick = function(kbd, sKey, simCode) {
|
||||
return function onClickKeyboard(event) {
|
||||
return function onKeyboardBindingClick(event) {
|
||||
if (!COMPILED && kbd.messageEnabled()) kbd.printMessage(sKey + " clicked", Messages.KEYS);
|
||||
if (kbd.cmp) kbd.cmp.updateFocus();
|
||||
kbd.updateShiftState(simCode, true); // future-proofing if/when any LOCK keys are added to CLICKCODES
|
||||
|
|
@ -1233,12 +1233,12 @@ Keyboard.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
|||
this.cSoftCodes++;
|
||||
this.bindings[id] = control;
|
||||
var fnDown = function(kbd, sKey, simCode) {
|
||||
return function onMouseOrTouchDownKeyboard(event) {
|
||||
return function onKeyboardBindingDown(event) {
|
||||
kbd.addActiveKey(simCode);
|
||||
};
|
||||
}(this, sBinding, Keyboard.SOFTCODES[sBinding]);
|
||||
var fnUp = function (kbd, sKey, simCode) {
|
||||
return function onMouseOrTouchUpKeyboard(event) {
|
||||
return function onKeyboardBindingUp(event) {
|
||||
kbd.removeActiveKey(simCode);
|
||||
};
|
||||
}(this, sBinding, Keyboard.SOFTCODES[sBinding]);
|
||||
|
|
@ -1254,8 +1254,8 @@ Keyboard.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
|||
else if (sValue) {
|
||||
/*
|
||||
* Instead of just having a dedicated "test" control, we now treat any unrecognized control with
|
||||
* a data value as a test control. The only caveat is that such controls must have binding IDs that
|
||||
* do not conflict with predefined controls (which, of course, is the only way you can get here).
|
||||
* a "value" attribute as a test control. The only caveat is that such controls must have binding IDs
|
||||
* that do not conflict with predefined controls (which, of course, is the only way you can get here).
|
||||
*/
|
||||
this.bindings[id] = control;
|
||||
control.onclick = function onClickTest(event) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue