VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've built a Prefetch Input Queue (6-byte in case of 8086 and 80186 processor emulation) into my CPU emulation:
https://bitbucket.org/superfury/x86emu/src/3e … cpu.c?at=master

CPU_readOP reads byte from the prefetch buffer and reloads it if it's empty during execution.
CPU_exec is the main instruction parsing routine.
CPU_resetOP is called with repeating instructions and by exceptions (REP* prefix and exceptions).
CPU_fillPIQ fills the PIQ using CPU[activeCPU].PIQ_EIP as the execution point (equivalent of EIP register).
CPU_flushPIQ clears the PIQ (called by CPU_resetOP when needed and by control transfers using CS and EIP).

When I try to run most software all runs well. But when trying to run Castlevania (Using MS-DOS 5.0) it seems to go wrong (and end up at some instruction in the BIOS which is essentially a "JMP $-2", or a JMP to the address the JMP is at or effectively an infinite loop in this case).

I'm running the game (Castlevania) from a hard disk image (2GB SFDIMG disk image file) on the 2nd hard disk with the first hard disk image (20MB SFDIMG disk image file) with MS-DOS 5.0. There's the IBM VGA BIOS ROM at C000:0000, XTIDE hard disk BIOS at C800:0000 and Turbo XT BIOS at F800:0000.

Anyone knows why it gets to this point when running the game with the 6-byte prefetch buffer enabled? When I disable the prefetch buffer, the game runs without problems.

If I disable the prefetch buffer (by setting the size of the current CPU to 0 bytes large, effectively disabling it) the game runs without problems.

Anyone knows why the game hangs (looking at it from a fast PC reveals the infinite loop at the Turbo XT BIOS ROM)?

Last edited by superfury on 2015-11-29, 15:39. Edited 1 time in total.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 1 of 2, by Scali

User metadata
Rank l33t
Rank
l33t
superfury wrote:

If I disable the prefetch buffer (by setting the size of the current CPU to 0 bytes large, effectively disabling it) the game runs without problems.

Have you tried setting it to 4 bytes? What happens then?

http://scalibq.wordpress.com/just-keeping-it- … ro-programming/

Reply 2 of 2, by superfury

User metadata
Rank l33t++
Rank
l33t++

It seems to go wrong as well. I've added support for setting the 8-bit bus in the BIOS settings (effectively changing the Prefetch Input Queue for 80(1)86 processors to their 80(1)88 equivalents: 4 bytes prefetched instead of 6 bytes).

When debugging the executed code using the emulator's own debugging utility, I notice that it's executing some kind of counter (I think it might be the IRQ0 handler) which decreases some counter and compares it to 0x18, finding it's not zero, signalling the PIC that it's done. After this it resets instead of executing an IRET. It gets back to the start of the interrupt handler (an STI instruction) infinitely looping (I notice that SP overflows infinitely while executing this way). Letting the CPU run doesn't seem to terminate the infinite loop.

Edit: Looking at the IRQ0 handler of the Turbo XT BIOS:

;---------------------------------------------------------------------------------------------------
; Interrupt 8h - Hardware Clock
;---------------------------------------------------------------------------------------------------
entry 0FEA5h ; IBM entry, hardware clock
proc int_8 far

sti ; Routine services clock tick
push ds
push dx
push ax
mov ax, 40h
mov ds, ax
dec [byte ds:40h] ; Decrement motor count
jnz @@increment ; not time to shut off
and [byte ds:3Fh], 11110000b ; Else show motor off
mov al, 0Ch ; send motor off
mov dx, 3F2h ; to the floppy
out dx, al ; disk controller

@@increment:
inc [word ds:6Ch] ; Bump low order time of day
jnz @@check_midnight ; no carry
inc [word ds:6Eh] ; Bump high order time of day

@@check_midnight:
cmp [word ds:6Eh], 18h ; Is it midnight yet?
jnz @@user ; no
cmp [word ds:6Ch], 0B0h ; Possibly, check low order
jnz @@user ; not midnight
mov [word ds:6Eh], 0 ; Midnight, reset high order
mov [word ds:6Ch], 0 ; low order ticks
mov [byte ds:70h], 1 ; Show new day since last read

@@user:
int 1Ch ; Execute user clock service
mov al, 20h ; send end_of_interrupt
out 20h, al ; to 8259 interrupt chip
pop ax
pop dx
pop ds
iret

It seems that the emulator is retriggering the IRQ0 after the out 20h,al instruction is executed (clearing the flag, after which the interrupt is retriggered for some reason when reaching the "pop ax" instruction?

Edit: After adjusting the debugger to correctly clear/flush PIT timing passed when returning from the debugger (acting like no time has passed at all to prevent extreme amounts of interrupts being called because the debugger pauses the CPU) I notice it's executing a "LOOP 1275" at 3C6A:1275 (in the Castlevania executable?).

I also notice that the IRQ0 is nesting itself (executing itself after acnowledging the interrupt with "out 20h,al"). Is this a problem? It's probably caused by the STI at the start of the interrupt.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io