Attempting To Code For The Irem M92. Again...
Re: Attempting To Code For The Irem M92. Again...
If you have a debugger, double check that your interrupt table contains correct addresses.
And in the interrupt handlers, insert a "jmp endlessloop" instead of trying to execute iret for now.
The hlt opcode shouldn't cause problems, or does it work when you remove that opcode?
A jump to 0 could be caused by interrupt table being zerofilled, or stack pointer pointing to zerofilled/readonly memory, though the ret from the palette function seems to have worked. But if it is a stack problem: look where sp points to after crash, and if there is anything currently stored on stack (or if there a still traces from values that were stored on stack).
That XA flag for 20bit vs 24bit addressing... I hope that won't affect the values in the irq table? Like automatically using 24bit mode for interrupts?
And in the interrupt handlers, insert a "jmp endlessloop" instead of trying to execute iret for now.
The hlt opcode shouldn't cause problems, or does it work when you remove that opcode?
A jump to 0 could be caused by interrupt table being zerofilled, or stack pointer pointing to zerofilled/readonly memory, though the ret from the palette function seems to have worked. But if it is a stack problem: look where sp points to after crash, and if there is anything currently stored on stack (or if there a still traces from values that were stored on stack).
That XA flag for 20bit vs 24bit addressing... I hope that won't affect the values in the irq table? Like automatically using 24bit mode for interrupts?
- Drew Sebastino
- Formerly Espozo
- Posts: 3496
- Joined: Mon Sep 15, 2014 4:35 pm
- Location: Richmond, Virginia
Re: Attempting To Code For The Irem M92. Again...
I noticed there was one address that didn't match the others, so I changed that, and I even moved the function to the beginning of the interrupt handler section. From 0x00000 to 0x003FF in rom is now filled with "0x0040 0x0000", which should be 0x00400, which would be correct. I also replaced the iret instruction with a jump to itself, but if this were the problem, I should have seen the processor at least jump to the iret anyway.
Unfortunately, it still doesn't work, even if I remove the hlt instruction (the only difference is that I need to wait a ton of cycles for the interrupt to fire). Something strange though, is that the 0x0068 that gets pushed to the stack from the palette uploader function (which I verified is the correct value for IP) gets pushed down 4 bytes, with "0x0041 0xF246" taking the top of the stack, which doesn't seem correct, but it's not 0x00000. The processor is at 0x00478 when the interrupt occurs.
Unfortunately, it still doesn't work, even if I remove the hlt instruction (the only difference is that I need to wait a ton of cycles for the interrupt to fire). Something strange though, is that the 0x0068 that gets pushed to the stack from the palette uploader function (which I verified is the correct value for IP) gets pushed down 4 bytes, with "0x0041 0xF246" taking the top of the stack, which doesn't seem correct, but it's not 0x00000. The processor is at 0x00478 when the interrupt occurs.
Re: Attempting To Code For The Irem M92. Again...
Maybe somehow you are executing from 0x41:0x68 instead of 0x40:0x78 ... ?
- Drew Sebastino
- Formerly Espozo
- Posts: 3496
- Joined: Mon Sep 15, 2014 4:35 pm
- Location: Richmond, Virginia
Re: Attempting To Code For The Irem M92. Again...
Those two should be equivalent, shouldn't they? CS starts and stays at 0x0041 until it (magically) gets wiped out. And I forgot to mention, the stack pointer goes from 0x0000, to 0xFFFE after the subroutine (and never goes back to 0x0000...) then goes to 0xFFFA after the interrupt is triggered.
Re: Attempting To Code For The Irem M92. Again...
They're the same linear address, but they'll show up differently on the stack.
Re: Attempting To Code For The Irem M92. Again...
The stack content looks right, interrupts are pushing 3 words (flags and CS:IP).
Pushed CS being 41h for main program is also right (because the source code has interrupt code in a separate segment at CS=40h, and main at CS=41h, which is a bit weird, I would put all code into the same segment, unless your code grows bigger than 64K, of course).
The values in the interrupt table are "00 00 40 00", right? Just in case you get the little endian wrong or whatever.
And the values are still so at time of crash, right? Just in case your code or some DMA had destroyed them somehow.
If you have a copy of a working game, check if its interrupt table looks somehow different as expected.
Probably not the problem: But the interrupt table would need some work, I would add comments to each line, saying IRQ 00h, IRQ 01h, ..., IRQ FFh (and/or use something like REPT to fill a range of unused entries). And especially, add a ERRIF directive at the end of the table, throwing an error if the table size isn't 400h bytes.
Do you have an idea which interrupt is getting triggered? That would help to know what is happening.
Or better: Use the "int" opcode to manually trigger an interrupt, eg. "int 00h" should jump to the first interrupt table entry, that kind of software interrupts should work even if IRQs are disabled.
Oh, and I've read a bit about Irem M92... one webpage mentioned encrypted ROMs. And, as far as understand only some bytes here and there are being encrypted? If I got that right, then you might need to encrypt your ROM, or make sure that your emulator can deal with unencrypted ROMs.
Btw. is the code and interrupt table in ROM or RAM?
Pushed CS being 41h for main program is also right (because the source code has interrupt code in a separate segment at CS=40h, and main at CS=41h, which is a bit weird, I would put all code into the same segment, unless your code grows bigger than 64K, of course).
The values in the interrupt table are "00 00 40 00", right? Just in case you get the little endian wrong or whatever.
And the values are still so at time of crash, right? Just in case your code or some DMA had destroyed them somehow.
If you have a copy of a working game, check if its interrupt table looks somehow different as expected.
Probably not the problem: But the interrupt table would need some work, I would add comments to each line, saying IRQ 00h, IRQ 01h, ..., IRQ FFh (and/or use something like REPT to fill a range of unused entries). And especially, add a ERRIF directive at the end of the table, throwing an error if the table size isn't 400h bytes.
Do you have an idea which interrupt is getting triggered? That would help to know what is happening.
Or better: Use the "int" opcode to manually trigger an interrupt, eg. "int 00h" should jump to the first interrupt table entry, that kind of software interrupts should work even if IRQs are disabled.
Oh, and I've read a bit about Irem M92... one webpage mentioned encrypted ROMs. And, as far as understand only some bytes here and there are being encrypted? If I got that right, then you might need to encrypt your ROM, or make sure that your emulator can deal with unencrypted ROMs.
Btw. is the code and interrupt table in ROM or RAM?
Re: Attempting To Code For The Irem M92. Again...
https://en.m.wikipedia.org/wiki/NEC_V20 says that V33 vs V33A differ in terms of incompatble "interrupt vector numbers" (whatever that means), that might be a problem if M92 has V33 chips, or if some such boards have V33 and others have V33A.
https://patpend.net/technical/arcade/m92.html mentions a interrupt controller that is written to on bootup, you should probably do that, too. Just copy the init code from another game, maybe it'll help.
For the in/out opcodes, you are always using 16bit ax, is that that intended? The patpend doc isn't too clear about the port size(s), some might be supposed to be used with 8bit al, but, even if so, perhaps one could still access two ports at once via 16bit ax.
https://patpend.net/technical/arcade/m92.html mentions a interrupt controller that is written to on bootup, you should probably do that, too. Just copy the init code from another game, maybe it'll help.
For the in/out opcodes, you are always using 16bit ax, is that that intended? The patpend doc isn't too clear about the port size(s), some might be supposed to be used with 8bit al, but, even if so, perhaps one could still access two ports at once via 16bit ax.
- Drew Sebastino
- Formerly Espozo
- Posts: 3496
- Joined: Mon Sep 15, 2014 4:35 pm
- Location: Richmond, Virginia
Re: Attempting To Code For The Irem M92. Again...
Sorry for the late reply; I've been busy all day.
But yasm writes "error: non-constant value given to `%if'"
Correct.nocash wrote:The values in the interrupt table are "00 00 40 00", right? Just in case you get the little endian wrong or whatever.
Also correct; it's in rom, but I was paranoid enough to check if it changes somehow anyway, and sure enough, it doesn't.nocash wrote:And the values are still so at time of crash, right? Just in case your code or some DMA had destroyed them somehow.
Do you have an idea of how to do this? I wrote:nocash wrote:ERRIF directive at the end of the table, throwing an error if the table size isn't 400h bytes.
Code: Select all
end_of_ivt:
%if (end_of_ivt > 0x400)
%error Interrupt Vector Table over 1KB.
%endif
It should be vblank; it occurs right before "beam y" loops back to 0. I don't know the number of the interrupt though.nocash wrote:Do you have an idea which interrupt is getting triggered? That would help to know what is happening.
That is only for the sound cpu program. I'm currently just using the files from Gunforce II for this.nocash wrote:Oh, and I've read a bit about Irem M92... one webpage mentioned encrypted ROMs. And, as far as understand only some bytes here and there are being encrypted? If I got that right, then you might need to encrypt your ROM, or make sure that your emulator can deal with unencrypted ROMs.
I have no idea, unfortunately.nocash wrote:says that V33 vs V33A differ in terms of incompatble "interrupt vector numbers" (whatever that means), that might be a problem if M92 has V33 chips, or if some such boards have V33 and others have V33A.
Oh, wow, you're right... I'll see what's written to these in an actual game and replicate it in my code, and if that doesn't work, I'll go and step through the code and copy everything all the way up until the title screen, at which point everything appears to be initialized.nocash wrote:mentions a interrupt controller that is written to on bootup, you should probably do that, too. Just copy the init code from another game, maybe it'll help.
Oh, oops, that's not.nocash wrote:For the in/out opcodes, you are always using 16bit ax, is that that intended?
- Drew Sebastino
- Formerly Espozo
- Posts: 3496
- Joined: Mon Sep 15, 2014 4:35 pm
- Location: Richmond, Virginia
Re: Attempting To Code For The Irem M92. Again...
Holy shit, look what I finally got working though:
I really don't know why I couldn't get this to work last time I did this years ago, because it was pretty straightforward; all you have to do is give your sprite (I arbitrary chose the 32nd one) parameters like a nonzero y value so it actually shows up on screen as well as a nonzero tile number (unless tile 0 isn't blank).
What was tripping me up is that patpend.net erroneously says 0xF9008 "Clears sprite ram" when all it does is DMA the copy of sprite ram to ram, and the MAME driver has it written like this
but the offset is really the offset * 2, because it's apparently by words.
I really don't know why I couldn't get this to work last time I did this years ago, because it was pretty straightforward; all you have to do is give your sprite (I arbitrary chose the 32nd one) parameters like a nonzero y value so it actually shows up on screen as well as a nonzero tile number (unless tile 0 isn't blank).
Code: Select all
;Enable Sprites
mov ax, VIDEO_HARDWARE_RAM_START
mov ds, ax
mov word [spriteRam + 0x100], 0x0100
mov word [spriteRam + 0x102], 0x0001
mov word [spriteRam + 0x104], 0x0000
mov word [spriteRam + 0x106], 0x0100
xor ax, ax
mov [spriteControlRam + 0], ax ;sets up DMA
mov [spriteControlRam + 4], ax ;sets up DMA
mov [spriteControlRam + 8], ax ;DMA spriteRam
Code: Select all
COMBINE_DATA(&m_spritecontrol[offset]);
// offset0: sprite list size (negative)
// offset1: ? (always 0)
// offset2: sprite control
// offset3: ? (always 0)
// offset4: sprite dma
// offset5: ?
- Drew Sebastino
- Formerly Espozo
- Posts: 3496
- Joined: Mon Sep 15, 2014 4:35 pm
- Location: Richmond, Virginia
Re: Attempting To Code For The Irem M92. Again...
Okay, getting interrupts to work properly was actually way easier than I expected; I just opened (the original) Gunforce II in MAME debugger, set watchpoints for IO 0x40 to 0x43, then copied exactly what was written to these registers in my code.
I have no idea what the meaning behind these values are, but if these registers are only written to at startup, I shouldn't have to worry. I'm also writing to the same register three times in a row, but I figure it's best not to tamper with it if I don't know how it works...
A simple demo scrolling BG1 has been created. I should have everything (except sound, but that's the very last thing I care about) working now; this hardware is gloriously simple... Expect to see stuff in the future. I might create another thread showcasing this if it turns into a full fledged engine instead of just a demo.
I have no idea what the meaning behind these values are, but if these registers are only written to at startup, I shouldn't have to worry. I'm also writing to the same register three times in a row, but I figure it's best not to tamper with it if I don't know how it works...
Code: Select all
;Set Up Interrupt Controller (This is exactly what Gunforce II writes)
mov al, 0x17
out 0x40, al
mov al, 0x20
out 0x42, al
mov al, 0x0F
out 0x42, al
mov al, 0x08
out 0x42, al
Re: Attempting To Code For The Irem M92. Again...
MAME says that the M92 apparently uses NEC's in-house clone (µPD70159, "Interrupt Control Unit") of the x86 PC's standard Programmable Interrupt Controller, the 8259.
The thing that's weird is that the 8259 has a single address line, and it's usually A0, so I'm a little confused why the code you've used as reference is using A1.
If it were instead
The thing that's weird is that the 8259 has a single address line, and it's usually A0, so I'm a little confused why the code you've used as reference is using A1.
If it were instead
Code: Select all
0x17→p[0x40] : write ICW1 (due to (address&1)==0 and (data&0x10)==0x40)
- data&0xE0 - unused, 8085 only
- data&0x08 - edge-triggered
- data&0x04 - 8085 only? IRQ vectors are spaced every 4 bytes
- data&0x02 - only one PIC is present (ICW3 will not be written)
- data&0x01 - ICW4 will be written
0x20→p[0x41] : write ICW2
- data&0xF8 - relay hardware IRQs to x86 IRQ vectors 0x20-0x27
- data&0x07 - 8085 only
0x0F→p[0x41] : write ICW4
- data&0xE0 - unused
- data&0x10 - disable "special fully nested mode" or use "normal nest mode"
- data&0x0C - primary/only PIC is using buffer mode
- data&0x02 - "auto end-of-interrupt"
- data&0x01 - x86 mode
0x08→p[0x41] : write OCW1
- data&0x08 : only IRQ3 is disabled
- Drew Sebastino
- Formerly Espozo
- Posts: 3496
- Joined: Mon Sep 15, 2014 4:35 pm
- Location: Richmond, Virginia
Re: Attempting To Code For The Irem M92. Again...
What is A1? do you mean how I store the variables in register AL? I didn't copy the exact code, but I am writing the same values in the same order to these IO registers, so the behavior should be the same.lidnariq wrote:The thing that's weird is that the 8259 has a single address line, and it's usually A0, so I'm a little confused why the code you've used as reference is using A1.
Re: Attempting To Code For The Irem M92. Again...
Address Line 1, containing the "2s" bit of the address. In the XT, the 8259 there is configured at I/O space ports 20h and 21h; but the code you're using as reference is instead apparently referring to them at 40h and 42h.
- Drew Sebastino
- Formerly Espozo
- Posts: 3496
- Joined: Mon Sep 15, 2014 4:35 pm
- Location: Richmond, Virginia
Re: Attempting To Code For The Irem M92. Again...
What I did, is I saw where interrupt control registers are located according to this: https://patpend.net/technical/arcade/m92.html, then set watchpoints for the IO write ports, then copied the behavior. It seems to work, somehow.