diff --git a/README b/README index 28cf050..904fc06 100644 --- a/README +++ b/README @@ -1,11 +1,11 @@ ---------------------------------------------- -SoftMPU 1.3 by bjt - Software MPU-401 Emulator +SoftMPU 1.4 by bjt - Software MPU-401 Emulator ---------------------------------------------- Copyright (C) 2013 bjt Copyright (C) 2002-2013 The DOSBox Team ---------------------------------------------- -Release Notes (09/07/13) +Release Notes (26/07/13) WHAT IS IT? @@ -24,7 +24,7 @@ work with the basic MPU interface found on sound cards. REQUIREMENTS -- MS-DOS 6.0 or later. SoftMPU will not work from within Windows +- MS-DOS 6.2 or later. SoftMPU will not work from within Windows - EMM386 must be loaded - Sound Blaster (or compatible) sound card with an MPU-401 interface supporting UART mode (e.g. Sound Blaster 16/AWE, Yamaha YMF71x) diff --git a/SOFTMPU.EXE b/SOFTMPU.EXE index 05fce71..6590256 100644 Binary files a/SOFTMPU.EXE and b/SOFTMPU.EXE differ diff --git a/SRC/APPSTR.ASM b/SRC/APPSTR.ASM new file mode 100644 index 0000000..7c39365 --- /dev/null +++ b/SRC/APPSTR.ASM @@ -0,0 +1,32 @@ +; +; Copyright (C) 2013 bjt +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation; either version 2 of the License, or +; (at your option) any later version. +; +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, write to the Free Software +; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +; + +; ------------------------------------------ +; SoftMPU by bjt - Software MPU-401 Emulator +; ------------------------------------------ +; +; App ID substrings +; + + ; Disable SB interrupts for these intelligent mode apps +AppIDStrings DB 'FB.E' ; Flashback + DB 'MM3.' ; Might and Magic III + DB 'SOC.' ; Sensible Soccer + DB 'UNVG' ; Waxworks + DB 'WC2.' ; Wing Commander II + DB 00h ; End diff --git a/SRC/EXPORT.H b/SRC/EXPORT.H index 7092a2a..04db28a 100644 --- a/SRC/EXPORT.H +++ b/SRC/EXPORT.H @@ -40,6 +40,7 @@ typedef enum EventID {MPU_EVENT,RESET_DONE,EOI_HANDLER,NUM_EVENTS} EventID; void PIC_Update(bool blocking); void MPU401_Init(Bitu sbport,Bitu irq,Bitu mpuport,bool delaysysex); +void MPU401_SetEnableSBIRQ(bool enable); Bitu MPU401_ReadStatus(void); void MPU401_WriteCommand(Bitu val); Bitu MPU401_ReadData(void); diff --git a/SRC/INTHAND.ASM b/SRC/INTHAND.ASM index d1171f7..fde9082 100644 --- a/SRC/INTHAND.ASM +++ b/SRC/INTHAND.ASM @@ -20,7 +20,7 @@ ; SoftMPU by bjt - Software MPU-401 Emulator ; ------------------------------------------ ; -; RTC, SB DMA and IRQ 2/8 Watchdog interrupt handlers +; RTC, SB DMA, DOS exec and IRQ watchdog interrupt handlers ; IntStackSize EQU 0100h ; 256 byte stack for handler @@ -54,7 +54,7 @@ Int70Handler: ASSUME ds:_DATA ; Access local vars via mov sp,ax ; Disable virtualised port access - mov NoVirtualise,1 + mov VirtualisePorts,0 ; Handle timer tick ; MPU lib has been initialised @@ -68,7 +68,7 @@ Int70Handler: ASSUME ds:_DATA ; Access local vars via popa ; Enable virtualised port access - mov NoVirtualise,0 + mov VirtualisePorts,1 ; Interrupts are still disabled ; Read status register C to clear pending interrupt @@ -100,9 +100,15 @@ Int70Handler: ASSUME ds:_DATA ; Access local vars via SBIntHandler: ASSUME ds:_DATA ; Access local vars via cs - ; Ensure interrupts are disabled, in case something's chained us + ; Early out if required pushf - cli + cmp SBIRQGen,1 + je @@SBIntHandler2 + popf + jmp OldSBISR + + ; Ensure interrupts are disabled, in case something's chained us +@@SBIntHandler2:cli ; Save scratch registers mov SavedAX,ax @@ -118,7 +124,7 @@ SBIntHandler: ASSUME ds:_DATA ; Access local vars via test al,01h ; 8-bit IRQ flag jz @@ExitISR ; Was the interrupt meant for us? mov SBDetected,1 ; Signal detection success - cmp NoSBEOI,1 ; Do we want to EOI? + cmp SBEOI,0 ; Do we want to EOI? je @@ExitISR ; Acknowledge interrupt @@ -159,45 +165,74 @@ TimerIntHandler:ASSUME ds:_DATA ; Access local vars via jmp SHORT $+2 ; Enforce short pause between read & write out 021h,al ; Set new mask - ; Make sure IRQ 8 (RTC) is unmasked - ; It's needed to drive the MPU timers -@@IRQ2OK: in al,0A1h ; Get current mask - test al,01h - jz @@IRQ8OK - and al,0FEh - jmp SHORT $+2 ; Enforce short pause between read & write - out 0A1h,al ; Set new mask - ; Restore scratch registers -@@IRQ8OK: mov ax,SavedAX +@@IRQ2OK: mov ax,SavedAX ; Chained ISR will have already sent an EOI iret ; Will restore int flag DOSIntHandler: ASSUME ds:_DATA ; Access local vars via cs - ; Check for exec call (4Bh) + ; Check for exec call (AH=04Bh,AL=00h) pushf cmp ah,04Bh jne @@ExitISR3 + cmp al,0 + jne @@ExitISR3 + + ; Disable interrupts to keep setting changes atomic + cli - mov NoSBEOI,0 ; Reset SB EOI control + ; Default settings + mov SBEOI,1 ; Enable SB EOI + mov SBIRQGen,1 ; Enable SB IRQ generation ; Parse filename for app detection substrings push si push eax + push ebx mov si,dx cld ; Auto increment si @@ParseFilename:lodsd ; Get a dword from the filename + cmp al,0 ; Check for null terminator + je @@ExitISR2 + + ; Should we disable EOI? cmp eax,'.EGU' ; It Came From The Desert (HUGE.EXE) je @@DisableSBEOI - sub si,3 ; Only step a byte at a time + jmp @@CheckIRQGen +@@DisableSBEOI: mov SBEOI,0 ; Don't send SB EOI + +@@CheckIRQGen: ; Should we disable SB IRQ generation? + push ds + push si + mov ebx,eax ; Save comparison string + mov ax,cs + mov ds,ax ; Copy cs->ds for data access + mov si,OFFSET AppIDStrings +@@ParseAppStrings: + lodsd ; Get an ID string cmp al,0 ; Check for null terminator - je @@ExitISR2 + je @@NextChar + cmp eax,ebx + je @@DisableIRQGen ; Found a match + jmp @@ParseAppStrings +@@DisableIRQGen:mov SBIRQGen,0 ; Disable SB interrupts +@@NextChar: pop si + pop ds + sub si,3 ; Only step a byte at a time jmp @@ParseFilename ; Next char - -@@DisableSBEOI: mov NoSBEOI,1 ; Don't send SB EOI -@@ExitISR2: pop eax +@@ExitISR2: pop ebx + pop eax ; Finished parsing pop si + + ; Now commit our changes + pusha + push ds + mov ax,SEG _DATA + mov ds,ax + INVOKE MPU401_SetEnableSBIRQ,SBIRQGen + pop ds + popa @@ExitISR3: popf jmp OldDOSISR diff --git a/SRC/MIDI.C b/SRC/MIDI.C index fd7cfd6..cfd2834 100644 --- a/SRC/MIDI.C +++ b/SRC/MIDI.C @@ -55,7 +55,7 @@ typedef int Bits; #define SYSEX_SIZE 1024 #define RAWBUF 1024 -static char* MIDI_welcome_msg="\xf0\x41\x10\x16\x12\x20\x00\x00 SoftMPU v1.3 \x2a\xf7"; /* SOFTMPU */ +static char* MIDI_welcome_msg="\xf0\x41\x10\x16\x12\x20\x00\x00 SoftMPU v1.4 \x29\xf7"; /* SOFTMPU */ static Bit8u MIDI_evt_len[256] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x00 diff --git a/SRC/MPU401.C b/SRC/MPU401.C index a9c1d84..5ced731 100644 --- a/SRC/MPU401.C +++ b/SRC/MPU401.C @@ -87,6 +87,7 @@ typedef enum MpuDataType MpuDataType; /* SOFTMPU */ static struct { bool intelligent; + bool generate_irqs; /* SOFTMPU */ MpuMode mode; Bitu sbport; Bitu mpuport; @@ -125,7 +126,7 @@ static struct { static void QueueByte(Bit8u data) { if (mpu.state.block_ack) {mpu.state.block_ack=false;return;} - if (mpu.queue_used==0 && mpu.intelligent) { + if (mpu.queue_used==0 && mpu.intelligent && mpu.generate_irqs) { mpu.state.irq_pending=true; PIC_ActivateIRQ(mpu.sbport); /* SOFTMPU */ } @@ -298,7 +299,7 @@ void MPU401_WriteCommand(Bitu val) { /* SOFTMPU */ break; case 0xff: /* Reset MPU-401 */ /*LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Reset %X",val);*/ /* SOFTMPU */ - PIC_AddEvent(RESET_DONE,MPU401_RESETBUSY); + PIC_AddEvent(RESET_DONE,MPU401_RESETBUSY); mpu.state.reset=true; MPU401_Reset(); if (mpu.mode==M_UART) return;//do not send ack in UART mode @@ -323,7 +324,7 @@ Bitu MPU401_ReadData(void) { /* SOFTMPU */ } if (!mpu.intelligent) return ret; - if (mpu.queue_used == 0) PIC_DeActivateIRQ(mpu.sbport); /* SOFTMPU */ + if ((mpu.queue_used == 0) && mpu.generate_irqs) PIC_DeActivateIRQ(mpu.sbport); /* SOFTMPU */ if (ret>=0xf0 && ret<=0xf7) { /* MIDI data request */ mpu.state.channel=ret&7; @@ -670,6 +671,18 @@ static void MPU401_Reset(void) { for (i=0;i<8;i++) {mpu.playbuf[i].type=T_OVERFLOW;mpu.playbuf[i].counter=0;} } +/* SOFTMPU: Enable/disable SB IRQ generation */ +void MPU401_SetEnableSBIRQ(bool enable) +{ + if (mpu.generate_irqs && !enable) + { + // Acknowledge any waiting IRQ + PIC_DeActivateIRQ(mpu.sbport); + } + + mpu.generate_irqs=enable; +} + /* SOFTMPU: Initialisation */ void MPU401_Init(Bitu sbport,Bitu irq,Bitu mpuport,bool delaysysex) { @@ -685,8 +698,9 @@ void MPU401_Init(Bitu sbport,Bitu irq,Bitu mpuport,bool delaysysex) mpu.mode=M_UART; mpu.sbport=sbport; mpu.mpuport=mpuport; + mpu.generate_irqs=true; /* SOFTMPU */ - mpu.intelligent = true; /* Default is on */ + mpu.intelligent=true; /* Default is on */ if (!mpu.intelligent) return; /* SOFTMPU: Moved IRQ 9 handler init to asm */ diff --git a/SRC/PORTHAND.ASM b/SRC/PORTHAND.ASM index c5e6f78..bbf4af0 100644 --- a/SRC/PORTHAND.ASM +++ b/SRC/PORTHAND.ASM @@ -33,7 +33,7 @@ PortHandler: ASSUME ds:_TEXT ; PM handler, can't read ; So we won't worry about a context switch... ; Interrupts are disabled already in here as well ; If we're inside the interrupt handler, pass through port access - cmp NoVirtualise,0 + cmp VirtualisePorts,1 je @@PortHandler2 stc ; Don't virtualise retf diff --git a/SRC/RESIDENT.ASM b/SRC/RESIDENT.ASM index bea0121..082913f 100644 --- a/SRC/RESIDENT.ASM +++ b/SRC/RESIDENT.ASM @@ -39,8 +39,9 @@ SBPortAddr DW 0 SBIRQ DB 0 DelaySysex DB 0 -NoVirtualise DB 1 ; Port virtualisation control -NoSBEOI DB 0 ; SBISR EOI control +VirtualisePorts DB 0 ; Port virtualisation control +SBEOI DB 1 ; SB ISR EOI control +SBIRQGen DB 1 ; SB IRQ generation control OldSBISR LABEL DWORD OldSBISRAddr DW ? @@ -58,9 +59,10 @@ SBDetected DB 0 ; Following data needs to be 4-byte aligned ; Might need to add some padding here for detection to work -IDPad DB 0 DUP (?) +IDPad DB 3 DUP (?) IDString DB '0S2M' ; Detection string + INCLUDE appstr.asm ; App ID substrings INCLUDE inthand.asm ; Interrupt handlers INCLUDE porthand.asm ; Port handler code @@ -84,9 +86,13 @@ Start: push es shl di,4 ; Calculate offset to resident end mov ax,04A15h mov bx,0 + stc ; Fail by default int 02Fh ; Install handler pop ds ; Restore ds jnc @@InitSoftMPU ; Init MPU lib + push es + mov ax,cs + mov es,ax ; Copy cs->es for var access from init jmp FAR PTR EMMErr ; Fail @@InitSoftMPU: INVOKE MPU401_Init,cs:SBPortAddr,cs:SBIRQ,cs:MPUDataPortAddr,cs:DelaySysex diff --git a/SRC/SOFTMPU.ASM b/SRC/SOFTMPU.ASM index a790d34..7e34878 100644 --- a/SRC/SOFTMPU.ASM +++ b/SRC/SOFTMPU.ASM @@ -49,6 +49,11 @@ ; - Merged latest DOSBox reset delay patch ; - Fixed "It Came From The Desert" ; +; 1.4 +; +; - Fixed games with digital FX +; - Improved EMM386 detection +; ; ------------------------------------------ StackSize EQU 0400h ; 1k stack for init diff --git a/SRC/STRINGS.ASM b/SRC/STRINGS.ASM index 3b915bb..e32a6f4 100644 --- a/SRC/STRINGS.ASM +++ b/SRC/STRINGS.ASM @@ -29,7 +29,7 @@ Header DB 0DAh DB 0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h DB 0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h DB 0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0BFh,0Dh,0Ah - DB 0B3h,'SoftMPU 1.3 by bjt ',0FEh,' Software MPU-401 Emulator',0B3h,0Dh,0Ah + DB 0B3h,'SoftMPU 1.4 by bjt ',0FEh,' Software MPU-401 Emulator',0B3h,0Dh,0Ah DB 0B3h,' ',0B3h,0Dh,0Ah DB 0B3h,'Copyright (C) 2013 bjt ',0B3h,0Dh,0Ah DB 0B3h,'Copyright (C) 2002-2013 The DOSBox Team ',0B3h,0Dh,0Ah @@ -39,7 +39,7 @@ Header DB 0DAh DB 0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h DB 0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h DB 0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0D9h,0Dh,0Ah,'$' -NoEMM DB '! Error: EMM386 is not available',0Dh,0Ah,'$' +NoEMM DB '! Error: EMM386 4.46 (or later) is not available',0Dh,0Ah,'$' EMMError DB '! Error: Port trap failed. Please submit a bug report',0Dh,0Ah,'$' LoadedError DB '! Error: SoftMPU is already loaded',0Dh,0Ah,'$' RTCError DB '! Error: Real Time Clock support not detected',0Dh,0Ah,'$' @@ -66,3 +66,5 @@ HelpText DB 'Usage: SOFTMPU /SB:nnn /IRQ:nn /MPU:nnn [/DELAY DB ' /IRQ:nn Sound Blaster interrupt (2-11)',0Dh,0Ah DB ' /MPU:nnn MPU-401 base I/O port address (220-350)',0Dh,0Ah DB ' /DELAYSYSEX Prevent Rev.0 MT-32 buffer overflow',0Dh,0Ah,'$' +EMMDevice DB 'EMMXXXX0',00h +EMMDevice2 DB 'EMMQXXX0',00h diff --git a/SRC/TRANS.ASM b/SRC/TRANS.ASM index 46bed92..8abc5ce 100644 --- a/SRC/TRANS.ASM +++ b/SRC/TRANS.ASM @@ -25,6 +25,10 @@ TransientSeg SEGMENT 'transient' +EMMVersion LABEL WORD ; EMM386 version buffer +EMMMajor DB 02h +EMMMinor DB 00h + Init: ; Ensure ds=cs push ds mov ax,cs @@ -187,18 +191,37 @@ Init: ; Ensure ds=cs mov SBIRQNum,al ; Check for EMM386 - push ds - xor ax,ax - mov ds,ax - mov ax,ds:[019Ch] - or ax,ds:[019Eh] - pop ds - jz @@NoEMM - mov ax,0FFA5h - int 067h - cmp ax,0845Ah - jz @@FoundEMM - + push ds ; Installation checks + xor ax,ax + mov ds,ax + mov ax,ds:[019Ch] + or ax,ds:[019Eh] + pop ds + jz @@NoEMM + mov ax,0FFA5h + int 067h + cmp ax,0845Ah + jne @@NoEMM + mov ax,03D00h ; Open file R/O + mov dx,OFFSET EMMDevice + int 021h ; Get handle + jnc @@CheckVersion + mov ax,03D00h ; Open file R/O + mov dx,OFFSET EMMDevice2 + int 021h ; Get handle + jc @@NoEMM +@@CheckVersion: mov bx,ax + mov ax,04402h ; Get manager version + mov cx,02h + mov dx,OFFSET EMMVersion + int 021h + mov ah,03Eh ; Close file + int 021h + cmp EMMMajor,4 ; Require EMM386 >= 4.46 + jl @@NoEMM + cmp EMMMinor,45 + jg @@FoundEMM + @@NoEMM: ; EMM386 not present mov ah,9 mov dx,OFFSET NoEMM @@ -297,9 +320,7 @@ Init: ; Ensure ds=cs je @@NoDelay mov dx,OFFSET DelaysEnabled int 021h ; Print sysex delay message -@@NoDelay: call InstTimerISR ; Install the IRQ 2/8 watchdog - call InstDOSISR ; Install the exec handler - pop ds +@@NoDelay: pop ds retf ; Return to caller EMMOK: ; Ensure ds=cs @@ -311,7 +332,11 @@ EMMOK: ; Ensure ds=cs inc eax mov DWORD PTR es:[si],eax ; Store complete ID string - ; Set RTC busy flag + ; Install support handlers + call InstTimerISR ; Install the IRQ 2/8 watchdog + call InstDOSISR ; Install the exec handler + + ; Set RTC busy flag ; Disable interrupts until we've replaced the handler pushf cli @@ -349,15 +374,15 @@ EMMOK: ; Ensure ds=cs mov al,0Ah call WriteRTC - ; Enable RTC interrupts - pushf - cli ; No interrupts while programming PIC - in al,0A1h + ; Enable RTC interrupts + pushf + cli ; No interrupts while programming PIC + in al,0A1h and al,0FEh ; Clear bit 0 = IRQ 8 (RTC) - jmp SHORT $+2 ; Short pause - out 0A1h,al - popf ; Start RTC interrupts - + jmp SHORT $+2 ; Short pause + out 0A1h,al + popf ; Start RTC interrupts + ; Print success message mov ah,9 mov dx,OFFSET LoadedStart @@ -381,7 +406,7 @@ EMMOK: ; Ensure ds=cs mov ah,049h int 021h ; Deallocate environment pop es - mov es:NoVirtualise,0 ; Enable port virtualisation + mov es:VirtualisePorts,1 ; Enable port virtualisation mov ah,031h mov dx,SEG STACK ; Int handlers have their own stack sub dx,bx ; Calc resident size from PSP in para @@ -403,6 +428,12 @@ EMMErr: ; Ensure ds=cs push ds mov ax,cs mov ds,ax + + ; Clean up after ourselves + call ResetMPU ; Switch back to normal mode + call RestoreSBISR ; Remove SB handler + + ; Print an error and exit mov ah,9 mov dx,OFFSET EMMError int 021h diff --git a/SRC/UTILS.ASM b/SRC/UTILS.ASM index 5f748c0..f5d8506 100644 --- a/SRC/UTILS.ASM +++ b/SRC/UTILS.ASM @@ -129,19 +129,8 @@ WaitForDRR: mov LoopCounter,0FFFFh @@DRRClear: clc retn ; OK to send -SwitchToUART: call TrySetDSR ; Clear pending data - jc @@SwitchFailed -@@TryReset: call WaitForDRR ; OK to send? - jc @@SwitchFailed - mov dx,es:MPUCmdPortAddr - mov al,0FFh - out dx,al ; Send reset cmd - call WaitForDSR - jc @@ResetFailed ; No ACK - mov dx,es:MPUDataPortAddr - in al,dx - cmp al,0FEh - jne @@ResetFailed ; No ACK +SwitchToUART: call ResetMPU ; Ensure we're in a sane state + jc @@SwitchFailed call TrySetDSR ; Clear pending data jc @@SwitchFailed call WaitForDRR ; OK to send? @@ -158,12 +147,32 @@ SwitchToUART: call TrySetDSR ; Clear pending data clc retn ; Now in UART mode +@@SwitchFailed: stc + retn ; Can't switch to UART + +ResetMPU: mov SecondReset,0 + call TrySetDSR ; Clear pending data + jc @@ResetFailed2 +@@TryReset: call WaitForDRR ; OK to send? + jc @@ResetFailed2 + mov dx,es:MPUCmdPortAddr + mov al,0FFh + out dx,al ; Send reset cmd + call WaitForDSR + jc @@ResetFailed ; No ACK + mov dx,es:MPUDataPortAddr + in al,dx + cmp al,0FEh + jne @@ResetFailed ; No ACK + clc + retn ; Now in normal mode + @@ResetFailed: mov al,SecondReset inc SecondReset - cmp al,0 ; Maybe we were already in UART mode + cmp al,0 ; Maybe we were in UART mode je @@TryReset -@@SwitchFailed: stc - retn ; Can't switch to UART +@@ResetFailed2: stc + retn ; Failed to reset DetectSB: ; Try to detect a Sound Blaster at the specifed port & irq mov al,es:SBIRQ ; Get hardware irq number @@ -171,9 +180,8 @@ DetectSB: ; Try to detect a Sound Blaster at the specifed port & irq cmp al,010h jl @@FirstPIC2 add al,060h ; Interrupt is on the secondary PIC -@@FirstPIC2: push ax ; Save software int number - ; Save the existing handler +@@FirstPIC2: ; Save the existing handler push es mov ah,035h int 021h ; Get interrupt vector @@ -234,7 +242,6 @@ DetectSB: ; Try to detect a Sound Blaster at the specifed port & irq pop dx ; Get PIC address cmp es:SBIRQ,9 je @@RestoreISR ; Allow IRQ 9<->2 mapping - pushf cli ; Disable interrupts in al,dx @@ -244,22 +251,28 @@ DetectSB: ; Try to detect a Sound Blaster at the specifed port & irq popf @@RestoreISR: ; Don't restore the handler on success - pop ax ; Get the interrupt num cmp es:SBDetected,1 ; Did the detection flag get set? je @@SBDetected + call RestoreSBISR ; Restore the old handler + stc + retn ; Failed to detect SB - ; Restore the old handler - mov ah,025h ; Interrupt num in al +@@SBDetected: clc + retn + +RestoreSBISR: ; Restore the old SB handler + mov al,es:SBIRQ ; Get hardware irq number + add al,8 + cmp al,010h + jl @@FirstPIC5 + add al,060h ; Interrupt is on the secondary PIC +@@FirstPIC5: mov ah,025h push ds mov ds,es:OldSBISRSeg mov dx,es:OldSBISRAddr int 021h ; Register old handler pop ds - stc - retn ; Failed to detect SB - -@@SBDetected: clc - retn + retn DetectRTC: push es mov ah,0C0h