Definitely has a niche for early games that run on composite colors, if it could simulate the artifacting as is done with the Apple II core.
This page lists 57 games that support that mode: https://www.mobygames.com/attribute/she ... Id,29/p,4/
Definitely has a niche for early games that run on composite colors, if it could simulate the artifacting as is done with the Apple II core.
and it's missing some games, isn't it? like maniac mansion.Newsdee wrote: ↑Tue Dec 28, 2021 1:34 pmDefinitely has a niche for early games that run on composite colors, if it could simulate the artifacting as is done with the Apple II core.
This page lists 57 games that support that mode: https://www.mobygames.com/attribute/she ... Id,29/p,4/
Happy new year to you as well ! Cross my fingers for having a better year than 2021, I'm confident it will be.
かすりん
There's something weird in your analysis. Position 44C3h gets modified by the INT 1Ch (Timer Tick) handler, which is located at 3758h. That interrupt handler is somewhat long; in particular this fragment is the one that should modify the byte at 44C3h:
Code: Select all
L37C1:
dec byte ptr cs:[44C2]
jne L37DB
mov byte ptr cs:[44C2],3C
cmp byte ptr cs:[44C3],0
je L37DB
dec byte ptr cs:[44C3]
L37DB:
Very well seen! I have not detected where the change of address is made in the 1Ch interrupt, but it is clear that at the point you comment is where the change of value of the content of that address takes place, I will check the CPU module, it would not surprise me that again due to problems with the code cache.pgimeno wrote: ↑Sat Jan 01, 2022 1:04 pmThere's something weird in your analysis. Position 44C3h gets modified by the INT 1Ch (Timer Tick) handler, which is located at 3758h. That interrupt handler is somewhat long; in particular this fragment is the one that should modify the byte at 44C3h:From that, I don't see how can that byte possibly become FEh, because it's a countdown that should stop at 0 and never wrap around. The other counter, 44C2h, seems to be constantly counting from 60 (3Ch) to 0 as a divisor of the tick frequency. Finding what writes an FEh to 44C3h would be important for diagnosis, because that should never happen, and it suggests a bug in the CPU module.Code: Select all
L37C1: dec byte ptr cs:[44C2] jne L37DB mov byte ptr cs:[44C2],3C cmp byte ptr cs:[44C3],0 je L37DB dec byte ptr cs:[44C3] L37DB:
For some reason, that routine is not listed in your list of references to 44C3h.
I have verified that 3C is decremented until reaching the loop, but, it seems that once there the int 8 is never launched. I've patched that loop to jump to another code where I force int 8 to run ... and that's how it works:pgimeno wrote: ↑Sat Jan 01, 2022 7:11 pm INT 1Ch should be called by the BIOS INT 08h handler. Is it possible that that isn't happening with the BIOS you're using?
If the timer is to blame and not the BIOS, it's possible that it works, but the speed is much slower than the creators anticipated. Have you waited for a while just in case?
By 3C do you mean 44C3?spark2k06 wrote: ↑Sun Jan 02, 2022 2:20 pmI have verified that 3C is decremented until reaching the loop, but, it seems that once there the int 8 is never launched. I've patched that loop to jump to another code where I force int 8 to run ... and that's how it works:
[...]
Therefore, there must be a bug in the Next186 CPU module that disable this int (and others maybe?), it will be the next thing to analyze.
Sorry for not being more specific. By 3C, I mean the divisor you were commenting on at address 44C2...pgimeno wrote:
By 3C do you mean 44C3?
I have already found the exact reason for this behavior. It turns out that before reaching this loop, between functions, a call is made to INT 13h, and what happens is that its output always clears the interrupt flag... and I also see that it does so after its return in IRET. So there are two options:pgimeno wrote:
There are many possible hypotheses, it's hard to put the finger on one. The interrupt flag may be a possible culprit, for example, especially if you say that the timer interrupt works in other circumstances. A wrong implementation of the 8259 PIC may be another one.
Code: Select all
; --------------------- INT 13h - Disk services ----------------
HDLastError equ <ds:[74h]>
HDOpStarted equ <ds:[92h]> ; bit 3: in INT13h (all other bits must be 0)
HDSize equ <ds:[94h]>
int13 proc near
push ds
push bp
push 40h
pop ds
xor byte ptr HDOpStarted, 8
jz short inINT13
sti
cld
cmp ah, 1ah
jbe short Disk1
sub ah, 41h-1bh ; extensions
cmp ah, 22h
jbe short Disk1
mov ah, 1 ; bad command error
jmp short exit33
inINT13:
mov ah, 0aah ; drive not ready
jmp short exit2
Disk1:
mov bp, ax
shr bp, 7
and bp, 1feh
push ds
call cs:disktbl[bp]
pop ds
exit33:
mov HDLastError, ah
exit2:
xor byte ptr HDOpStarted, 8
neg ah ; CF <- (AH != 0)
exit77:
mov bp, sp
rcr byte ptr [bp+8], 1
rol byte ptr [bp+8], 1 ; insert error CF on stack
neg ah
pop bp
pop ds
iret
I did not know Quaid Analyzer, thank you very much for the suggestion, I will keep it in mind for future debuggingpgimeno wrote: Do you have Quaid Analyzer? I think it's much more suitable for this task than debug, because it gives you control and step-by-step trace even when the keyboard interrupt is trapped by the application. It also tries to preserve the graphical screen and switch to text mode for debugging (the graphical screen is not correctly preserved in most cases, but at least you can see what you're doing). It also allows you to trace whether interrupts are executed, and even to redefine the breakpoint interrupt in case INT 3 is blocked by the application (but you have to be careful because then it becomes a length 2 instruction). It's quirky and not very comfortable to work with, but these features make it reach places that debug can't.
Good finding. IRET should definitely restore interrupts to the state stored in the stack. If they were disabled before executing INT 13h, they should be disabled after IRET. If they were enabled, they should be enabled after IRET. If that's not the case, then the implementation of IRET is buggy. Of course it's possible to fiddle with the stack inside the interrupt routine, and disable the copy of the flags stored there, to enable/disable interrupts on return, but it doesn't seem to me that the INT 13h handler does this, from what you've posted.spark2k06 wrote: ↑Mon Jan 03, 2022 12:20 pm I'm thinking about where the real problem may be. Now it is easy to debug it, because a simple call to INT 13h from the debugger allows us to see how after the IRET, it clears the interrupt flag ... when from PCEM or in a real PCXT machine this does not happen. It is therefore very likely that the bug is in the Next186 module.
Code: Select all
rcr byte ptr [bp+8], 1
rol byte ptr [bp+8], 1 ; insert error CF on stack
Yes, but curiously, the INT 13h does not behave like this in the PCEM for example ... within the INT 13h routine there is an STI, and apparently, in this case the correct behavior is for the function to return the enabled interrupts, although prior to the INT 13h call they are disabled:pgimeno wrote: ↑Mon Jan 03, 2022 1:12 pm Good finding. IRET should definitely restore interrupts to the state stored in the stack. If they were disabled before executing INT 13h, they should be disabled after IRET. If they were enabled, they should be enabled after IRET. If that's not the case, then the implementation of IRET is buggy. Of course it's possible to fiddle with the stack and disable the copy of the flags stored there, to enable/disable interrupts on return, but it doesn't seem to me that the INT 13h handler does this, from what you've posted.
Very well seen too! I will take a lookpgimeno wrote: ↑Mon Jan 03, 2022 1:12 pm
EDIT: Come to think about it, the bug might be in these read-modify-write instructions:It should not be accessing the second byte of the flags, where the interrupt flag is stored, because it's a byte access. Worth taking a look though.Code: Select all
rcr byte ptr [bp+8], 1 rol byte ptr [bp+8], 1 ; insert error CF on stack
A different BIOS may not use IRET for returning. It's fairly usual to use RETF 0002h to return without restoring the flags. The BIOS you posted does use IRET though, therefore the interrupt flag should be preserved.spark2k06 wrote: ↑Mon Jan 03, 2022 1:24 pm Yes, but curiously, the INT 13h does not behave like this in the PCEM for example ... within the INT 13h routine there is an STI, and apparently, in this case the correct behavior is for the function to return the enabled interrupts, although prior to the INT 13h call they are disabled:
Yes,pgimeno wrote: ↑Mon Jan 03, 2022 1:32 pm Edit: From my recollection, this inconsistency in handling the interrupt flag (some forcing it set, some restoring it) was endemic in interrupt handlers (except those for IRQs of course). Most handlers forced it set and returned with RETF 0002h instead of IRET. It's usual to have to disable ints after an interrupt call if you want them off, even if they were off before the call.
Code: Select all
exit77:
mov bp, sp
rcr byte ptr [bp+8], 1
rol byte ptr [bp+8], 1 ; insert error CF on stack
or byte ptr [bp+9], 2 ; sti
neg ah
pop bp
pop ds
iret
Code: Select all
exit77:
mov bp, sp
rcr byte ptr [bp+8], 1
rol byte ptr [bp+8], 1 ; insert error CF on stack
neg ah
pop bp
pop ds
retf 0002
Code: Select all
exit77:
pushf ; preserve carry
neg ah
popf ; restore carry
pop bp
pop ds
retf 0002h
I checked that the ror and rcl instructions were working correctly, the bp + 9 contained 00 at the time, because interrupts are disabled at the time of IRET, I will try to find out why it is 00.pgimeno wrote: ↑Mon Jan 03, 2022 8:45 pm The question is what is clearing the bit in [BP+9]. That's what shouldn't be happening in the first place, at least if INT 13h is called with interrupts enabled. Is it? Where's the INT 13h call that is disabling the interrupts? EDIT: If it's the one at 08B7 then yes, it's called with interrupts enabled and therefore nothing should be clearing it in the stack. Whatever clears it is not working properly. That's the byte at address 03FD if I'm not mistaken. I'd first check if either of the RCR/ROL instructions I've pointed at is the culprit. EDIT2: Another hypothesis is that the INT nn instruction is saving the flags with that bit cleared, which would be obviously wrong.
Anyway, a simple BIOS-side fix is:
Code: Select all
exit77: pushf ; preserve carry neg ah popf ; restore carry pop bp pop ds retf 0002h
The answer to this question has to do with how this interruption is reached. Both in this BIOS and in the original PCXT, INT 13h is reached through intermediate calls where PUSHF has previously been executed, as this instruction comes from the call to INT 13h, it causes interruptions to have been previously disabled, this it is the only reason then, and in any case, on all intermediate calls functions are exited via RETF 0002, just as the last BIOS routine should also do.pgimeno wrote: The question is what is clearing the bit in [BP+9]. That's what shouldn't be happening in the first place, at least if INT 13h is called with interrupts enabled. Is it? Where's the INT 13h call that is disabling the interrupts? EDIT: If it's the one at 08B7 then yes, it's called with interrupts enabled and therefore nothing should be clearing it in the stack. Whatever clears it is not working properly. That's the byte at address 03FD if I'm not mistaken. I'd first check if either of the RCR/ROL instructions I've pointed at is the culprit. EDIT2: Another hypothesis is that the INT nn instruction is saving the flags with that bit cleared, which would be obviously wrong.
pgimeno wrote: Anyway, a simple BIOS-side fix is:
Code: Select all
exit77: pushf ; preserve carry neg ah popf ; restore carry pop bp pop ds retf 0002h
Code: Select all
SUB SP,2
MOV [SP],SP
Code: Select all
MOV [SP-2],SP
SUB SP,2
Correct! It is as you comment. If we jump from that point now it is detected as 186, as it should be:pgimeno wrote: In the former case, after PUSH SP / POP AX, you have AX != SP, but in the latter case, AX == SP.
Do you know any good source to read about how instructions work for 8088/86 (286 would also be cool). That way we could make the instructions work like on the real machine. I only found pdf's explaining how many cycles every instruction takes, we could make the cpu cycle accurate but it would still be different.pgimeno wrote: ↑Wed Jan 05, 2022 2:45 am Don't miss that PUSH SP may have changed behaviour between models. I bet it's the instruction that comes right before the POP AX that appears in the first line of the snippet you've shown.
Most likely, in 8088/8086, PUSH SP pushes the value of SP *after* decrementing, that is, except for flags, it is equivalent to:
In later models, the behaviour is:Code: Select all
SUB SP,2 MOV [SP],SP
In the former case, after PUSH SP / POP AX, you have AX != SP, but in the latter case, AX == SP.Code: Select all
MOV [SP-2],SP SUB SP,2
No, I know that from my own experience. I've done a lot of disassembly on x86 in my DOS times I've seen PUSH SP used to detect the CPU type in more cases.
Maybe something like a list of CPU bugs could have these kinds of specifics.