From 9578faf231f34dfa5d59e1761be140296d8fc34d Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Wed, 3 Dec 2014 16:59:12 -0800 Subject: [PATCH] Hard disk controller fixes Still some lingering OS/2 disk-related issues however --- devices/pc/bios/5170/1985-11-15.json | 2 +- devices/pc/bios/5170/1985-11-15.map | 2 +- modules/pcjs/lib/chipset.js | 367 +++++++++++++++------------ modules/pcjs/lib/debugger.js | 13 +- modules/pcjs/lib/disk.js | 113 ++++++--- modules/pcjs/lib/fdc.js | 8 +- modules/pcjs/lib/hdc.js | 177 +++++++------ modules/pcjs/lib/keyboard.js | 18 +- modules/pcjs/lib/video.js | 25 +- modules/pcjs/lib/x86cpu.js | 14 +- modules/pcjs/lib/x86help.js | 2 +- modules/shared/lib/component.js | 33 ++- 12 files changed, 435 insertions(+), 339 deletions(-) diff --git a/devices/pc/bios/5170/1985-11-15.json b/devices/pc/bios/5170/1985-11-15.json index 14990a0ec..e4d355cbb 100644 --- a/devices/pc/bios/5170/1985-11-15.json +++ b/devices/pc/bios/5170/1985-11-15.json @@ -1023,4 +1023,4 @@ 0,0,0,0,-822083584,4958953,216530944,-1259812051,1156107052,-773207253,53,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,14703594,791753200,942617905,-1979973579] -,"symbols":{"POST1_TEST01":{"o":80,"s":61440,"c":"TEST.01: 286 PROCESSOR TEST (REAL MODE)"},"POST1_TEST02":{"o":391,"s":61440,"c":"TEST.02: ROM CHECKSUM TEST"},"POST1_TEST03":{"o":419,"s":61440,"c":"TEST.03: VERIFY CMOS SHUTDOWN BYTE"},"POST1_TEST04":{"o":457,"s":61440,"c":"TEST.04: 8254 CHECK TIMER 1 (ALL BITS ON)"},"POST1_TEST05":{"o":503,"s":61440,"c":"TEST.05: 8254 CHECK TIMER 1 (ALL BITS OFF)"},"POST1_TEST06":{"o":541,"s":61440,"c":"TEST.06: 8237 DMA 0 INITIALIZATION"},"POST1_TEST07":{"o":607,"s":61440,"c":"TEST.07: 8237 DMA 1 INITIALIZATION"},"POST1_TEST08":{"o":724,"s":61440,"c":"TEST.08: DMA PAGE REGISTER TEST"},"POST1_TEST09":{"o":807,"s":61440,"c":"TEST.09: STORAGE REFRESH TEST"},"POST1_TEST10":{"o":829,"s":61440,"c":"TEST.10: 8042 INTERFACE TEST"},"POST1_TEST11":{"o":951,"s":61440,"c":"TEST.11: BASE 64K R/W STORAGE TEST"},"POST1_TEST11A":{"o":1494,"s":61440,"c":"TEST.11A: VERIFY GDT/IDT INSTRUCTIONS"},"POST1_TEST12":{"o":1726,"s":61440,"c":"TEST.12: VERIFY CMOS CHECKSUM"},"POST1_TEST13":{"o":1920,"s":61440,"c":"TEST.13: PROTECTED MODE TEST"},"POST1_TEST13A":{"o":2158,"s":61440,"c":"TEST.13A: MEMORY SIZE TEST (ABOVE 1024K)"},"POST1_TEST14":{"o":2713,"s":61440,"c":"TEST.14: INITIALIZE CRT CONTROLLER"},"POST1_TEST15":{"o":2829,"s":61440,"c":"TEST.15: VIDEO LINE TEST"},"POST1_TEST16":{"o":2845,"s":61440,"c":"TEST.16: CRT INTERFACE LINES TEST"},"MFG_BOOT":{"o":3109,"s":61440,"c":"MANUFACTURING BOOT TEST CODE ROUTINE"},"POST2":{"o":3220,"s":61440},"POST2_CHK_HFNUM":{"o":5372,"s":61440,"c":"CHECK FOR SECOND FIXED DISK PRESENT BUT NOT DEFINED"},"POST3":{"o":5749,"s":61440},"POST4":{"o":6469,"s":61440},"CMOS_READ":{"o":6469,"s":61440},"CMOS_WRITE":{"o":6495,"s":61440},"DDS":{"o":6521,"s":61440},"E_MSG":{"o":6529,"s":61440},"ERR_BEEP":{"o":6582,"s":61440},"BEEP":{"o":6644,"s":61440},"WAITF":{"o":6714,"s":61440,"c":"FIXED TIME WAIT (CX = COUNT OF 15.085737us INTERVALS TO WAIT)"},"CONFIG_BAD":{"o":6729,"s":61440},"XPC_BYTE":{"o":6749,"s":61440},"PRT_SEG":{"o":6772,"s":61440},"PROT_PRT":{"o":6793,"s":61440},"ROM_CHECKSUM":{"o":6837,"s":61440},"ROM_CHECK":{"o":6849,"s":61440},"KBD_RESET":{"o":6899,"s":61440},"BLINK_INT":{"o":6942,"s":61440},"SET_TOD":{"o":6956,"s":61440},"POST5":{"o":7230,"s":61440},"POST6":{"o":7867,"s":61440},"XMIT_8042":{"o":8167,"s":61440},"BOOT_STRAP_1":{"o":8232,"s":61440},"DISKETTE_IO_1":{"o":8521,"s":61440},"DISK_RESET":{"o":8656,"s":61440},"DISK_STATUS":{"o":8741,"s":61440},"DISK_READ":{"o":8753,"s":61440},"DISK_WRITE":{"o":8765,"s":61440},"DISK_VERF":{"o":8777,"s":61440},"DISK_FORMAT":{"o":8789,"s":61440},"DISK_PARMS":{"o":8891,"s":61440},"DISK_CHANGE":{"o":9110,"s":61440,"c":"RETURNS THE STATE OF THE DISK CHANGE LINE"},"FORMAT_SET":{"o":9153,"s":61440},"DISK_TYPE":{"o":9076,"s":61440},"SET_MEDIA":{"o":9250,"s":61440},"DR_TYPE_CHECK":{"o":9365,"s":61440},"SEND_SPEC":{"o":9397,"s":61440},"XLAT_NEW":{"o":9452,"s":61440},"XLAT_OLD":{"o":9490,"s":61440},"SETUP_END":{"o":10462,"s":61440},"SETUP_DBL":{"o":10488,"s":61440,"c":"CHECK DOUBLE STEP"},"READ_ID":{"o":10588,"s":61440},"CMOS_TYPE":{"o":10609,"s":61440},"MOTOR_ON":{"o":10655,"s":61440},"NEC_OUTPUT":{"o":10877,"s":61440},"SEEK":{"o":10921,"s":61440},"RESULTS":{"o":11118,"s":61440},"READ_DSKCHNG":{"o":11181,"s":61440},"WAIT_INT":{"o":11078,"s":61440},"DISK_INT_1":{"o":11230,"s":61440},"DSKETTE_SETUP":{"o":11253,"s":61440},"DISK_SETUP":{"o":11337,"s":61440},"DISK_IO":{"o":11762,"s":61440},"HDISK_SETUP":{"o":11369,"s":61440},"HD_RESET_1":{"o":11629,"s":61440},"SET_FAIL":{"o":11749,"s":61440},"POD_TCHK":{"o":11763,"s":61440},"HDISK_IO":{"o":11794,"s":61440},"HDISK_IO_CONT":{"o":11918,"s":61440},"HDISK_RESET":{"o":12074,"s":61440},"HDISK_STATUS":{"o":12158,"s":61440},"HDISK_READ":{"o":12167,"s":61440},"HDISK_WRITE":{"o":12174,"s":61440},"HDISK_VERF":{"o":12181,"s":61440},"FMT_TRK":{"o":12199,"s":61440},"READ_DASD":{"o":12220,"s":61440},"GET_PARM":{"o":12284,"s":61440},"INIT_DRV":{"o":12378,"s":61440},"RD_LONG":{"o":12428,"s":61440},"WR_LONG":{"o":12435,"s":61440},"DISK_SEEK":{"o":12442,"s":61440},"TST_RDY":{"o":12472,"s":61440,"c":"TEST HARD DISK READY (AH = 0x10)"},"HDISK_RECAL":{"o":12495,"s":61440},"CTLR_DIAGNOSTIC":{"o":12535,"s":61440},"COMMANDI":{"o":12591,"s":61440},"COMMANDO":{"o":12654,"s":61440},"COMMAND":{"o":12741,"s":61440},"WAIT":{"o":12741,"s":61440},"NOT_BUSY":{"o":12892,"s":61440},"WAIT_DRQ":{"o":12931,"s":61440},"CHECK_STATUS":{"o":12953,"s":61440},"CHECK_ST":{"o":12971,"s":61440},"CHECK_ER":{"o":13023,"s":61440},"CHECK_DMA":{"o":13066,"s":61440},"GET_VEC":{"o":13101,"s":61440},"HD_INT":{"o":13123,"s":61440},"KEYBOARD_IO_1":{"o":13158,"s":61440},"K1S":{"o":13357,"s":61440,"c":"READ THE KEY TO FIGURE OUT WHAT TO DO"},"K2S":{"o":13417,"s":61440,"c":"READ THE KEY TO SEE IF ONE IS PRESENT"},"KIO_E_XLAT":{"o":13451,"s":61440,"c":"TRANSLATE SCAN CODE PAIRS FOR EXTENDED CALLS"},"KIO_S_XLAT":{"o":13462,"s":61440,"c":"TRANSLATE SCAN CODE PAIRS FOR STANDARD CALLS"},"K4":{"o":13518,"s":61440,"c":"INCREMENT BUFFER POINTER ROUTINE"},"KB_INT_1":{"o":13531,"s":61440,"c":"KEYBOARD INTERRUPT ROUTINE"},"KB_INT_01":{"o":13553,"s":61440,"c":"WAIT FOR KEYBOARD DISABLE COMMAND TO BE ACCEPTED"},"KB_INT_02":{"o":13571,"s":61440,"c":"CHECK FOR A RESEND COMMAND TO KEYBOARD"},"KB_INT_4":{"o":13589,"s":61440,"c":"RESEND THE LAST BYTE"},"KB_INT_2":{"o":13598,"s":61440,"c":"UPDATE MODE INDICATORS IF CHANGE IN STATE"},"UP0":{"o":13616,"s":61440,"c":"START OF KEY PROCESSING"},"T_SYS_KEY":{"o":13758,"s":61440,"c":"TEST FOR SYSTEM KEY"},"K16A":{"o":13823,"s":61440,"c":"TEST FOR SHIFT KEYS"},"K17":{"o":13842,"s":61440,"c":"SHIFT KEY FOUND"},"K17C":{"o":13860,"s":61440,"c":"SHIFT KEY FOUND, DETERMINE SET OR TOGGLE"},"K23":{"o":13979,"s":61440,"c":"BREAK SHIFT FOUND"},"K25":{"o":14059,"s":61440,"c":"TEST FOR HOLD STATE"},"K26A":{"o":14084,"s":61440,"c":"INTERRUPT RETURN"},"K57":{"o":14676,"s":61440,"c":"PUT CHARACTER INTO BUFFER"},"SHIP_IT":{"o":14747,"s":61440,"c":"HANDLE TRANSMISSION OF BYTES TO 8042"},"SND_DATA":{"o":14762,"s":61440,"c":"HANDLE TRANSMISSION OF COMMAND AND DATA BYTES"},"SND_LED":{"o":14822,"s":61440,"c":"TURN ON THE MODE INDICATORS"},"MAKE_LED":{"o":14903,"s":61440,"c":"FORM THE DATA BYTE FOR THE MODE INDICATORS"},"CASSETTE_IO_1":{"o":17549,"s":61440,"c":"BIOS1 (11/15/85)"},"INT15_EVENT_WAIT":{"o":17650,"s":61440},"INT15_JOY_STICK":{"o":17757,"s":61440},"INT15_WAIT":{"o":17911,"s":61440},"INT15_BLOCKMOVE":{"o":18007,"s":61440},"SHUT9":{"o":18199,"s":61440,"c":"RETURN FROM SHUTDOWN"},"GATE_A20":{"o":18521,"s":61440},"EMPTY_8042":{"o":18546,"s":61440},"EXT_MEMORY":{"o":18555,"s":61440},"X_VIRTUAL":{"o":18567,"s":61440},"TIME_OF_DAY_1":{"o":18709,"s":61440,"c":"BIOS2 (11/15/85)"},"RTC_INT":{"o":19095,"s":61440,"c":"ALARM INTERRUPT (INT 0x70, IRQ 8)"}}} \ No newline at end of file +,"symbols":{"POST1_TEST01":{"o":80,"s":61440,"c":"TEST.01: 286 PROCESSOR TEST (REAL MODE)"},"POST1_TEST02":{"o":391,"s":61440,"c":"TEST.02: ROM CHECKSUM TEST"},"POST1_TEST03":{"o":419,"s":61440,"c":"TEST.03: VERIFY CMOS SHUTDOWN BYTE"},"POST1_TEST04":{"o":457,"s":61440,"c":"TEST.04: 8254 CHECK TIMER 1 (ALL BITS ON)"},"POST1_TEST05":{"o":503,"s":61440,"c":"TEST.05: 8254 CHECK TIMER 1 (ALL BITS OFF)"},"POST1_TEST06":{"o":541,"s":61440,"c":"TEST.06: 8237 DMA 0 INITIALIZATION"},"POST1_TEST07":{"o":607,"s":61440,"c":"TEST.07: 8237 DMA 1 INITIALIZATION"},"POST1_TEST08":{"o":724,"s":61440,"c":"TEST.08: DMA PAGE REGISTER TEST"},"POST1_TEST09":{"o":807,"s":61440,"c":"TEST.09: STORAGE REFRESH TEST"},"POST1_TEST10":{"o":829,"s":61440,"c":"TEST.10: 8042 INTERFACE TEST"},"POST1_TEST11":{"o":951,"s":61440,"c":"TEST.11: BASE 64K R/W STORAGE TEST"},"POST1_TEST11A":{"o":1494,"s":61440,"c":"TEST.11A: VERIFY GDT/IDT INSTRUCTIONS"},"POST1_TEST12":{"o":1726,"s":61440,"c":"TEST.12: VERIFY CMOS CHECKSUM"},"POST1_TEST13":{"o":1920,"s":61440,"c":"TEST.13: PROTECTED MODE TEST"},"POST1_TEST13A":{"o":2158,"s":61440,"c":"TEST.13A: MEMORY SIZE TEST (ABOVE 1024K)"},"POST1_TEST14":{"o":2713,"s":61440,"c":"TEST.14: INITIALIZE CRT CONTROLLER"},"POST1_TEST15":{"o":2829,"s":61440,"c":"TEST.15: VIDEO LINE TEST"},"POST1_TEST16":{"o":2845,"s":61440,"c":"TEST.16: CRT INTERFACE LINES TEST"},"MFG_BOOT":{"o":3109,"s":61440,"c":"MANUFACTURING BOOT TEST CODE ROUTINE"},"POST2":{"o":3220,"s":61440},"POST2_CHK_HFNUM":{"o":5372,"s":61440,"c":"CHECK FOR SECOND FIXED DISK PRESENT BUT NOT DEFINED"},"POST3":{"o":5749,"s":61440},"POST4":{"o":6469,"s":61440},"CMOS_READ":{"o":6469,"s":61440},"CMOS_WRITE":{"o":6495,"s":61440},"DDS":{"o":6521,"s":61440},"E_MSG":{"o":6529,"s":61440},"ERR_BEEP":{"o":6582,"s":61440},"BEEP":{"o":6644,"s":61440},"WAITF":{"o":6714,"s":61440,"c":"FIXED TIME WAIT (CX = COUNT OF 15.085737us INTERVALS TO WAIT)"},"CONFIG_BAD":{"o":6729,"s":61440},"XPC_BYTE":{"o":6749,"s":61440},"PRT_SEG":{"o":6772,"s":61440},"PROT_PRT":{"o":6793,"s":61440},"ROM_CHECKSUM":{"o":6837,"s":61440},"ROM_CHECK":{"o":6849,"s":61440},"KBD_RESET":{"o":6899,"s":61440},"BLINK_INT":{"o":6942,"s":61440},"SET_TOD":{"o":6956,"s":61440},"POST5":{"o":7230,"s":61440},"POST6":{"o":7867,"s":61440},"XMIT_8042":{"o":8167,"s":61440},"BOOT_STRAP_1":{"o":8232,"s":61440},"DISKETTE_IO_1":{"o":8521,"s":61440},"DISK_RESET":{"o":8656,"s":61440},"DISK_STATUS":{"o":8741,"s":61440},"DISK_READ":{"o":8753,"s":61440},"DISK_WRITE":{"o":8765,"s":61440},"DISK_VERF":{"o":8777,"s":61440},"DISK_FORMAT":{"o":8789,"s":61440},"DISK_PARMS":{"o":8891,"s":61440},"DISK_CHANGE":{"o":9110,"s":61440,"c":"RETURNS THE STATE OF THE DISK CHANGE LINE"},"FORMAT_SET":{"o":9153,"s":61440},"DISK_TYPE":{"o":9076,"s":61440},"SET_MEDIA":{"o":9250,"s":61440},"DR_TYPE_CHECK":{"o":9365,"s":61440},"SEND_SPEC":{"o":9397,"s":61440},"XLAT_NEW":{"o":9452,"s":61440},"XLAT_OLD":{"o":9490,"s":61440},"SETUP_END":{"o":10462,"s":61440},"SETUP_DBL":{"o":10488,"s":61440,"c":"CHECK DOUBLE STEP"},"READ_ID":{"o":10588,"s":61440},"CMOS_TYPE":{"o":10609,"s":61440},"MOTOR_ON":{"o":10655,"s":61440},"NEC_OUTPUT":{"o":10877,"s":61440},"SEEK":{"o":10921,"s":61440},"RESULTS":{"o":11118,"s":61440},"READ_DSKCHNG":{"o":11181,"s":61440},"WAIT_INT":{"o":11078,"s":61440},"DISK_INT_1":{"o":11230,"s":61440},"DSKETTE_SETUP":{"o":11253,"s":61440},"DISK_SETUP":{"o":11337,"s":61440},"DISK_IO":{"o":11762,"s":61440},"HDISK_SETUP":{"o":11369,"s":61440},"HD_RESET_1":{"o":11629,"s":61440},"SET_FAIL":{"o":11749,"s":61440},"POD_TCHK":{"o":11763,"s":61440},"HDISK_IO":{"o":11794,"s":61440},"HDISK_IO_CONT":{"o":11918,"s":61440},"HDISK_RESET":{"o":12074,"s":61440},"HDISK_STATUS":{"o":12158,"s":61440},"HDISK_READ":{"o":12167,"s":61440},"HDISK_WRITE":{"o":12174,"s":61440},"HDISK_VERF":{"o":12181,"s":61440},"FMT_TRK":{"o":12199,"s":61440},"READ_DASD":{"o":12220,"s":61440},"GET_PARM":{"o":12284,"s":61440},"INIT_DRV":{"o":12378,"s":61440},"RD_LONG":{"o":12428,"s":61440},"WR_LONG":{"o":12435,"s":61440},"DISK_SEEK":{"o":12442,"s":61440},"TST_RDY":{"o":12472,"s":61440,"c":"TEST HARD DISK READY (AH = 0x10)"},"HDISK_RECAL":{"o":12495,"s":61440},"CTLR_DIAGNOSTIC":{"o":12535,"s":61440},"COMMANDI":{"o":12591,"s":61440},"COMMANDO":{"o":12654,"s":61440},"COMMAND":{"o":12741,"s":61440},"WAIT":{"o":12843,"s":61440},"NOT_BUSY":{"o":12892,"s":61440},"WAIT_DRQ":{"o":12931,"s":61440},"CHECK_STATUS":{"o":12953,"s":61440},"CHECK_ST":{"o":12971,"s":61440},"CHECK_ER":{"o":13023,"s":61440},"CHECK_DMA":{"o":13066,"s":61440},"GET_VEC":{"o":13101,"s":61440},"HD_INT":{"o":13123,"s":61440},"KEYBOARD_IO_1":{"o":13158,"s":61440},"K1S":{"o":13357,"s":61440,"c":"READ THE KEY TO FIGURE OUT WHAT TO DO"},"K2S":{"o":13417,"s":61440,"c":"READ THE KEY TO SEE IF ONE IS PRESENT"},"KIO_E_XLAT":{"o":13451,"s":61440,"c":"TRANSLATE SCAN CODE PAIRS FOR EXTENDED CALLS"},"KIO_S_XLAT":{"o":13462,"s":61440,"c":"TRANSLATE SCAN CODE PAIRS FOR STANDARD CALLS"},"K4":{"o":13518,"s":61440,"c":"INCREMENT BUFFER POINTER ROUTINE"},"KB_INT_1":{"o":13531,"s":61440,"c":"KEYBOARD INTERRUPT ROUTINE"},"KB_INT_01":{"o":13553,"s":61440,"c":"WAIT FOR KEYBOARD DISABLE COMMAND TO BE ACCEPTED"},"KB_INT_02":{"o":13571,"s":61440,"c":"CHECK FOR A RESEND COMMAND TO KEYBOARD"},"KB_INT_4":{"o":13589,"s":61440,"c":"RESEND THE LAST BYTE"},"KB_INT_2":{"o":13598,"s":61440,"c":"UPDATE MODE INDICATORS IF CHANGE IN STATE"},"UP0":{"o":13616,"s":61440,"c":"START OF KEY PROCESSING"},"T_SYS_KEY":{"o":13758,"s":61440,"c":"TEST FOR SYSTEM KEY"},"K16A":{"o":13823,"s":61440,"c":"TEST FOR SHIFT KEYS"},"K17":{"o":13842,"s":61440,"c":"SHIFT KEY FOUND"},"K17C":{"o":13860,"s":61440,"c":"SHIFT KEY FOUND, DETERMINE SET OR TOGGLE"},"K23":{"o":13979,"s":61440,"c":"BREAK SHIFT FOUND"},"K25":{"o":14059,"s":61440,"c":"TEST FOR HOLD STATE"},"K26A":{"o":14084,"s":61440,"c":"INTERRUPT RETURN"},"K57":{"o":14676,"s":61440,"c":"PUT CHARACTER INTO BUFFER"},"SHIP_IT":{"o":14747,"s":61440,"c":"HANDLE TRANSMISSION OF BYTES TO 8042"},"SND_DATA":{"o":14762,"s":61440,"c":"HANDLE TRANSMISSION OF COMMAND AND DATA BYTES"},"SND_LED":{"o":14822,"s":61440,"c":"TURN ON THE MODE INDICATORS"},"MAKE_LED":{"o":14903,"s":61440,"c":"FORM THE DATA BYTE FOR THE MODE INDICATORS"},"CASSETTE_IO_1":{"o":17549,"s":61440,"c":"BIOS1 (11/15/85)"},"INT15_EVENT_WAIT":{"o":17650,"s":61440},"INT15_JOY_STICK":{"o":17757,"s":61440},"INT15_WAIT":{"o":17911,"s":61440},"INT15_BLOCKMOVE":{"o":18007,"s":61440},"SHUT9":{"o":18199,"s":61440,"c":"RETURN FROM SHUTDOWN"},"GATE_A20":{"o":18521,"s":61440},"EMPTY_8042":{"o":18546,"s":61440},"EXT_MEMORY":{"o":18555,"s":61440},"X_VIRTUAL":{"o":18567,"s":61440},"TIME_OF_DAY_1":{"o":18709,"s":61440,"c":"BIOS2 (11/15/85)"},"RTC_INT":{"o":19095,"s":61440,"c":"ALARM INTERRUPT (INT 0x70, IRQ 8)"}}} \ No newline at end of file diff --git a/devices/pc/bios/5170/1985-11-15.map b/devices/pc/bios/5170/1985-11-15.map index 4ced11d22..faf254809 100644 --- a/devices/pc/bios/5170/1985-11-15.map +++ b/devices/pc/bios/5170/1985-11-15.map @@ -121,7 +121,7 @@ F000:04C6 @ COMMANDI F000:0505 @ COMMANDO F000:055C @ COMMAND - F000:055C @ WAIT + F000:05C2 @ WAIT F000:05F3 @ NOT_BUSY F000:061A @ WAIT_DRQ F000:0630 @ CHECK_STATUS diff --git a/modules/pcjs/lib/chipset.js b/modules/pcjs/lib/chipset.js index 5f32ff705..97731b4c4 100644 --- a/modules/pcjs/lib/chipset.js +++ b/modules/pcjs/lib/chipset.js @@ -503,16 +503,16 @@ ChipSet.PIC_HI = { // ChipSet.PIC1.PORT_HI or ChipSet.PIC2.PORT_HI ChipSet.IRQ = { TIMER0: 0x00, KBD: 0x01, - SLAVE: 0x02, + SLAVE: 0x02, // MODEL_5170 COM2: 0x03, COM1: 0x04, XTC: 0x05, // MODEL_5160 uses IRQ 5 for HDC (XTC version) LPT2: 0x05, // MODEL_5170 uses IRQ 5 for LPT2 FDC: 0x06, LPT1: 0x07, - RTC: 0x08, - IRQ2: 0x09, - COPROC: 0x0D, + RTC: 0x08, // MODEL_5170 + IRQ2: 0x09, // MODEL_5170 + COPROC: 0x0D, // MODEL_5170 ATC: 0x0E // MODEL_5170 uses IRQ 14 for HDC (ATC version) }; @@ -1332,17 +1332,17 @@ ChipSet.prototype.getRTCCycleLimit = function(nCycles) if (nCyclesUpdate > 0) { if (nCycles > nCyclesUpdate) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.RTC)) { - this.messageDebugger("getRTCCycleLimit(" + nCycles + "): reduced to " + nCyclesUpdate + " cycles"); + this.messageDebugger("getRTCCycleLimit(" + nCycles + "): reduced to " + nCyclesUpdate + " cycles", true); } nCycles = nCyclesUpdate; } else { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.RTC)) { - this.messageDebugger("getRTCCycleLimit(" + nCycles + "): already less than " + nCyclesUpdate + " cycles"); + this.messageDebugger("getRTCCycleLimit(" + nCycles + "): already less than " + nCyclesUpdate + " cycles", true); } } } else { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.RTC)) { - this.messageDebugger("RTC next update has passed by " + nCyclesUpdate + " cycles"); + this.messageDebugger("RTC next update has passed by " + nCyclesUpdate + " cycles", true); } } } @@ -2289,7 +2289,7 @@ ChipSet.prototype.inDMAChannelAddr = function(iDMAC, iChannel, port, addrFrom) var channel = controller.aChannels[iChannel]; var b = channel.addrCurrent[controller.bIndex]; if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".ADDR[" + controller.bIndex + "]", 0, b); + this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".ADDR[" + controller.bIndex + "]", b, true); } controller.bIndex ^= 0x1; /* @@ -2326,7 +2326,7 @@ ChipSet.prototype.outDMAChannelAddr = function outDMAChannelAddr(iDMAC, iChannel { var controller = this.aDMACs[iDMAC]; if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".ADDR[" + controller.bIndex + "]"); + this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".ADDR[" + controller.bIndex + "]", null, true); } var channel = controller.aChannels[iChannel]; channel.addrCurrent[controller.bIndex] = channel.addrInit[controller.bIndex] = bOut; @@ -2349,7 +2349,7 @@ ChipSet.prototype.inDMAChannelCount = function(iDMAC, iChannel, port, addrFrom) var channel = controller.aChannels[iChannel]; var b = channel.countCurrent[controller.bIndex]; if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".COUNT[" + controller.bIndex + "]", 0, b); + this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".COUNT[" + controller.bIndex + "]", b, true); } controller.bIndex ^= 0x1; /* @@ -2390,7 +2390,7 @@ ChipSet.prototype.outDMAChannelCount = function(iDMAC, iChannel, port, bOut, add { var controller = this.aDMACs[iDMAC]; if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".COUNT[" + controller.bIndex + "]"); + this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".COUNT[" + controller.bIndex + "]", null, true); } var channel = controller.aChannels[iChannel]; channel.countCurrent[controller.bIndex] = channel.countInit[controller.bIndex] = bOut; @@ -2433,7 +2433,7 @@ ChipSet.prototype.inDMAStatus = function(iDMAC, port, addrFrom) var b = controller.bStatus | ChipSet.DMA_STATUS.CH0_TC; controller.bStatus &= ~ChipSet.DMA_STATUS.ALL_TC; if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".STATUS", 0, b); + this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".STATUS", b, true); } return b; }; @@ -2450,7 +2450,7 @@ ChipSet.prototype.inDMAStatus = function(iDMAC, port, addrFrom) ChipSet.prototype.outDMACmd = function(iDMAC, port, bOut, addrFrom) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CMD"); + this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CMD", null, true); } this.aDMACs[iDMAC].bCmd = bOut; }; @@ -2478,7 +2478,7 @@ ChipSet.prototype.outDMAReq = function(iDMAC, port, bOut, addrFrom) { var controller = this.aDMACs[iDMAC]; if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".REQ"); + this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".REQ", null, true); } /* * Bits 0-1 contain the channel number @@ -2505,7 +2505,7 @@ ChipSet.prototype.outDMAMask = function(iDMAC, port, bOut, addrFrom) { var controller = this.aDMACs[iDMAC]; if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MASK"); + this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MASK", null, true); } var iChannel = bOut & ChipSet.DMA_MASK.CHANNEL; var channel = controller.aChannels[iChannel]; @@ -2525,7 +2525,7 @@ ChipSet.prototype.outDMAMask = function(iDMAC, port, bOut, addrFrom) ChipSet.prototype.outDMAMode = function(iDMAC, port, bOut, addrFrom) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MODE"); + this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MODE", null, true); } var iChannel = bOut & ChipSet.DMA_MODE.CHANNEL; this.aDMACs[iDMAC].aChannels[iChannel].mode = bOut; @@ -2546,7 +2546,7 @@ ChipSet.prototype.outDMAMode = function(iDMAC, port, bOut, addrFrom) ChipSet.prototype.outDMAResetFF = function(iDMAC, port, bOut, addrFrom) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".RESET_FF"); + this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".RESET_FF", null, true); } this.aDMACs[iDMAC].bIndex = 0; }; @@ -2563,7 +2563,7 @@ ChipSet.prototype.outDMAResetFF = function(iDMAC, port, bOut, addrFrom) ChipSet.prototype.outDMAMasterClear = function(iDMAC, port, bOut, addrFrom) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MASTER_CLEAR"); + this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MASTER_CLEAR", null, true); } /* * The value written to this port doesn't matter; any write triggers a "master clear" operation @@ -2590,7 +2590,7 @@ ChipSet.prototype.inDMAPageReg = function(iDMAC, iChannel, port, addrFrom) { var bIn = this.aDMACs[iDMAC].aChannels[iChannel].bPage; if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".PAGE", 0, bIn); + this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".PAGE", bIn, true); } return bIn; }; @@ -2608,7 +2608,7 @@ ChipSet.prototype.inDMAPageReg = function(iDMAC, iChannel, port, addrFrom) ChipSet.prototype.outDMAPageReg = function(iDMAC, iChannel, port, bOut, addrFrom) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".PAGE"); + this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".PAGE", null, true); } this.aDMACs[iDMAC].aChannels[iChannel].bPage = bOut; }; @@ -2626,7 +2626,7 @@ ChipSet.prototype.inDMAPageSpare = function(iSpare, port, addrFrom) { var bIn = this.abDMAPageSpare[iSpare]; if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, null, addrFrom, "DMA.SPARE" + iSpare + ".PAGE", 0, bIn); + this.messagePort(port, null, addrFrom, "DMA.SPARE" + iSpare + ".PAGE", bIn, true); } return bIn; }; @@ -2643,7 +2643,7 @@ ChipSet.prototype.inDMAPageSpare = function(iSpare, port, addrFrom) ChipSet.prototype.outDMAPageSpare = function(iSpare, port, bOut, addrFrom) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA.SPARE" + iSpare + ".PAGE"); + this.messagePort(port, bOut, addrFrom, "DMA.SPARE" + iSpare + ".PAGE", null, true); } this.abDMAPageSpare[iSpare] = bOut; }; @@ -2713,7 +2713,7 @@ ChipSet.prototype.requestDMA = function(iDMAChannel, done) if (!channel.component || !channel.fnTransfer || !channel.obj) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.OTHER)) { - this.messageDebugger("requestDMA(" + iDMAChannel + "): not connected to a component"); + this.messageDebugger("requestDMA(" + iDMAChannel + "): not connected to a component", true); } if (done) done(true); return; @@ -2730,7 +2730,7 @@ ChipSet.prototype.requestDMA = function(iDMAChannel, done) if (channel.masked) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.OTHER)) { - this.messageDebugger("requestDMA(" + iDMAChannel + "): channel masked, request queued"); + this.messageDebugger("requestDMA(" + iDMAChannel + "): channel masked, request queued", true); } return; } @@ -2783,7 +2783,7 @@ ChipSet.prototype.advanceDMA = function(channel, fInit) if (DEBUG && DEBUGGER && channel.sAddrDebug === null) { channel.sAddrDebug = str.toHex(addr >> 4, 4) + ":" + str.toHex(addr & 0xf, 4); if (this.messageEnabled(this.messageBitsDMA(iDMAChannel)) && channel.xfer != ChipSet.DMA_MODE.XFER_WRITE) { - this.messageDebugger("advanceDMA(" + iDMAChannel + ") transferring " + channel.cbDebug + " bytes from " + channel.sAddrDebug); + this.messageDebugger("advanceDMA(" + iDMAChannel + ") transferring " + channel.cbDebug + " bytes from " + channel.sAddrDebug, true); this.dbg.doDump("db", channel.sAddrDebug, "l" + Math.floor((channel.cbDebug + 15) / 16)); } } @@ -2794,7 +2794,7 @@ ChipSet.prototype.advanceDMA = function(channel, fInit) if (b < 0) { if (!channel.fWarning) { if (DEBUG && obj.messageEnabled(Debugger.MESSAGE.DMA)) { - obj.messageDebugger("advanceDMA(" + iDMAChannel + ") ran out of data, assuming 0xff"); + obj.messageDebugger("advanceDMA(" + iDMAChannel + ") ran out of data, assuming 0xff", true); } channel.fWarning = true; } @@ -2843,7 +2843,7 @@ ChipSet.prototype.advanceDMA = function(channel, fInit) } else { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.WARN)) { - this.messageDebugger("advanceDMA(" + iDMAChannel + ") unsupported xfer mode: " + str.toHexWord(channel.xfer)); + this.messageDebugger("advanceDMA(" + iDMAChannel + ") unsupported xfer mode: " + str.toHexWord(channel.xfer), true); } channel.fError = true; } @@ -2897,7 +2897,7 @@ ChipSet.prototype.updateDMA = function(channel) } if (DEBUG && this.messageEnabled(this.messageBitsDMA(iDMAChannel)) && channel.xfer == ChipSet.DMA_MODE.XFER_WRITE && channel.sAddrDebug) { - this.messageDebugger("updateDMA(" + iDMAChannel + ") transferred " + channel.cbDebug + " bytes to " + channel.sAddrDebug); + this.messageDebugger("updateDMA(" + iDMAChannel + ") transferred " + channel.cbDebug + " bytes to " + channel.sAddrDebug, true); this.dbg.doDump("db", channel.sAddrDebug, "l" + Math.floor((channel.cbDebug + 15) / 16)); } @@ -2938,8 +2938,8 @@ ChipSet.prototype.inPICLo = function(iPIC, addrFrom) break; } } - if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT)) { - this.messagePort(pic.port, null, addrFrom, "PIC" + iPIC, 0, b); + if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT | Debugger.MESSAGE.CHIPSET)) { + this.messagePort(pic.port, null, addrFrom, "PIC" + iPIC, b, true); } return b; }; @@ -2955,8 +2955,8 @@ ChipSet.prototype.inPICLo = function(iPIC, addrFrom) ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom) { var pic = this.aPICs[iPIC]; - if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT)) { - this.messagePort(pic.port, bOut, addrFrom, "PIC" + iPIC); + if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT | Debugger.MESSAGE.CHIPSET)) { + this.messagePort(pic.port, bOut, addrFrom, "PIC" + iPIC, null, true); } if (bOut & ChipSet.PIC_LO.ICW1) { /* @@ -3040,13 +3040,13 @@ ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom) var nIRQ = (nIRL == null? undefined : pic.nIRQBase + nIRL); if (pic.bISR & bIREnd) { if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ))) { - this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): IRQ " + nIRQ + " going out of service"); + this.messageDebugger("outPIC" + iPIC + "(0x" + str.toHexByte(pic.port) + "): IRQ " + nIRQ + " going out of service", true); } pic.bISR &= ~bIREnd; - this.checkIRR(iPIC); + this.checkIRR(); } else { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN)) { - this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): unexpected EOI command, IRQ " + nIRQ + " not in service"); + this.messageDebugger("outPIC" + iPIC + "(0x" + str.toHexByte(pic.port) + "): unexpected EOI command, IRQ " + nIRQ + " not in service", true); if (!SAMPLER && MAXDEBUG) this.dbg.stopCPU(); } } @@ -3054,7 +3054,7 @@ ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom) * TODO: Support EOI commands with automatic rotation (eg, ChipSet.PIC_LO.OCW2_EOI_ROT and ChipSet.PIC_LO.OCW2_EOI_ROTSPEC) */ if (DEBUG && (bOCW2 & ChipSet.PIC_LO.OCW2_SET_ROTAUTO) && this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN)) { - this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): unsupported OCW2 rotate command: " + str.toHexByte(bOut)); + this.messageDebugger("outPIC" + iPIC + "(0x" + str.toHexByte(pic.port) + "): unsupported OCW2 rotate command: " + str.toHexByte(bOut), true); this.dbg.stopCPU(); } } @@ -3069,7 +3069,7 @@ ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom) * TODO: Remaining commands to support: ChipSet.PIC_LO.OCW2_SET_ROTAUTO and ChipSet.PIC_LO.OCW2_CLR_ROTAUTO */ if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN)) { - this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): unsupported OCW2 automatic EOI command: " + str.toHexByte(bOut)); + this.messageDebugger("outPIC" + iPIC + "(0x" + str.toHexByte(pic.port) + "): unsupported OCW2 automatic EOI command: " + str.toHexByte(bOut), true); this.dbg.stopCPU(); } } @@ -3082,7 +3082,7 @@ ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom) */ if (bOut & (ChipSet.PIC_LO.OCW3_POLL_CMD | ChipSet.PIC_LO.OCW3_SMM_CMD)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN)) { - this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): unsupported OCW3 command: " + str.toHexByte(bOut)); + this.messageDebugger("outPIC" + iPIC + "(0x" + str.toHexByte(pic.port) + "): unsupported OCW3 command: " + str.toHexByte(bOut), true); } } pic.bOCW3 = bOut; @@ -3101,8 +3101,8 @@ ChipSet.prototype.inPICHi = function(iPIC, addrFrom) { var pic = this.aPICs[iPIC]; var b = pic.bIMR; - if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT)) { - this.messagePort(pic.port+1, null, addrFrom, "PIC" + iPIC, 0, b); + if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT | Debugger.MESSAGE.CHIPSET)) { + this.messagePort(pic.port+1, null, addrFrom, "PIC" + iPIC, b, true); } return b; }; @@ -3118,8 +3118,8 @@ ChipSet.prototype.inPICHi = function(iPIC, addrFrom) ChipSet.prototype.outPICHi = function(iPIC, bOut, addrFrom) { var pic = this.aPICs[iPIC]; - if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT)) { - this.messagePort(pic.port+1, bOut, addrFrom, "PIC" + iPIC); + if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT | Debugger.MESSAGE.CHIPSET)) { + this.messagePort(pic.port+1, bOut, addrFrom, "PIC" + iPIC, null, true); } if (pic.nICW < pic.aICW.length) { pic.aICW[pic.nICW++] = bOut; @@ -3143,80 +3143,7 @@ ChipSet.prototype.outPICHi = function(iPIC, bOut, addrFrom) * previous models could be handled with a 4-instruction delay provided by the Keyboard.resetDevice() call * to setIRR(), but the MODEL_5170 needs a roughly 6-instruction delay after it unmasks the KBD IRQ. */ - this.checkIRR(iPIC, !iPIC && bOut == 0xFD? 6 : 0); - } -}; - -/** - * checkIRR(iPIC, nDelay) - * - * @this {ChipSet} - * @param {number} iPIC - * @param {number} [nDelay] is an optional number of instructions to delay acknowledgment of the IRQ (see getIRRVector) - */ -ChipSet.prototype.checkIRR = function(iPIC, nDelay) -{ - /* - * Look for any IRR bits that aren't masked and aren't already in service - */ - var pic = this.aPICs[iPIC]; - var bIR = ((pic.bISR | pic.bIMR) ^ 0xff) & pic.bIRR; - this.cpu.updateINTR(!!bIR); - if (bIR && nDelay) pic.nDelay = nDelay; -}; - -/** - * setIRR(nIRQ, nDelay) - * - * @this {ChipSet} - * @param {number} nIRQ (IRQ 0-7 implies iPIC 0, and IRQ 8-15 implies iPIC 1) - * @param {number} [nDelay] is an optional number of instructions to delay acknowledgment of the IRQ (see getIRRVector) - */ -ChipSet.prototype.setIRR = function(nIRQ, nDelay) -{ - var iPIC = nIRQ >> 3; - var nIRL = nIRQ & 0x7; - var pic = this.aPICs[iPIC]; - pic.bIRR |= 1 << nIRL; - if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ))) { - this.messageDebugger("setIRR(" + nIRQ + ")"); - } - pic.nDelay = nDelay || 0; - /* - * When any slave IRR goes high, I'm assuming that the master's slave IRR line should go high as well - */ - if (iPIC == 1) this.aPICs[0].bIRR |= 0x4; - this.checkIRR(iPIC); -}; - -/** - * clearIRR(nIRQ) - * - * @this {ChipSet} - * @param {number} nIRQ (IRQ 0-7 implies iPIC 0, which is all we currently support anyway) - */ -ChipSet.prototype.clearIRR = function(nIRQ) -{ - var iPIC = nIRQ >> 3; - var nIRL = nIRQ & 0x7; - var pic = this.aPICs[iPIC]; - var bIRR = (1 << nIRL); - if (pic.bIRR & bIRR) { - pic.bIRR &= ~bIRR; - if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ))) { - this.messageDebugger("clearIRR(" + nIRQ + ")"); - } - /* - * When all slave IRRs go low, I'm assuming that the master's slave IRR line should go low as well - */ - if (iPIC == 1 && !pic.bIRR) this.aPICs[0].bIRR &= ~0x4; - /* - * NOTE: I don't think calling checkIRR(), and by extension, cpu.updateINTR(false), is strictly necessary, - * because when the CPU gets around to acknowledging the INTR signal, it still has to call getIRRVector(), which - * will inform the CPU that there are no longer any requested interrupts. However, some small efficiency may be - * gained by clearing INTR sooner rather than later. So that's what we'll do. - */ - this.checkIRR(iPIC); + this.checkIRR(!iPIC && bOut == 0xFD? 6 : 0); } }; @@ -3235,6 +3162,101 @@ ChipSet.prototype.checkIMR = function(nIRQ) return (pic.bIMR & (0x1 << nIRL))? true : false; }; +/** + * setIRR(nIRQ, nDelay) + * + * @this {ChipSet} + * @param {number} nIRQ (IRQ 0-7 implies iPIC 0, and IRQ 8-15 implies iPIC 1) + * @param {number} [nDelay] is an optional number of instructions to delay acknowledgment of the IRQ (see getIRRVector) + */ +ChipSet.prototype.setIRR = function(nIRQ, nDelay) +{ + var iPIC = nIRQ >> 3; + var nIRL = nIRQ & 0x7; + var pic = this.aPICs[iPIC]; + pic.bIRR |= 1 << nIRL; + if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ) | Debugger.MESSAGE.CHIPSET)) { + this.messageDebugger("setIRR(" + nIRQ + ")", true); + } + pic.nDelay = nDelay || 0; + /* + * When any (unmasked) slave IRR goes high, the master's slave IRR line should go high as well + */ + if (iPIC == 1 && (pic.bIRR & ~pic.bIMR)) this.aPICs[0].bIRR |= (1 << ChipSet.IRQ.SLAVE); + this.checkIRR(); +}; + +/** + * clearIRR(nIRQ) + * + * @this {ChipSet} + * @param {number} nIRQ (IRQ 0-7 implies iPIC 0, which is all we currently support anyway) + */ +ChipSet.prototype.clearIRR = function(nIRQ) +{ + var iPIC = nIRQ >> 3; + var nIRL = nIRQ & 0x7; + var pic = this.aPICs[iPIC]; + var bIRR = (1 << nIRL); + if (pic.bIRR & bIRR) { + pic.bIRR &= ~bIRR; + if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ) | Debugger.MESSAGE.CHIPSET)) { + this.messageDebugger("clearIRR(" + nIRQ + ")", true); + } + /* + * When all (unmasked) slave IRRs go low, the master's slave IRR line should go low as well + */ + if (iPIC == 1 && !(pic.bIRR & ~pic.bIMR)) this.aPICs[0].bIRR &= ~(1 << ChipSet.IRQ.SLAVE); + /* + * NOTE: I don't think calling checkIRR(), and by extension, cpu.updateINTR(false), is strictly necessary, + * because when the CPU gets around to acknowledging the INTR signal, it still has to call getIRRVector(), + * which will inform the CPU that there are no longer any requested interrupts. + * + * However, some efficiency may be gained by clearing INTR sooner rather than later, so that's what we'll do. + */ + this.checkIRR(); + } +}; + +/** + * checkIRR(nDelay) + * + * @this {ChipSet} + * @param {number} [nDelay] is an optional number of instructions to delay acknowledgment of a pending interrupt + */ +ChipSet.prototype.checkIRR = function(nDelay) +{ + /* + * Look for any IRR bits that aren't masked and aren't already in service; in theory, all we have to + * check is the master PIC (which is the *only* PIC on pre-5170 models), because when any IRQs are set + * or cleared on the slave, that should automatically be reflected in IRQ.SLAVE on the master. + * + * HOWEVER, when a slave interrupt is acknowledged, getIRRVector() ends up clearing the IRR bits for BOTH + * the slave's IRQ and the master's IRQ.SLAVE, setting the corresponding ISR bits, and then when interrupt + * handler send an EOI for both, the corresponding ISR bits are cleared as well. + * + * As a result, if another lower-priority slave IRQ was waiting to be dispatched, that fact would no longer + * be reflected in the master's IRR bit for IRQ.SLAVE. We resolve that problem here, by first checking the + * slave PIC for any unmasked, unserviced interrupts and updating the master's IRR bit for IRQ.SLAVE. + */ + var pic; + var bIR = 0; + + if (this.cPICs > 1) { + pic = this.aPICs[1]; + bIR = ~(pic.bISR | pic.bIMR) & pic.bIRR; + } + + pic = this.aPICs[0]; + if (bIR) pic.bIRR |= (1 << ChipSet.IRQ.SLAVE); + + bIR = ~(pic.bISR | pic.bIMR) & pic.bIRR; + + this.cpu.updateINTR(!!bIR); + + if (bIR && nDelay) pic.nDelay = nDelay; +}; + /** * getIRRVector() * @@ -3283,7 +3305,7 @@ ChipSet.prototype.getIRRVector = function(iPIC) var bIRNext = 1 << nIRL; if (bIR & bIRNext) { - if (!iPIC && nIRL == 2) { + if (!iPIC && nIRL == ChipSet.IRQ.SLAVE) { /* * Slave interrupts are tied to the master PIC on IRQ2; query the slave PIC for the vector # */ @@ -3297,15 +3319,20 @@ ChipSet.prototype.getIRRVector = function(iPIC) if (nIDT >= 0) { pic.bISR |= bIRNext; - pic.bIRR &= ~bIRNext; - } - var nIRQ = pic.nIRQBase + nIRL; - if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ))) { - this.messageDebugger("getIRRVector(): IRQ " + nIRQ + " interrupting @" + str.toHexAddr(this.cpu.regIP, this.cpu.segCS.sel) + " stack=" + str.toHexAddr(this.cpu.regSP, this.cpu.segSS.sel)); - } - if (MAXDEBUG && DEBUGGER) { - this.acInterrupts[nIRQ]++; + /* + * Setting the ISR implies clearing the IRR, but clearIRR() has side-effects we don't want + * (eg, clearing the slave IRQ, notifying the CPU, etc), so we clear the IRR ourselves. + */ + pic.bIRR &= ~bIRNext; + + var nIRQ = pic.nIRQBase + nIRL; + if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ))) { + this.messageDebugger("getIRRVector(): IRQ " + nIRQ + " interrupting @" + str.toHexAddr(this.cpu.regIP, this.cpu.segCS.sel) + " stack=" + str.toHexAddr(this.cpu.regSP, this.cpu.segSS.sel), true); + } + if (MAXDEBUG && DEBUGGER) { + this.acInterrupts[nIRQ]++; + } } break; } @@ -3338,7 +3365,7 @@ ChipSet.prototype.inTimer = function(iTimer, addrFrom) this.updateTimer(iTimer); b = timer.countCurrent[timer.countIndex++]; if (this.messageEnabled(Debugger.MESSAGE.TIMER | Debugger.MESSAGE.PORT)) { - this.messagePort(ChipSet.TIMER0.PORT + iTimer, null, addrFrom, "TIMER" + iTimer, 0, b); + this.messagePort(ChipSet.TIMER0.PORT + iTimer, null, addrFrom, "TIMER" + iTimer, b, true); } return b; }; @@ -3363,7 +3390,7 @@ ChipSet.prototype.inTimer = function(iTimer, addrFrom) ChipSet.prototype.outTimer = function(iTimer, bOut, addrFrom) { if (this.messageEnabled(Debugger.MESSAGE.TIMER | Debugger.MESSAGE.PORT)) { - this.messagePort(ChipSet.TIMER0.PORT + iTimer, bOut, addrFrom, "TIMER" + iTimer); + this.messagePort(ChipSet.TIMER0.PORT + iTimer, bOut, addrFrom, "TIMER" + iTimer, null, true); } var timer = this.aTimers[iTimer]; if (timer.countIndex == timer.countBytes) this.resetTimerIndex(iTimer); @@ -3416,7 +3443,7 @@ ChipSet.prototype.outTimer = function(iTimer, bOut, addrFrom) */ ChipSet.prototype.inTimerCtrl = function(port, addrFrom) { - this.messagePort(port, null, addrFrom, "TIMER_CTRL", Debugger.MESSAGE.TIMER); + this.messagePort(port, null, addrFrom, "TIMER_CTRL", null, Debugger.MESSAGE.TIMER); if (DEBUG) this.messageDebugger("TIMER_CTRL: Read-Back command not supported (yet)", Debugger.MESSAGE.TIMER); return null; }; @@ -3432,7 +3459,7 @@ ChipSet.prototype.inTimerCtrl = function(port, addrFrom) ChipSet.prototype.outTimerCtrl = function(port, bOut, addrFrom) { this.bTimerCtrl = bOut; - this.messagePort(port, bOut, addrFrom, "TIMER_CTRL", Debugger.MESSAGE.TIMER); + this.messagePort(port, bOut, addrFrom, "TIMER_CTRL", null, Debugger.MESSAGE.TIMER); /* * Extract the SC (Select Counter) bits */ @@ -3490,7 +3517,7 @@ ChipSet.prototype.outTimerCtrl = function(port, bOut, addrFrom) timer.countStart[1] = timer.countInit[1]; timer.nCyclesStart = this.cpu.getCycles(this.fScaleTimers); if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) { - this.messageDebugger("TIMER0 count reset @" + timer.nCyclesStart + " cycles"); + this.messageDebugger("TIMER0 count reset @" + timer.nCyclesStart + " cycles", true); } } } @@ -3693,7 +3720,7 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset) if (ticksElapsed < 0) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) { - this.messageDebugger("updateTimer(" + iTimer + "): negative tick count (" + ticksElapsed + ")"); + this.messageDebugger("updateTimer(" + iTimer + "): negative tick count (" + ticksElapsed + ")", true); } timer.nCyclesStart = nCycles; ticksElapsed = 0; @@ -3713,7 +3740,7 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset) if (timer.mode == ChipSet.TIMER_CTRL.MODE0) { if (count <= 0) count = 0; if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) { - this.messageDebugger("updateTimer(" + iTimer + "): MODE0 timer count=" + count); + this.messageDebugger("updateTimer(" + iTimer + "): MODE0 timer count=" + count, true); } if (!count) { timer.fOUT = true; @@ -3748,7 +3775,7 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset) count = countInit + count; if (count <= 0) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) { - this.messageDebugger("updateTimer(" + iTimer + "): underflow=" + count); + this.messageDebugger("updateTimer(" + iTimer + "): underflow=" + count, true); } count = countInit; } @@ -3780,7 +3807,7 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset) count = countInit + count; if (count <= 0) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) { - this.messageDebugger("updateTimer(" + iTimer + "): underflow=" + count); + this.messageDebugger("updateTimer(" + iTimer + "): underflow=" + count, true); } count = countInit; } @@ -3844,7 +3871,7 @@ ChipSet.prototype.inPPIA = function(port, addrFrom) b = this.kbd.readScanCode(); } } - this.messagePort(port, null, addrFrom, "PPI_A", Debugger.MESSAGE.CHIPSET, b); + this.messagePort(port, null, addrFrom, "PPI_A", b); return b; }; @@ -3858,7 +3885,7 @@ ChipSet.prototype.inPPIA = function(port, addrFrom) */ ChipSet.prototype.outPPIA = function(port, bOut, addrFrom) { - this.messagePort(port, bOut, addrFrom, "PPI_A", Debugger.MESSAGE.CHIPSET); + this.messagePort(port, bOut, addrFrom, "PPI_A"); this.bPPIA = bOut; }; @@ -3873,7 +3900,7 @@ ChipSet.prototype.outPPIA = function(port, bOut, addrFrom) ChipSet.prototype.inPPIB = function(port, addrFrom) { var b = this.bPPIB; - this.messagePort(port, null, addrFrom, "PPI_B", Debugger.MESSAGE.CHIPSET, b); + this.messagePort(port, null, addrFrom, "PPI_B", b); return b; }; @@ -3887,7 +3914,7 @@ ChipSet.prototype.inPPIB = function(port, addrFrom) */ ChipSet.prototype.outPPIB = function(port, bOut, addrFrom) { - this.messagePort(port, bOut, addrFrom, "PPI_B", Debugger.MESSAGE.CHIPSET); + this.messagePort(port, bOut, addrFrom, "PPI_B"); this.updatePPIB(bOut); if (this.kbd) this.kbd.setEnable((bOut & ChipSet.PPI_B.CLEAR_KBD)? false : true, (bOut & ChipSet.PPI_B.CLK_KBD)? true : false); }; @@ -3964,7 +3991,7 @@ ChipSet.prototype.inPPIC = function(port, addrFrom) * The ROM BIOS polls this port incessantly during its memory tests, checking for memory parity errors * (which of course we never report), so we further restrict these port messages to MESSAGE_MEM. */ - this.messagePort(port, null, addrFrom, "PPI_C", Debugger.MESSAGE.CHIPSET | Debugger.MESSAGE.MEM, b); + this.messagePort(port, null, addrFrom, "PPI_C", b, Debugger.MESSAGE.CHIPSET | Debugger.MESSAGE.MEM); return b; }; @@ -3978,7 +4005,7 @@ ChipSet.prototype.inPPIC = function(port, addrFrom) */ ChipSet.prototype.outPPIC = function(port, bOut, addrFrom) { - this.messagePort(port, bOut, addrFrom, "PPI_C", Debugger.MESSAGE.CHIPSET); + this.messagePort(port, bOut, addrFrom, "PPI_C"); this.bPPIC = bOut; }; @@ -3993,7 +4020,7 @@ ChipSet.prototype.outPPIC = function(port, bOut, addrFrom) ChipSet.prototype.inPPICtrl = function(port, addrFrom) { var b = this.bPPICtrl; - this.messagePort(port, null, addrFrom, "PPI_CTRL", Debugger.MESSAGE.CHIPSET, b); + this.messagePort(port, null, addrFrom, "PPI_CTRL", b); return b; }; @@ -4007,7 +4034,7 @@ ChipSet.prototype.inPPICtrl = function(port, addrFrom) */ ChipSet.prototype.outPPICtrl = function(port, bOut, addrFrom) { - this.messagePort(port, bOut, addrFrom, "PPI_CTRL", Debugger.MESSAGE.CHIPSET); + this.messagePort(port, bOut, addrFrom, "PPI_CTRL"); this.bPPICtrl = bOut; }; @@ -4022,7 +4049,7 @@ ChipSet.prototype.outPPICtrl = function(port, bOut, addrFrom) ChipSet.prototype.in8042OutBuff = function(port, addrFrom) { var b = this.b8042OutBuff; - this.messagePort(port, null, addrFrom, "8042_OUTBUFF", Debugger.MESSAGE.C8042, b); + this.messagePort(port, null, addrFrom, "8042_OUTBUFF", b, Debugger.MESSAGE.C8042); this.b8042Status &= ~(ChipSet.KBC.STATUS.OUTBUFF_FULL | ChipSet.KBC.STATUS.OUTBUFF_DELAY); var bNext = this.kbd && this.kbd.readScanCode(true); if (bNext) this.set8042OutBuff(bNext); @@ -4043,7 +4070,7 @@ ChipSet.prototype.in8042OutBuff = function(port, addrFrom) */ ChipSet.prototype.out8042InBuffData = function(port, bOut, addrFrom) { - this.messagePort(port, bOut, addrFrom, "8042_INBUF.DATA", Debugger.MESSAGE.C8042); + this.messagePort(port, bOut, addrFrom, "8042_INBUF.DATA", null, Debugger.MESSAGE.C8042); if (this.b8042Status & ChipSet.KBC.STATUS.CMD_FLAG) { switch (this.b8042InBuff) { @@ -4169,7 +4196,7 @@ ChipSet.prototype.in8042RWReg = function(port, addrFrom) * Thanks to the WAITF function, this has become a very "busy" port, so let's not generate messages * unless both MESSAGE_8042 *and* MESSAGE_LOG are set. */ - this.messagePort(port, null, addrFrom, "8042_RWREG", Debugger.MESSAGE.C8042, b); + this.messagePort(port, null, addrFrom, "8042_RWREG", b, Debugger.MESSAGE.C8042); return b; }; @@ -4183,7 +4210,7 @@ ChipSet.prototype.in8042RWReg = function(port, addrFrom) */ ChipSet.prototype.out8042RWReg = function(port, bOut, addrFrom) { - this.messagePort(port, bOut, addrFrom, "8042_RWREG", Debugger.MESSAGE.C8042); + this.messagePort(port, bOut, addrFrom, "8042_RWREG", null, Debugger.MESSAGE.C8042); this.updatePPIB(bOut); }; @@ -4197,7 +4224,7 @@ ChipSet.prototype.out8042RWReg = function(port, bOut, addrFrom) */ ChipSet.prototype.in8042Status = function(port, addrFrom) { - this.messagePort(port, null, addrFrom, "8042_STATUS", Debugger.MESSAGE.C8042, this.b8042Status); + this.messagePort(port, null, addrFrom, "8042_STATUS", this.b8042Status, Debugger.MESSAGE.C8042); var b = this.b8042Status & 0xff; /* * There's code in the 5170 BIOS (F000:03BF) that writes an 8042 command (0xAA), waits for @@ -4235,7 +4262,7 @@ ChipSet.prototype.in8042Status = function(port, addrFrom) */ ChipSet.prototype.out8042InBuffCmd = function(port, bOut, addrFrom) { - this.messagePort(port, bOut, addrFrom, "8042_INBUFF.CMD", Debugger.MESSAGE.C8042); + this.messagePort(port, bOut, addrFrom, "8042_INBUFF.CMD", null, Debugger.MESSAGE.C8042); this.assert(!(this.b8042Status & ChipSet.KBC.STATUS.INBUFF_FULL)); this.b8042InBuff = bOut; @@ -4302,7 +4329,7 @@ ChipSet.prototype.out8042InBuffCmd = function(port, bOut, addrFrom) default: if (DEBUG && this.messageEnabled(Debugger.MESSAGE.C8042)) { - this.messageDebugger("unrecognized 8042 command: " + str.toHexByte(this.b8042InBuff)); + this.messageDebugger("unrecognized 8042 command: " + str.toHexByte(this.b8042InBuff), true); this.dbg.stopCPU(); } break; @@ -4379,7 +4406,7 @@ ChipSet.prototype.set8042OutPort = function(b) * determine if that's what the caller intended. */ if (DEBUG && this.messageEnabled(Debugger.MESSAGE.C8042)) { - this.messageDebugger("unexpected 8042 output port reset: " + str.toHexByte(b)); + this.messageDebugger("unexpected 8042 output port reset: " + str.toHexByte(b), true); this.dbg.stopCPU(); } this.cpu.resetRegs(); @@ -4493,7 +4520,7 @@ ChipSet.prototype.notifyKbdData = function(fAvail) */ ChipSet.prototype.inCMOSAddr = function(port, addrFrom) { - this.messagePort(port, null, addrFrom, "CMOS.ADDR", Debugger.MESSAGE.CMOS, this.bCMOSAddr); + this.messagePort(port, null, addrFrom, "CMOS.ADDR", this.bCMOSAddr, Debugger.MESSAGE.CMOS); return this.bCMOSAddr; }; @@ -4507,7 +4534,7 @@ ChipSet.prototype.inCMOSAddr = function(port, addrFrom) */ ChipSet.prototype.outCMOSAddr = function(port, bOut, addrFrom) { - this.messagePort(port, bOut, addrFrom, "CMOS.ADDR", Debugger.MESSAGE.CMOS); + this.messagePort(port, bOut, addrFrom, "CMOS.ADDR", null, Debugger.MESSAGE.CMOS); this.bCMOSAddr = bOut; this.bNMI = (bOut & ChipSet.CMOS.ADDR.NMI_DISABLE)? ChipSet.NMI.DISABLE : ChipSet.NMI.ENABLE; }; @@ -4525,7 +4552,7 @@ ChipSet.prototype.inCMOSData = function(port, addrFrom) var bAddr = this.bCMOSAddr & ChipSet.CMOS.ADDR.MASK; var bIn = (bAddr <= ChipSet.CMOS.ADDR.STATUSD? this.getRTCByte(bAddr) : this.abCMOSData[bAddr]); if (this.messageEnabled(Debugger.MESSAGE.CMOS | Debugger.MESSAGE.PORT)) { - this.messagePort(port, null, addrFrom, "CMOS.DATA[" + str.toHexByte(bAddr) + "]", 0, bIn); + this.messagePort(port, null, addrFrom, "CMOS.DATA[" + str.toHexByte(bAddr) + "]", bIn, true); } if (addrFrom != null) { if (bAddr == ChipSet.CMOS.ADDR.STATUSC) { @@ -4560,7 +4587,7 @@ ChipSet.prototype.outCMOSData = function(port, bOut, addrFrom) { var bAddr = this.bCMOSAddr & ChipSet.CMOS.ADDR.MASK; if (this.messageEnabled(Debugger.MESSAGE.CMOS | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "CMOS.DATA[" + str.toHexByte(bAddr) + "]"); + this.messagePort(port, bOut, addrFrom, "CMOS.DATA[" + str.toHexByte(bAddr) + "]", null, true); } var bDelta = bOut ^ this.abCMOSData[bAddr]; this.abCMOSData[bAddr] = (bAddr <= ChipSet.CMOS.ADDR.STATUSD? this.setRTCByte(bAddr, bOut) : bOut); @@ -4584,7 +4611,7 @@ ChipSet.prototype.outCMOSData = function(port, bOut, addrFrom) */ ChipSet.prototype.inMFGData = function(port, addrFrom) { - this.messagePort(port, null, addrFrom, "MFG_DATA", Debugger.MESSAGE.CHIPSET, this.bMFGData); + this.messagePort(port, null, addrFrom, "MFG_DATA", this.bMFGData); return this.bMFGData; }; @@ -4598,7 +4625,7 @@ ChipSet.prototype.inMFGData = function(port, addrFrom) */ ChipSet.prototype.outMFGData = function(port, bOut, addrFrom) { - this.messagePort(port, bOut, addrFrom, "MFG_DATA", Debugger.MESSAGE.CHIPSET); + this.messagePort(port, bOut, addrFrom, "MFG_DATA"); this.bMFGData = bOut; }; @@ -4614,7 +4641,7 @@ ChipSet.prototype.outMFGData = function(port, bOut, addrFrom) */ ChipSet.prototype.outNMI = function(port, bOut, addrFrom) { - this.messagePort(port, bOut, addrFrom, "NMI", Debugger.MESSAGE.CHIPSET); + this.messagePort(port, bOut, addrFrom, "NMI"); this.bNMI = bOut; }; @@ -4711,17 +4738,13 @@ ChipSet.prototype.setSpeaker = function(fOn) if (fOn) { if (this.sourceAudio) { this.sourceAudio['frequency']['value'] = freq; - if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) { - this.messageDebugger("speaker set to " + freq + "hz"); - } + if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) this.messageDebugger("speaker set to " + freq + "hz", true); } else { this.sourceAudio = this.contextAudio['createOscillator'](); this.sourceAudio['type'] = 1; // 0: sine wave, 1: square wave, 2: sawtooth wave, 3: triangle wave this.sourceAudio['connect'](this.contextAudio['destination']); this.sourceAudio['frequency']['value'] = freq; - if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) { - this.messageDebugger("speaker on at " + freq + "hz"); - } + if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) this.messageDebugger("speaker on at " + freq + "hz", true); this.sourceAudio['noteOn'](0); // aka start() } } else { @@ -4729,9 +4752,7 @@ ChipSet.prototype.setSpeaker = function(fOn) this.sourceAudio['noteOff'](0); // aka stop() this.sourceAudio['disconnect'](); // QUESTION: is this automatic following a stop(), since this particular source cannot be started again? delete this.sourceAudio; // QUESTION: ditto? - if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) { - this.messageDebugger("speaker off at " + freq + "hz"); - } + if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) this.messageDebugger("speaker off at " + freq + "hz", true); } } } else if (fOn) { @@ -4767,12 +4788,20 @@ ChipSet.prototype.messageBitsDMA = function(iChannel) ChipSet.prototype.messageBitsIRQ = function(nIRQ) { var bitsMessage = Debugger.MESSAGE.PIC; - if (nIRQ == ChipSet.IRQ.TIMER0) { + if (nIRQ == ChipSet.IRQ.TIMER0) { // IRQ 0 bitsMessage |= Debugger.MESSAGE.TIMER; - } else if (nIRQ == ChipSet.IRQ.KBD) { + } else if (nIRQ == ChipSet.IRQ.KBD) { // IRQ 1 bitsMessage |= Debugger.MESSAGE.KBD; - } else if (nIRQ == ChipSet.IRQ.FDC) { + } else if (nIRQ == ChipSet.IRQ.SLAVE) { // IRQ 2 (MODEL_5170 and up) + bitsMessage |= Debugger.MESSAGE.CHIPSET; + } else if (nIRQ == ChipSet.IRQ.XTC) { // IRQ 5 (MODEL_5160) + bitsMessage |= Debugger.MESSAGE.HDC; + } else if (nIRQ == ChipSet.IRQ.FDC) { // IRQ 6 bitsMessage |= Debugger.MESSAGE.FDC; + } else if (nIRQ == ChipSet.IRQ.RTC) { // IRQ 8 (MODEL_5170 and up) + bitsMessage |= Debugger.MESSAGE.RTC; + } else if (nIRQ == ChipSet.IRQ.ATC) { // IRQ 14 (MODEL_5170 and up) + bitsMessage |= Debugger.MESSAGE.HDC; } return bitsMessage; }; diff --git a/modules/pcjs/lib/debugger.js b/modules/pcjs/lib/debugger.js index da25ef076..c9353f9e3 100644 --- a/modules/pcjs/lib/debugger.js +++ b/modules/pcjs/lib/debugger.js @@ -1656,7 +1656,7 @@ if (DEBUGGER) { * at the moment. If that changes, then this will have to change as well. */ addr -= 2; - this.message("INT 0x" + str.toHexByte(nInt) + ": AH=" + str.toHexByte(AH) + " at " + str.toHexAddr(addr - this.cpu.segCS.base, this.cpu.segCS.sel) + sFunc); + this.message("INT 0x" + str.toHexByte(nInt) + ": AH=" + str.toHexByte(AH) + " @" + str.toHexAddr(addr - this.cpu.segCS.base, this.cpu.segCS.sel) + sFunc); } return fMessage; }; @@ -1684,12 +1684,11 @@ if (DEBUGGER) { * @param {number|null} bOut if an output operation * @param {number|null} [addrFrom] * @param {string|null} [name] of the port, if any - * @param {number} [bIn] is the input value, if known, on an input operation + * @param {number|null} [bIn] is the input value, if known, on an input operation * @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) */ Debugger.prototype.messageIO = function(component, port, bOut, addrFrom, name, bIn, bitsMessage) { - if (!bitsMessage) bitsMessage = 0; bitsMessage |= Debugger.MESSAGE.PORT; if (addrFrom == null || (this.bitsMessage & bitsMessage) == bitsMessage) { var segFrom = null; @@ -1697,7 +1696,7 @@ if (DEBUGGER) { segFrom = this.cpu.segCS.sel; addrFrom -= this.cpu.segCS.base; } - this.message(component.idComponent + "." + (bOut != null? "outPort" : "inPort") + "(0x" + str.toHexWord(port) + "," + (name? name : "unknown") + (bOut != null? ",0x" + str.toHexByte(bOut) : "") + ")" + (bIn != null? (": 0x" + str.toHexByte(bIn)) : "") + (addrFrom != null? (" at " + str.toHexAddr(addrFrom, segFrom)) : "")); + this.message(component.idComponent + "." + (bOut != null? "outPort" : "inPort") + "(0x" + str.toHexWord(port) + "," + (name? name : "unknown") + (bOut != null? ",0x" + str.toHexByte(bOut) : "") + ")" + (bIn != null? (": 0x" + str.toHexByte(bIn)) : "") + (addrFrom != null? (" @" + str.toHexAddr(addrFrom, segFrom)) : "")); } }; @@ -4078,7 +4077,7 @@ if (DEBUGGER) { * "biggest" being that the large disk images really need to be compressed first, because they * get "inflated" with use. See the dump() method in the Disk component for more details. */ - this.println(drive.disk.dump()); + this.println(drive.disk.toJSON()); return; } if (dc.seekDrive(drive, iSector, nSectors)) { @@ -4539,6 +4538,10 @@ if (DEBUGGER) { this.incAddr(aAddr, 1); fRepeat = fPrefix = true; break; + case X86.OPCODE.INSB: + case X86.OPCODE.INSW: + case X86.OPCODE.OUTSB: + case X86.OPCODE.OUTSW: case X86.OPCODE.MOVSB: case X86.OPCODE.MOVSW: case X86.OPCODE.CMPSB: diff --git a/modules/pcjs/lib/disk.js b/modules/pcjs/lib/disk.js index 938d6f6dd..39d8f9893 100644 --- a/modules/pcjs/lib/disk.js +++ b/modules/pcjs/lib/disk.js @@ -36,12 +36,12 @@ * 1) creating an empty disk: create() * 2) loading a disk image: load() * 3) getting disk information: info() - * 4) dumping disk contents: dump() - * 5) seeking a disk sector: seek() - * 6) reading data from a sector: read() - * 7) writing data to a sector: write() - * 8) save disk deltas: save() - * 9) restore disk deltas: restore() + * 4) seeking a disk sector: seek() + * 5) reading data from a sector: read() + * 6) writing data to a sector: write() + * 7) save disk deltas: save() + * 8) restore disk deltas: restore() + * 9) converting disk contents: toJSON() * * More functionality may be factored out of the FDC and HDC components later and moved here, to * further reduce some of the duplication between them, but the above functionality is a good start. @@ -1236,39 +1236,6 @@ Disk.prototype.info = function() return [this.aDiskData.length, this.aDiskData[0].length, this.aDiskData[0][0].length, this.aDiskData[0][0][0]['length']]; }; -/** - * dump() - * - * We perform some RegExp massaging on the JSON data to eliminate unnecessary properties - * (eg, 'length' values of 512, 'pattern' values of 0, quotes around the property names, etc). - * Sectors that were initially compressed should remain compressed unless/until they were modified. - * - * TODO: Check sectors (or at least modified sectors) to see if they can be recompressed. - * - * @this {Disk} - * @return {string} containing the entire disk image as JSON-encoded data - */ -Disk.prototype.dump = function() -{ - var s = JSON.stringify(this.aDiskData); - s = s.replace(/,"length":512/gm, "").replace(/,"pattern":0/gm, ""); - /* - * I don't really want to strip quotes from disk image property names, since I would have to put them - * back again during mount() -- or whenever JSON.parse() is used instead of eval(). But I still remove - * them temporarily, so that any remaining property names (eg, "iModify", "cModify", "fDirty") can - * easily be stripped out, by virtue of their being the only quoted properties left. We then "requote" - * all the property names that remain. - */ - s = s.replace(/"(sector|length|data|pattern)":/gm, "$1:"); - /* - * The next line will remove any other numeric or boolean properties that were added at runtime, although - * they may have completely different ("minified") names if the code has been compiled. - */ - s = s.replace(/,"[^"]*":([0-9]+|true|false)/gm, ""); - s = s.replace(/(sector|length|data|pattern):/gm, "\"$1\":"); - return s; -}; - /** * seek(iCylinder, iHead, iSector, fWrite, done) * @@ -1653,6 +1620,74 @@ Disk.prototype.restore = function(deltas) return nChanges; }; +/** + * toJSON() + * + * We perform some RegExp massaging on the JSON data to eliminate unnecessary properties + * (eg, 'length' values of 512, 'pattern' values of 0, quotes around the property names, etc). + * Sectors that were initially compressed should remain compressed unless/until they were modified. + * + * TODO: Check sectors (or at least modified sectors) to see if they can be recompressed. + * + * @this {Disk} + * @return {string} containing the entire disk image as JSON-encoded data + */ +Disk.prototype.toJSON = function() +{ + var s = JSON.stringify(this.aDiskData); + s = s.replace(/,"length":512/gm, "").replace(/,"pattern":0/gm, ""); + /* + * I don't really want to strip quotes from disk image property names, since I would have to put them + * back again during mount() -- or whenever JSON.parse() is used instead of eval(). But I still remove + * them temporarily, so that any remaining property names (eg, "iModify", "cModify", "fDirty") can + * easily be stripped out, by virtue of their being the only quoted properties left. We then "requote" + * all the property names that remain. + */ + s = s.replace(/"(sector|length|data|pattern)":/gm, "$1:"); + /* + * The next line will remove any other numeric or boolean properties that were added at runtime, although + * they may have completely different ("minified") names if the code has been compiled. + */ + s = s.replace(/,"[^"]*":([0-9]+|true|false)/gm, ""); + s = s.replace(/(sector|length|data|pattern):/gm, "\"$1\":"); + return s; +}; + +/** + * dumpSector(sector) + * + * @param {Object} sector (returned from a previous seek) + * @return {string|undefined} + */ +Disk.prototype.dumpSector = function(sector) +{ + var sDump; + if (DEBUG) { + sDump = ""; + var sBytes = "", sChars = ""; + var cbSector = sector['length']; + var cdwData = sector['data'].length; + var dw = 0; + for (var i = 0; i < cbSector; i++) { + if (i % 16 == 0) { + if (sDump) sDump += sBytes + ' ' + sChars + '\n'; + sDump += str.toHexWord(i) + ": "; + sBytes = sChars = ""; + } + if (i % 4 == 0) { + var idw = i >> 2; + dw = (idw < cdwData? sector['data'][idw] : sector['pattern']); + } + var b = dw & 0xff; + dw >>>= 8; + sBytes += str.toHexByte(b) + (i % 16 == 7? "-" : " "); + sChars += (b >= 32 && b < 128? String.fromCharCode(b) : "."); + } + if (sBytes) sDump += sBytes + ' ' + sChars + '\n'; + } + return sDump; +}; + if (typeof APP_PCJS !== 'undefined') APP_PCJS.Disk = Disk; if (typeof module !== 'undefined') module.exports = Disk; diff --git a/modules/pcjs/lib/fdc.js b/modules/pcjs/lib/fdc.js index 69048bb90..2d1596a49 100644 --- a/modules/pcjs/lib/fdc.js +++ b/modules/pcjs/lib/fdc.js @@ -2026,10 +2026,10 @@ FDC.prototype.popCmd = function(name) { this.assert((!this.regDataIndex || name !== undefined) && this.regDataIndex < this.regDataTotal); var bCmd = this.regDataArray[this.regDataIndex]; - if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PORT)) { + if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PORT | Debugger.MESSAGE.FDC)) { var bCmdMasked = bCmd & FDC.REG_DATA.CMD.MASK; if (!name && !this.regDataIndex && FDC.aCmdInfo[bCmdMasked]) name = FDC.aCmdInfo[bCmdMasked].name; - this.messageDebugger("FDC.CMD[" + (name || this.regDataIndex) + "]: 0x" + str.toHexByte(bCmd)); + this.messageDebugger("FDC.CMD[" + (name || this.regDataIndex) + "]: 0x" + str.toHexByte(bCmd), true); } this.regDataIndex++; return bCmd; @@ -2080,8 +2080,8 @@ FDC.prototype.beginResult = function() */ FDC.prototype.pushResult = function(bResult, name) { - if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PORT)) { - this.messageDebugger("FDC.RES[" + (name || this.regDataTotal) + "]: 0x" + str.toHexByte(bResult)); + if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PORT | Debugger.MESSAGE.FDC)) { + this.messageDebugger("FDC.RES[" + (name || this.regDataTotal) + "]: 0x" + str.toHexByte(bResult), true); } this.regDataArray[this.regDataTotal++] = bResult; }; diff --git a/modules/pcjs/lib/hdc.js b/modules/pcjs/lib/hdc.js index 3a1fcf641..9e373ba01 100644 --- a/modules/pcjs/lib/hdc.js +++ b/modules/pcjs/lib/hdc.js @@ -891,7 +891,7 @@ HDC.prototype.initDrive = function(iDrive, drive, driveConfig, data, fHard) this.verifyDrive(drive); /* - * The next group of properties are managed by worker functions (eg, doRead()) to maintain state across DMA requests. + * The next group of properties are managed by worker functions (eg, doDMARead()) to maintain state across DMA requests. */ drive.ibSector = data[i++]; // location of the next byte to be accessed in the above sector drive.sector = null; // initialized to null by worker, and then set to the next sector satisfying the request @@ -1082,7 +1082,7 @@ HDC.prototype.seekDrive = function(drive, iSector, nSectors) drive.errorCode = HDC.XTC.DATA.ERR.NONE; /* * At this point, we've finished simulating what an HDC.XTC.DATA.CMD.READ_DATA command would have performed, - * up through doRead(). Now it's the caller responsibility to call readByte(), like the DMA Controller would. + * up through doDMARead(). Now it's the caller responsibility to call readByte(), like the DMA Controller would. */ return true; } @@ -1261,7 +1261,7 @@ HDC.prototype.outXTCData = function(port, bOut, addrFrom) */ this.regStatus |= HDC.XTC.STATUS.IOMODE; this.regStatus &= ~HDC.XTC.STATUS.REQ; - this.doXTCommand(); + this.doXTC(); } }; @@ -1386,14 +1386,8 @@ HDC.prototype.outXTCNoise = function(port, bOut, addrFrom) HDC.prototype.inATCData = function(port, addrFrom) { var bIn = -1; - var fSuppress = false; if (this.drive) { - /* - * messagePort() calls, if enabled, can be overwhelming for this port, so limit them to the first byte. - */ - fSuppress = (this.drive.ibSector > 0); - /* * We use the synchronous form of readByte() at this point because we have no choice; an I/O instruction * has just occurred and cannot be delayed. The good news is that doATCommand() should have already primed @@ -1407,7 +1401,22 @@ HDC.prototype.inATCData = function(port, addrFrom) * Now that we've supplied a full sector of data, see if the caller's expecting additional sectors; * if so, prime the pump again. The caller should not poll us again until another interrupt's been delivered. */ - if (this.drive.ibSector == this.drive.cbSector) { + if (this.drive.ibSector == 1) { + /* + * messagePort() calls, if enabled, can be overwhelming for this port, so limit them to the first byte + * of each sector. + */ + if (this.messageEnabled(Debugger.MESSAGE.PORT | Debugger.MESSAGE.HDC)) { + this.messagePort(port, null, addrFrom, "DATA[" + this.drive.ibSector + "]", bIn); + } + } + else if (this.drive.ibSector == this.drive.cbSector) { + + if (this.messageEnabled(Debugger.MESSAGE.OTHER | Debugger.MESSAGE.HDC)) { + var sDump = this.drive.disk.dumpSector(this.drive.sector); + if (sDump) this.dbg.message(sDump); + } + this.drive.nBytes -= this.drive.cbSector; this.regSecCnt = (this.regSecCnt - 1) & 0xff; /* @@ -1416,13 +1425,11 @@ HDC.prototype.inATCData = function(port, addrFrom) */ if (this.drive.nBytes >= this.drive.cbSector) { var hdc = this; + hdc.regStatus = HDC.ATC.STATUS.BUSY | HDC.ATC.STATUS.DATA_REQ; this.readByte(this.drive, function(b, fAsync) { if (b >= 0) { hdc.setATCIRR(); - /* - * I shouldn't have to set BUSY (or DATA_REQ) again, because it should still be set, no? - */ - hdc.assert(!!(hdc.regStatus & HDC.ATC.STATUS.BUSY)); + hdc.regStatus = HDC.ATC.STATUS.READY | HDC.ATC.STATUS.SEEK_OK; } else { /* * TODO: It would be nice to be a bit more specific about the error (if any) that just occurred. @@ -1439,7 +1446,6 @@ HDC.prototype.inATCData = function(port, addrFrom) } } } - if (!fSuppress) this.messagePort(port, null, addrFrom, "DATA", bIn); return bIn; }; @@ -1453,11 +1459,6 @@ HDC.prototype.inATCData = function(port, addrFrom) */ HDC.prototype.outATCData = function(port, bOut, addrFrom) { - /* - * messagePort() calls, if enabled, can be overwhelming for this port, so limit them to the first byte. - */ - if (!this.drive || !this.drive.ibSector) this.messagePort(port, bOut, addrFrom, "DATA"); - if (this.drive) { if (this.drive.nBytes >= this.drive.cbSector) { if (this.writeByte(this.drive, bOut) < 0) { @@ -1471,18 +1472,30 @@ HDC.prototype.outATCData = function(port, bOut, addrFrom) this.messageDebugger("HDC.outATCData(" + str.toHexByte(bOut) + "): write failed"); } } + else if (this.drive.ibSector == 1) { + /* + * messagePort() calls, if enabled, can be overwhelming for this port, so limit them to the first byte + * of each sector. + */ + if (this.messageEnabled(Debugger.MESSAGE.PORT | Debugger.MESSAGE.HDC)) { + this.messagePort(port, bOut, addrFrom, "DATA[" + this.drive.ibSector + "]"); + } + } else if (this.drive.ibSector == this.drive.cbSector) { + + if (this.messageEnabled(Debugger.MESSAGE.OTHER | Debugger.MESSAGE.HDC)) { + var sDump = this.drive.disk.dumpSector(this.drive.sector); + if (sDump) this.dbg.message(sDump); + } + this.drive.nBytes -= this.drive.cbSector; this.regSecCnt = (this.regSecCnt - 1) & 0xff; - this.setATCIRR(); + this.setATCIRR(true); + this.regStatus = HDC.ATC.STATUS.READY | HDC.ATC.STATUS.SEEK_OK; if (this.drive.nBytes >= this.drive.cbSector) { - /* - * I shouldn't have to set BUSY (or DATA_REQ) again, because it should still be set, no? - */ - this.assert(!!(this.regStatus & HDC.ATC.STATUS.BUSY)); + this.regStatus |= HDC.ATC.STATUS.DATA_REQ; } else { this.assert(!this.drive.nBytes); - this.regStatus = HDC.ATC.STATUS.READY | HDC.ATC.STATUS.SEEK_OK; } } } else { @@ -1710,6 +1723,7 @@ HDC.prototype.inATCStatus = function(port, addrFrom) { var bIn = this.regStatus; this.messagePort(port, null, addrFrom, "STATUS", bIn); + if (this.chipset) this.chipset.clearIRR(ChipSet.IRQ.ATC); return bIn; }; @@ -1726,7 +1740,7 @@ HDC.prototype.outATCCommand = function(port, bOut, addrFrom) this.messagePort(port, bOut, addrFrom, "COMMAND"); this.regCommand = bOut; if (this.chipset) this.chipset.clearIRR(ChipSet.IRQ.ATC); - this.doATCommand(); + this.doATC(); }; /** @@ -1752,13 +1766,13 @@ HDC.prototype.outATCFDR = function(port, bOut, addrFrom) }; /** - * doATCommand() + * doATC() * * Handles ATC (AT Controller) commands * * @this {HDC} */ -HDC.prototype.doATCommand = function() +HDC.prototype.doATC = function() { var hdc = this; var fInterrupt = false; @@ -1790,35 +1804,40 @@ HDC.prototype.doATCommand = function() * follow-up I/O instructions. For example, any subsequent inATCData() and outATCData() calls need to * know which drive to talk to ("this.drive"), to issue their own readByte() and writeByte() calls. * - * The XTC didn't need this, because it used doRead(), doWrite(), doFormat() helper functions, which - * reset the current drive's "sector" and "errorCode" properties themselves and then used DMA functions - * that delivered drive data with direct calls to readByte() and writeByte(). + * The XTC didn't need this, because it used doDMARead(), doDMAWrite(), doDMAFormat() helper functions, + * which reset the current drive's "sector" and "errorCode" properties themselves and then used DMA + * functions that delivered drive data with direct calls to readByte() and writeByte(). */ drive.sector = null; + drive.ibSector = 0; drive.errorCode = 0; this.drive = drive; } - if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PORT | Debugger.MESSAGE.HDC)) { - this.messageDebugger("HDC.doATCommand(" + str.toHexByte(bCmd) + "): " + HDC.aATCCommands[bCmd]); + if (DEBUG && this.messageEnabled(Debugger.MESSAGE.HDC)) { + this.messageDebugger("HDC.doATC(0x" + str.toHexByte(bCmd) + "): " + HDC.aATCCommands[bCmd], true); } switch (bCmd & HDC.ATC.COMMAND.MASK) { case HDC.ATC.COMMAND.READ_DATA: + if (DEBUG && this.messageEnabled(Debugger.MESSAGE.HDC)) { + this.messageDebugger("HDC.doRead(" + iDrive + ',' + drive.wCylinder + ':' + drive.bHead + ':' + drive.bSector + ',' + nSectors + ")", true); + } /* * We're using a call to readByte() that disables auto-increment, so that once we've got the first * byte of the next sector, we can signal an interrupt without also consuming the first byte, allowing * inATCData() to begin with that byte. + * + * As with the WRITE_DATA command, I'm not sure which of BUSY and DATA_REQ (or both) should be set here, + * so I'm setting both of them for now. I clear them as soon as I have data. */ + hdc.regStatus = HDC.ATC.STATUS.BUSY | HDC.ATC.STATUS.DATA_REQ; + this.readByte(drive, function(b, fAsync) { if (b >= 0 && hdc.chipset) { hdc.setATCIRR(); - /* - * As with the WRITE_DATA command, I'm not sure which of BUSY and DATA_REQ (or both) - * should be set here, so I'm setting both of them for now. - */ - hdc.regStatus = HDC.ATC.STATUS.BUSY | HDC.ATC.STATUS.DATA_REQ; + hdc.regStatus = HDC.ATC.STATUS.READY | HDC.ATC.STATUS.SEEK_OK; } else { /* * TODO: It would be nice to be a bit more specific about the error (if any) that just occurred. @@ -1831,17 +1850,10 @@ HDC.prototype.doATCommand = function() break; case HDC.ATC.COMMAND.WRITE_DATA: - if (this.chipset) { - this.setATCIRR(); - /* - * I know that DATA_REQ must be set at this point, but I'm not sure about BUSY; so I'm - * setting both of them for now. - */ - this.regStatus = HDC.ATC.STATUS.BUSY | HDC.ATC.STATUS.DATA_REQ; - } else { - this.regStatus = HDC.ATC.STATUS.ERROR; - this.regError = HDC.ATC.ERROR.CMD_ABORT; + if (DEBUG && this.messageEnabled(Debugger.MESSAGE.HDC)) { + this.messageDebugger("HDC.doWrite(" + iDrive + ',' + drive.wCylinder + ':' + drive.bHead + ':' + drive.bSector + ',' + nSectors + ")", true); } + this.regStatus = HDC.ATC.STATUS.DATA_REQ; break; case HDC.ATC.COMMAND.RESTORE: @@ -1853,7 +1865,8 @@ HDC.prototype.doATCommand = function() case HDC.ATC.COMMAND.READ_VERF: /* - * Since the READ VERIFY command returns no data, once again, logically, there isn't much for us to do. + * Since the READ VERIFY command returns no data, once again, logically, there isn't much we HAVE to + * to do, but... TODO: Verify that all the disk parameters are valid, and return an error if they're not. */ fInterrupt = true; break; @@ -1871,8 +1884,8 @@ HDC.prototype.doATCommand = function() * * WPREC: 0x4B * SECCNT: 0x11 (for 17 sectors per track) - * CYL: 0x100 (256 -- uh, what?) - * SECNUM: 0x0C (12 -- uh, what?) + * CYL: 0x100 (256 -- huh?) + * SECNUM: 0x0C (12 -- huh?) * DRVHD: 0xA3 (max head of 0x03, for 4 total heads) * * The importance of SECCNT (nSectors) and DRVHD (nHeads) is controlling how multi-sector operations @@ -1887,7 +1900,7 @@ HDC.prototype.doATCommand = function() default: if (DEBUG && this.messageEnabled()) { - this.messageDebugger("HDC.doATCommand(" + str.toHexByte(this.regCommand) + "): " + (bCmd < 0? ("invalid drive (" + iDrive + ")") : "unsupported operation")); + this.messageDebugger("HDC.doATC(0x" + str.toHexByte(this.regCommand) + "): " + (bCmd < 0? ("invalid drive (" + iDrive + ")") : "unsupported operation")); if (bCmd >= 0) this.dbg.stopCPU(); } break; @@ -1897,25 +1910,33 @@ HDC.prototype.doATCommand = function() }; /** - * setATCIRR() + * setATCIRR(fWrite) * * Raise the ATC's IRQ, provided ATC interrupts are enabled. * * @this {HDC} + * @param {boolean} [fWrite] is true on completion of a write to the sector buffer */ -HDC.prototype.setATCIRR = function() +HDC.prototype.setATCIRR = function(fWrite) { - if (this.chipset && !(this.regFDR & HDC.ATC.FDR.INT_DISABLE)) this.chipset.setIRR(ChipSet.IRQ.ATC); + if (this.chipset) { + if (!(this.regFDR & HDC.ATC.FDR.INT_DISABLE)) { + this.chipset.setIRR(ChipSet.IRQ.ATC); + if (DEBUG) this.messageDebugger("HDC.setATCIRR(): enabled", Debugger.MESSAGE.PIC | Debugger.MESSAGE.HDC); + } else { + if (DEBUG) this.messageDebugger("HDC.setATCIRR(): disabled", Debugger.MESSAGE.PIC | Debugger.MESSAGE.HDC); + } + } }; /** - * doXTCommand() + * doXTC() * * Handles XTC (XT Controller) commands * * @this {HDC} */ -HDC.prototype.doXTCommand = function() +HDC.prototype.doXTC = function() { var hdc = this; this.regDataIndex = 0; @@ -1985,7 +2006,7 @@ HDC.prototype.doXTCommand = function() bDataStatus = HDC.XTC.DATA.STATUS_OK; if (!drive && this.iDriveAllowFail == iDrive) { this.iDriveAllowFail = -1; - if (DEBUG) this.messageDebugger("HDC.doXTCommand(): fake failure triggered"); + if (DEBUG) this.messageDebugger("HDC.doXTC(): fake failure triggered"); bDataStatus = HDC.XTC.DATA.STATUS_ERROR; } this.beginResult(bDataStatus | bDrive); @@ -2022,7 +2043,7 @@ HDC.prototype.doXTCommand = function() case HDC.XTC.DATA.CMD.RECALIBRATE: // 0x01 drive.bControl = bControl; if (DEBUG && this.messageEnabled()) { - this.messageDebugger("HDC.doXTCommand(): drive " + iDrive + " control byte: 0x" + str.toHexByte(bControl)); + this.messageDebugger("HDC.doXTC(): drive " + iDrive + " control byte: 0x" + str.toHexByte(bControl)); } this.beginResult(HDC.XTC.DATA.STATUS_OK | bDrive); break; @@ -2035,7 +2056,7 @@ HDC.prototype.doXTCommand = function() break; case HDC.XTC.DATA.CMD.READ_DATA: // 0x08 - this.doRead(drive, function(bStatus) { + this.doDMARead(drive, function(bStatus) { hdc.beginResult(bStatus | bDrive); }); break; @@ -2046,13 +2067,13 @@ HDC.prototype.doXTCommand = function() * but it is omitted from the HDC.XTC.DATA.CMD.READ_DATA command. Is that correct? Note that, as far as the length * of the transfer is concerned, we rely exclusively on the DMA controller being programmed with the appropriate byte count. */ - this.doWrite(drive, function(bStatus) { + this.doDMAWrite(drive, function(bStatus) { hdc.beginResult(bStatus | bDrive); }); break; case HDC.XTC.DATA.CMD.WRITE_BUFFER: // 0x0F - this.doWriteToBuffer(drive, function(bStatus) { + this.doDMAWriteBuffer(drive, function(bStatus) { hdc.beginResult(bStatus | bDrive); }); break; @@ -2060,7 +2081,7 @@ HDC.prototype.doXTCommand = function() default: this.beginResult(HDC.XTC.DATA.STATUS_ERROR | bDrive); if (DEBUG && this.messageEnabled()) { - this.messageDebugger("HDC.doXTCommand(" + str.toHexByte(bCmdOrig) + "): " + (bCmd < 0? ("invalid drive (" + iDrive + ")") : "unsupported operation")); + this.messageDebugger("HDC.doXTC(0x" + str.toHexByte(bCmdOrig) + "): " + (bCmd < 0? ("invalid drive (" + iDrive + ")") : "unsupported operation")); if (bCmd >= 0) this.dbg.stopCPU(); } break; @@ -2081,7 +2102,7 @@ HDC.prototype.popCmd = function() if (bCmdIndex < this.regDataTotal) { bCmd = this.regDataArray[this.regDataIndex++]; if (DEBUG && this.messageEnabled((bCmdIndex > 0? Debugger.MESSAGE.PORT : 0) | Debugger.MESSAGE.HDC)) { - this.messageDebugger("HDC.CMD[" + bCmdIndex + "]: 0x" + str.toHexByte(bCmd) + (!bCmdIndex && HDC.aXTCCommands[bCmd]? (" (" + HDC.aXTCCommands[bCmd] + ")") : "")); + this.messageDebugger("HDC.CMD[" + bCmdIndex + "]: 0x" + str.toHexByte(bCmd) + (!bCmdIndex && HDC.aXTCCommands[bCmd]? (" (" + HDC.aXTCCommands[bCmd] + ")") : ""), true); } } return bCmd; @@ -2121,7 +2142,7 @@ HDC.prototype.beginResult = function(bResult) HDC.prototype.pushResult = function(bResult) { if (DEBUG && this.messageEnabled((this.regDataTotal > 0? Debugger.MESSAGE.PORT : 0) | Debugger.MESSAGE.HDC)) { - this.messageDebugger("HDC.RES[" + this.regDataTotal + "]: 0x" + str.toHexByte(bResult)); + this.messageDebugger("HDC.RES[" + this.regDataTotal + "]: 0x" + str.toHexByte(bResult), true); } this.regDataArray[this.regDataTotal++] = bResult; }; @@ -2205,18 +2226,18 @@ HDC.prototype.dmaWriteFormat = function(drive, b) }; /** - * doRead(drive, done) + * doDMARead(drive, done) * * @this {HDC} * @param {Object} drive * @param {function(number)} done (dataStatus is XTC.DATA.STATUS_OK or XTC.DATA.STATUS_ERROR; if error, then drive.errorCode should be set as well) */ -HDC.prototype.doRead = function(drive, done) +HDC.prototype.doDMARead = function(drive, done) { drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY; if (DEBUG && this.messageEnabled()) { - this.messageDebugger("HDC.doRead(" + drive.wCylinder + ":" + drive.bHead + ":" + drive.bSector + ")"); + this.messageDebugger("HDC.doDMARead(" + drive.iDrive + ',' + drive.wCylinder + ':' + drive.bHead + ':' + drive.bSector + ',' + ((drive.nBytes / drive.cbSector)|0) + ")"); } if (drive.disk) { @@ -2249,18 +2270,18 @@ HDC.prototype.doRead = function(drive, done) }; /** - * doWrite(drive, done) + * doDMAWrite(drive, done) * * @this {HDC} * @param {Object} drive * @param {function(number)} done (dataStatus is XTC.DATA.STATUS_OK or XTC.DATA.STATUS_ERROR; if error, then drive.errorCode should be set as well) */ -HDC.prototype.doWrite = function(drive, done) +HDC.prototype.doDMAWrite = function(drive, done) { drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY; if (DEBUG && this.messageEnabled()) { - this.messageDebugger("HDC.doWrite(" + drive.wCylinder + ":" + drive.bHead + ":" + drive.bSector + ")"); + this.messageDebugger("HDC.doDMAWrite(" + drive.iDrive + ',' + drive.wCylinder + ':' + drive.bHead + ':' + drive.bSector + ',' + ((drive.nBytes / drive.cbSector)|0) + ")"); } if (drive.disk) { @@ -2300,17 +2321,17 @@ HDC.prototype.doWrite = function(drive, done) }; /** - * doWriteToBuffer(drive, done) + * doDMAWriteBuffer(drive, done) * * @this {HDC} * @param {Object} drive * @param {function(number)} done (dataStatus is XTC.DATA.STATUS_OK or XTC.DATA.STATUS_ERROR; if error, then drive.errorCode should be set as well) */ -HDC.prototype.doWriteToBuffer = function(drive, done) +HDC.prototype.doDMAWriteBuffer = function(drive, done) { drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY; - if (DEBUG) this.messageDebugger("HDC.doWriteToBuffer()"); + if (DEBUG) this.messageDebugger("HDC.doDMAWriteBuffer()"); if (!drive.abSector || drive.abSector.length != drive.nBytes) { drive.abSector = new Array(drive.nBytes); @@ -2343,9 +2364,9 @@ HDC.prototype.doWriteToBuffer = function(drive, done) }; /** - * doFormat(drive, done) + * doDMAFormat(drive, done) * - * The drive variable is initialized by doXTCommand() to the following extent: + * The drive variable is initialized by doXTC() to the following extent: * * drive.bHead (ignored) * drive.nBytes (bytes/sector) @@ -2358,7 +2379,7 @@ HDC.prototype.doWriteToBuffer = function(drive, done) * @param {Object} drive * @param {function(number)} done (dataStatus is XTC.DATA.STATUS_OK or XTC.DATA.STATUS_ERROR; if error, then drive.errorCode should be set as well) */ -HDC.prototype.doFormat = function(drive, done) +HDC.prototype.doDMAFormat = function(drive, done) { drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY; diff --git a/modules/pcjs/lib/keyboard.js b/modules/pcjs/lib/keyboard.js index 1e9259e25..817e96165 100644 --- a/modules/pcjs/lib/keyboard.js +++ b/modules/pcjs/lib/keyboard.js @@ -967,7 +967,7 @@ Keyboard.prototype.resetDevice = function() /* * TODO: There's more to reset, like LED indicators, default type rate, and emptying the scan code buffer. */ - this.messageDebugger("keyboard reset", Debugger.MESSAGE.PORT); + this.messageDebugger("keyboard reset", Debugger.MESSAGE.KBD | Debugger.MESSAGE.PORT); this.abScanBuffer = [Keyboard.CMDRES.BAT_SUCC]; if (this.chipset) this.chipset.notifyKbdData(true); }; @@ -989,8 +989,8 @@ Keyboard.prototype.setEnable = function(fData, fClock) { var fReset = false; if (this.fClock !== fClock) { - if (DEBUG && this.messageEnabled()) { - this.messageDebugger("keyboard clock line changing to " + fClock, Debugger.MESSAGE.PORT); + if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KBD | Debugger.MESSAGE.PORT)) { + this.messageDebugger("keyboard clock line changing to " + fClock, true); } /* * Toggling the clock line low and then high signals a "reset", which we acknowledge once the @@ -999,8 +999,8 @@ Keyboard.prototype.setEnable = function(fData, fClock) this.fClock = this.fResetOnEnable = fClock; } if (this.fData !== fData) { - if (DEBUG && this.messageEnabled()) { - this.messageDebugger("keyboard data line changing to " + fData, Debugger.MESSAGE.PORT); + if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KBD | Debugger.MESSAGE.PORT)) { + this.messageDebugger("keyboard data line changing to " + fData, true); } this.fData = fData; /* @@ -1637,7 +1637,7 @@ Keyboard.prototype.keyUpDown = function(event, fDown) } if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KEYS)) { - this.messageDebugger(/*(fDown?"\n":"") +*/ "key" + (fDown? "Down" : "Up") + "(" + keyCode + "): " + (fPass? "pass" : "consume")); + this.messageDebugger(/*(fDown?"\n":"") +*/ "key" + (fDown? "Down" : "Up") + "(" + keyCode + "): " + (fPass? "pass" : "consume"), true); } return fPass; }; @@ -1687,7 +1687,7 @@ Keyboard.prototype.keyPress = function(event) } if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KEYS)) { - this.messageDebugger("keyPress(" + keyCode + "): " + (fPass? "pass" : "consume")); + this.messageDebugger("keyPress(" + keyCode + "): " + (fPass? "pass" : "consume"), true); } return fPass; }; @@ -1749,7 +1749,7 @@ Keyboard.prototype.keySimulatePress = function(keyCode, fCheckShift, fQuickRelea fSimulated = true; } if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KEYS)) { - this.messageDebugger("keySimulatePress(" + keyCode + "): " + (fSimulated? "true" : "false")); + this.messageDebugger("keySimulatePress(" + keyCode + "): " + (fSimulated? "true" : "false"), true); } return fSimulated; }; @@ -1836,7 +1836,7 @@ Keyboard.prototype.keySimulateUpOrDown = function(keyCode, fDown, simCode) fSimulated = true; } if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KEYS)) { - this.messageDebugger("keySimulateUpOrDown(" + keyCode + "," + (fDown? "down" : "up") + "," + Keyboard.aSimCodeDescs[simCode] + "): " + (fSimulated? "true" : "false")); + this.messageDebugger("keySimulateUpOrDown(" + keyCode + "," + (fDown? "down" : "up") + "," + Keyboard.aSimCodeDescs[simCode] + "): " + (fSimulated? "true" : "false"), true); } return fSimulated; }; diff --git a/modules/pcjs/lib/video.js b/modules/pcjs/lib/video.js index 5a4fb7677..dd304d0fd 100644 --- a/modules/pcjs/lib/video.js +++ b/modules/pcjs/lib/video.js @@ -43,16 +43,6 @@ if (typeof module !== 'undefined') { var Debugger = require("./debugger"); } -/** - * @class Font - * @property {number} cxCell - * @property {number} cyCell - * @property {Array} aCSSColors - * @property {Array} aRGBColors - * @property {Array} aColorMap - * @property {Array} aCanvas - */ - /** * Video(parmsVideo, canvas, context, textarea) * @@ -171,14 +161,13 @@ function Video(parmsVideo, canvas, context, textarea) * Originally, setMode() would map/unmap the video buffer ONLY when the active card changed, * because as long as an MDA or CGA remained active, its video buffer never changed. However, * since the EGA can change its video buffer on the fly, setMode() must also compare the card's - * hard-coded and/or programmed) buffer address/size to the "active" address/size; the latter + * hard-coded and/or programmed buffer address/size to the "active" address/size; the latter * is recorded here. */ this.addrBuffer = this.sizeBuffer = 0; /* - * aFonts is an array of font objects (ie, arrays) indexed by FONT ID. Font characters are - * arranged in 16x16 grids, with one grid per canvas object in the aCanvas array of each font object. + * aFonts is an array of font objects indexed by FONT ID. Font characters are * arranged in 16x16 grids, with one grid per canvas object in the aCanvas array of each font object. * * Each element is a Font object that describes the font size and provides bitmaps for all the font * color permutations. aFonts.length will be non-zero if ANY fonts are loaded, but do NOT assume @@ -495,6 +484,16 @@ Video.MODES.EGA_640X350_MONO = 0x0F; // mapped at A000:0000, monochrome Video.MODES.EGA_640X350 = 0x10; // mapped at A000:0000, color Video.MODES.UNKNOWN = 0xFF; +/** + * @class Font + * @property {number} cxCell + * @property {number} cyCell + * @property {Array} aCSSColors + * @property {Array} aRGBColors + * @property {Array} aColorMap + * @property {Array} aCanvas + */ + /* * Supported Fonts * diff --git a/modules/pcjs/lib/x86cpu.js b/modules/pcjs/lib/x86cpu.js index 999e2a868..6ee82017d 100644 --- a/modules/pcjs/lib/x86cpu.js +++ b/modules/pcjs/lib/x86cpu.js @@ -2516,13 +2516,13 @@ X86CPU.prototype.stepCPU = function(nMinCycles) this.opPrefixes = this.opFlags & X86.OPFLAG.REPEAT; if (this.intFlags) { if (this.checkINTR()) { - /* - * ASSERT: If it's never possible to have !nMinCycles WITHOUT the Debugger, then all we need - * to check is !nMinCycles. - */ - if (DEBUGGER && !nMinCycles) { - this.opFlags = 0; - break; + if (!nMinCycles) { + this.assert(DEBUGGER); // nMinCycles of zero should be generated ONLY by the Debugger + if (DEBUGGER) { + this.println("interrupt dispatched"); + this.opFlags = 0; + break; + } } } if (this.intFlags & X86.INTFLAG.HALT) { diff --git a/modules/pcjs/lib/x86help.js b/modules/pcjs/lib/x86help.js index eb73814a9..d5fa674f9 100644 --- a/modules/pcjs/lib/x86help.js +++ b/modules/pcjs/lib/x86help.js @@ -691,7 +691,7 @@ var X86Help = { if (this.messageEnabled(bitsMessage) || fHalt) { var sMessage = (fHalt? '\n' : '') + "Fault " + str.toHexByte(nFault) + (nError != null? " (" + str.toHexWord(nError) + ")" : "") + " on opcode 0x" + str.toHexByte(bOpcode) + " at " + str.toHexAddr(this.regIP, this.segCS.sel) + " (%" + str.toHex(this.regEIP, 6) + ")"; var fRunning = this.bitField.fRunning; - if (this.messageDebugger(sMessage)) { + if (this.messageDebugger(sMessage, bitsMessage)) { if (fHalt) { /* * By setting fHalt to fRunning (which is true while running but false while single-stepping), diff --git a/modules/shared/lib/component.js b/modules/shared/lib/component.js index c869979da..fa499f16a 100644 --- a/modules/shared/lib/component.js +++ b/modules/shared/lib/component.js @@ -933,20 +933,20 @@ Component.prototype = { return true; }, /** - * messageEnabled(bitsMessage, fOnly) + * messageEnabled(bitsMessage) + * + * If bitsMessage is not specified, the component's MESSAGE category is used. * * @this {Component} - * @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) + * @param {number} [bitsMessage] is zero or more Debugger MESSAGE_* category flag(s) * @return {boolean} true if all specified message enabled, false if not */ messageEnabled: function(bitsMessage) { if (DEBUGGER && this.dbg) { if (this === this.dbg) { - bitsMessage = bitsMessage || 0; + bitsMessage |= 0; } else { - if (!bitsMessage) { - bitsMessage = this.bitsMessage; - } + bitsMessage = bitsMessage || this.bitsMessage; } var bitsEnabled = this.dbg.bitsMessage & bitsMessage; return (bitsEnabled === bitsMessage || !!(bitsEnabled & this.dbg.bitsWarning)); @@ -956,15 +956,18 @@ Component.prototype = { /** * messageDebugger(sMessage, bitsMessage, fAddress) * + * If bitsMessage is not specified, the component's MESSAGE category is used. + * If bitsMessage is true, the message is displayed regardless. + * * @this {Component} * @param {string} sMessage is any caller-defined message string - * @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) + * @param {number|boolean} [bitsMessage] is zero or more Debugger MESSAGE_* category flag(s) * @param {boolean} [fAddress] is true to display the current address * @return {boolean} true if Debugger available, false if not */ messageDebugger: function(sMessage, bitsMessage, fAddress) { if (DEBUGGER && this.dbg) { - if (bitsMessage == null || this.messageEnabled(bitsMessage)) { + if (bitsMessage === true || this.messageEnabled(bitsMessage | 0)) { this.dbg.message(sMessage, fAddress); } return true; @@ -974,19 +977,25 @@ Component.prototype = { /** * messagePort(port, bOut, addrFrom, name, bIn, bitsMessage) * - * This is an internal version of the Debugger's messagePort() function, for convenience. + * If bitsMessage is not specified, the component's MESSAGE category is used. + * If bitsMessage is true, the message is displayed as long as MESSAGE.PORT is enabled. * * @this {Component} * @param {number} port * @param {number|null} bOut if an output operation * @param {number|null} [addrFrom] * @param {string|null} [name] of the port, if any - * @param {number} [bIn] is the input value, if known, on an input operation - * @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) + * @param {number|null} [bIn] is the input value, if known, on an input operation + * @param {number|boolean} [bitsMessage] is zero or more Debugger MESSAGE_* category flag(s) */ messagePort: function(port, bOut, addrFrom, name, bIn, bitsMessage) { if (DEBUGGER && this.dbg) { - this.dbg.messageIO(this, port, bOut, addrFrom, name, bIn, bitsMessage || this.bitsMessage); + if (bitsMessage === true) { + bitsMessage = 0; + } else if (bitsMessage == null) { + bitsMessage = this.bitsMessage; + } + this.dbg.messageIO(this, port, bOut, addrFrom, name, bIn, bitsMessage); } } };