Skip to content

Commit

Permalink
fix and enable MAIN_ISR_CHAINED again.
Browse files Browse the repository at this point in the history
  • Loading branch information
crazii committed Feb 4, 2024
1 parent 4793e44 commit dffe7e4
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 11 deletions.
8 changes: 4 additions & 4 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ PROGNAME = "SBEMU";
#define MAIN_TRAP_PIC_ONDEMAND 1
#define MAIN_INSTALL_RM_ISR 1 //not needed. but to workaround some rm games' problem. need RAW_HOOk in dpmi_dj2.c
#define MAIN_DOUBLE_OPL_VOLUME 1 //hack: double the amplitude of OPL PCM. should be 1 or 0
#define MAIN_ISR_CHAINED 0 //auto calls next handler AFTER current handler exits
#define MAIN_ISR_CHAINED 1 //auto calls next handler AFTER current handler exits

#define MAIN_TSR_INT 0x2D //AMIS multiplex. TODO: 0x2F?
#define MAIN_TSR_INTSTART_ID 0x01 //start id
Expand Down Expand Up @@ -989,7 +989,7 @@ int main(int argc, char* argv[])
//IRQ routing path:
//PM: IDT -> PM handlers after SBEMU -> SBEMU MAIN_InterruptPM(*) -> PM handlers befoe SBEMU -> IVT -> SBEMU MAIN_InterruptRM(*) -> DPMI entrance -> IVT handlers before DPMI installed
//RM: IVT -> RM handlers before SBEMU -> SBEMU MAIN_InterruptRM(*) -> RM handlers after SBEMU -> DPMI entrance -> PM handlers after SBEMU -> SBEMU MAIN_InterruptPM(*) -> PM handlers befoe SBEMU -> IVT handlers before DPMI installed
//(*) means SBEMU might early terminate the calling chain if sound irq is handled.
//(*) means SBEMU might early terminate the calling chain if sound irq is handled (when MAIN_ISR_CHAINED==0).
//early terminating is OK because PCI irq are level triggered, IRQ signal will keep high (raised) unless the hardware IRQ is ACKed.

static void MAIN_InterruptPM()
Expand All @@ -1010,9 +1010,9 @@ static void MAIN_InterruptPM()
//
//it has one problem that if other drivers (shared IRQ) enables interrupts (because it needs wait or is time consuming)
//then because we're still in MAIN_InterruptPM, so MAIN_InterruptPM is never enterred agian (guarded by go32 or MAIN_ININT_PM),
//so the newly coming irq will never be processed and the IRQ will flood the system
//so the newly coming irq will never be processed and the IRQ will flood the system (freeze)
//an alternative chained methods will EXIT MAIN_InterruptPM FIRST and calls next handler, which will avoid this case, see @MAIN_ISR_CHAINED
//but we need a hack if the default handler in IVT doesn't send EOI or masks the irq (TODO)
//but we need a hack if the default handler in IVT doesn't send EOI or masks the irq - this is done in the RM final wrapper, see @DPMI_RMISR_ChainedWrapper

//MAIN_IntContext.EFLAGS |= (MAIN_InINT&MAIN_ININT_RM) ? (MAIN_IntContext.EFLAGS&CPU_VMFLAG) : 0;
HDPMIPT_GetInterrupContext(&MAIN_IntContext);
Expand Down
62 changes: 57 additions & 5 deletions sbemu/dpmi/dpmi_dj2.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <stdio.h>
#include "xms.h"
#include "dbgutil.h"
#include "../pic.h"

extern DPMI_ADDRESSING DPMI_Addressing;

Expand Down Expand Up @@ -489,6 +490,48 @@ static void __NAKED DPMI_RMISR_ChainedWrapper()
_ASM(call dword ptr cs:[0]) //call target
_ASM(pushf) //calling iret
_ASM(call dword ptr cs:[4]) //call chained next

_ASM(push ax)

//unmask IRQ because default entry in IVT may mask the irq out
_ASM(in al, 0x21)
_ASM(and al, byte ptr cs:[8])
_ASM(out 0x21, al)
_ASM(in al, 0xA1)
_ASM(and al, byte ptr cs:[9])
_ASM(out 0xA1, al)

//read pic
_ASM(xor ah, ah)
_ASM(mov al, 0x0B) //read isr
_ASM(out 0x20, al)
_ASM(in al, 0x20)
_ASM(test al, 0x04)
_ASM(jz noslave)
_ASM(and al, ~0x04)
_ASM(mov ah, al)
_ASM(mov al, 0x0B) //read slave isr
_ASM(out 0xA0, al)
_ASM(in al, 0xA0)
_ASM(xchg ah, al)
_ASMLBL(noslave:)
_ASM(test ax, ax)
_ASM(jz done) //no pending irq in pic isr, done
_ASM(bsf ax, ax)
_ASM(cmp al, byte ptr cs:[10]) //compare with irq
_ASM(jne done) //different irq pending, done

//same irq pending after the full chain is called, send EOI in case the default entry in IVT doesn't send EOI
//note if this irq is new coming, send EOI doesn't matter (at least for SBEMU) since it is level triggered.
_ASM(mov al, 0x20)
_ASM(cmp byte ptr cs:[10], 8) //irq: 0-7?
_ASM(jb masterEOI)
_ASM(out 0xA0, al)
_ASMLBL(masterEOI:)
_ASM(out 0x20, al)

_ASMLBL(done:)
_ASM(pop ax)
_ASM(iret)
_ASM_END16
}
Expand Down Expand Up @@ -525,28 +568,37 @@ uint16_t DPMI_InstallRealModeISR(uint8_t i, void(*ISR_RM)(void), DPMI_REG* RMReg
if(chained)
{
uint32_t codesize = (uintptr_t)&DPMI_RMISR_ChainedWrapperEnd - (uintptr_t)&DPMI_RMISR_ChainedWrapper;
handle->chainedDOSMem = DPMI_HighMalloc((codesize + 8 + 15)>>4, TRUE); //+target + chained next (both real mode far ptr)
const uint32_t extra_size = 11; //+target + chained next (both real mode far ptr) + irqunmask + irq
handle->chainedDOSMem = DPMI_HighMalloc((codesize + extra_size + 15)>>4, TRUE);
if(handle->chainedDOSMem == 0)
{
_go32_dpmi_free_real_mode_callback(&go32pa_rm);
assert(FALSE);
return -1;
}
uint8_t irq = PIC_VEC2IRQ(i);
uint16_t unmask = 1<<irq;
if(irq >= 8) unmask |= 0x04; //mark slave cascaded in master
unmask = ~unmask;

uint8_t* buf = (uint8_t*)malloc(codesize+8);
uint8_t* buf = (uint8_t*)malloc(codesize+extra_size);
//copy target
memcpy(buf+0, &go32pa_rm.rm_offset, 2);
memcpy(buf+2, &go32pa_rm.rm_segment, 2);
//copy chained next
memcpy(buf+4, &ra.offset16, 2);
memcpy(buf+6, &ra.segment, 2);
//copy irq unmask
memcpy(buf+8, &unmask, 2);
//copy irq
memcpy(buf+10, &irq, 1);
//copy warpper code
memcpy(buf+8, &DPMI_RMISR_ChainedWrapper, codesize);
DPMI_CopyLinear(DPMI_SEGOFF2L(handle->chainedDOSMem, 0), DPMI_PTR2L(buf), codesize+8);
memcpy(buf+extra_size, &DPMI_RMISR_ChainedWrapper, codesize);
DPMI_CopyLinear(DPMI_SEGOFF2L(handle->chainedDOSMem, 0), DPMI_PTR2L(buf), codesize+extra_size);
free(buf);

go32pa_rm.rm_segment = handle->chainedDOSMem&0xFFFF;
go32pa_rm.rm_offset = 8;
go32pa_rm.rm_offset = (uint16_t)extra_size;
}

int result = -1;
Expand Down
5 changes: 3 additions & 2 deletions sbemu/pic.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ uint8_t PIC_GetIRQ(void)
if(mask&0x4)
{
outp(PIC_PORT2, PIC_READISR);
mask = (uint16_t)(inp(PIC_PORT2)<<8);
mask &= ~0x04;
mask = (uint16_t)(inp(PIC_PORT2)<<8) | mask;
}
STIL();
if(mask == 0)
Expand Down Expand Up @@ -110,7 +111,7 @@ void PIC_MaskIRQ(uint8_t irq)
void PIC_UnmaskIRQ(uint8_t irq)
{
uint16_t port = PIC_DATA1;
CLIS();
CLIS();
if(irq >= 8)
{
uint8_t master = inp(port);
Expand Down

0 comments on commit dffe7e4

Please sign in to comment.