Attempting To Code For The Irem M92. Again...

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Attempting To Code For The Irem M92. Again...
by on (#157349)
Yup... Again, with all this talk of doing something simple originally, I figured I'd better try something simple, and since I didn't want to backtrack on the SNES, I figured I'd do it here, although that didn't work too well the last time...

Well, because I'm an idiot, I lost my x86 reference pdf file that I think lidnariq gave me. Also, I think I remember lidnariq saying something about not initializing some register during vblank where I was trying to DMA sprite data and that that could potentially be why no sprites ever appeared. In fact, does anyone know what topic that is from? I looked at the "Simple x86 Code" one, but I couldn't find it, so it must be something else.
Re: Attempting To Code For The Irem M92. Again...
by on (#157354)
You didn't initialize SS or SP on power up, so when an IRQ finished (or any subroutine, for that matter) it would return to some random value in ROM (since I think both SS and SP power on as 0?).

Unfortunately I have no idea what x86 reference I (if indeed I) gave you.
Re: Attempting To Code For The Irem M92. Again...
by on (#157361)
lidnariq wrote:
You didn't initialize SS or SP on power up, so when an IRQ finished (or any subroutine, for that matter) it would return to some random value in ROM (since I think both SS and SP power on as 0?).

What value are they supposed to hold then?

Also, do you remember what topic this was from?
Re: Attempting To Code For The Irem M92. Again...
by on (#157365)
Espozo wrote:
What value are they supposed to hold then?

SS and SP should point to the segment and offset where you want your stack to be. Unlike the 6502 and 65816, you can put the stack anywhere you want; the only limit is that it can't be larger than 64kB (since SP is 16 bits).
Re: Attempting To Code For The Irem M92. Again...
by on (#157367)
So, I'm guessing SS is the segment? Again, I'd just make the segment 4 bits and leave the rest 0, because that way, you could write to something like 0x40000 and 0x46000 without having to change the segment.

Joe wrote:
you can put the stack anywhere you want; the only limit is that it can't be larger than 64kB (since SP is 16 bits).

Well, that's the exact size of ram. (0xE0000 to 0xEFFFF) Not even the Irem M92 has as much ram as the SNES :lol: (Kind of shows you Nintendo's screwed up priorities...)

Anyway, what way does the stack go? Does it grow backward like on the SNES? If so, I'd just put it at the end of ram.
Re: Attempting To Code For The Irem M92. Again...
by on (#157369)
Espozo wrote:
Anyway, what way does the stack go? Does it grow backward like on the SNES? If so, I'd just put it at the end of ram.

The stack grows downward, same as SNES. To put it at the top of RAM, you'd set SS:SP to 0xE000:0x0000.
Re: Attempting To Code For The Irem M92. Again...
by on (#157370)
Joe wrote:
To put it at the top of RAM, you'd set SS:SP to 0xE000:0x0000.

I would have thought it'd be 0xE000:0xFFFF. Anyway, I'm guessing I have to do something like this?

Code:
  mov AX, 0xE000
  mov SS, AX

  mov AX, 0xFFFF
  mov SP, AX
Re: Attempting To Code For The Irem M92. Again...
by on (#157374)
Espozo wrote:
I would have thought it'd be 0xE000:0xFFFF.

This is the most common stack-related mistake I see x86 programmers making. Take a look at the description of the stack here. The 6502 family has an empty stack, but x86 has a full stack. In other words, when you push a value to the stack, SP is decremented first and the value is written second, and when you pop a value from the stack, the value is read first and SP is incremented second.

Espozo wrote:
Anyway, I'm guessing I have to do something like this?

SP is a general-purpose register, same as AX, so you can set it directly like this:
Code:
    mov ax, 0xe000
    mov ss, ax
    mov sp, 0x0000

It's common to use xor or sub to set a register to zero, even though it affects the flags, because it's a smaller instruction.
Code:
    xor sp, sp
Re: Attempting To Code For The Irem M92. Again...
by on (#157422)
Espozo wrote:
I would have thought it'd be 0xE000:0xFFFF.

Then you'd waste a byte. You should see E000:0000 like it was E000:10000 (then the first time you push a word, it'll go to E000:FFFE-FFFF).
Re: Attempting To Code For The Irem M92. Again...
by on (#157446)
Espozo wrote:
Also, do you remember what topic this was from?
Towards the end of your previous thread about it: viewtopic.php?p=151870#p151870
Re: Attempting To Code For The Irem M92. Again...
by on (#157468)
Well, I though I knew what I was doing, but apparently, I don't because I wanted to make this one simple code that would add 1 to the value of color 0 every frame, which was supposed to start out white, but it doesn't work in that it starts out at the default color black. Have any ideas?

Code:
;========================================================================
;Section IVT
;========================================================================

cpu 80186

section ivt start=0 ; you will need this later

idt:
   dw diverr_handler, (section.code.start >> 4)
   dw brk_handler, (section.code.start >> 4)
   dw nmi_handler, (section.code.start >> 4)
   dw int3_handler, (section.code.start >> 4)
   dw into_handler, (section.code.start >> 4)
   dw bound_handler, (section.code.start >> 4)
   dw undefinst_handler, (section.code.start >> 4)
   dw nocoprocessor_handler, (section.code.start >> 4)
   dw vbl_handler, (section.code.start >> 4)
   dw sprbuf_handler, (section.code.start >> 4)
   dw raster_handler, (section.code.start >> 4)
   dw sound_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw coprocessorerror_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw vbl_handler, (section.code.start >> 4)
   dw sprbuf_handler, (section.code.start >> 4)
   dw raster_handler, (section.code.start >> 4)
   dw sound_handler, (section.code.start >> 4)

;========================================================================
;Section Code (Pointers)
;========================================================================

section code vstart=0 align=16

diverr_handler:
  iret

brk_handler:
  iret

nmi_handler:
  iret

int3_handler:
  iret

into_handler:
  iret

bound_handler:
  iret

undefinst_handler:
  iret

nocoprocessor_handler:
  iret

vbl_handler:
  iret

sprbuf_handler:
  iret

raster_handler:
  iret

sound_handler:
  iret

def_handler:
  iret

coprocessorerror_handler:
  iret

;========================================================================
;Section Code (Main Code)
;========================================================================

main_code:

;Set Stack Location
  mov sp, 0xe000
  mov ss, sp
  mov sp, 0x0000

;White Color Upload
  mov di, VideoHardwareRamStart
  mov es, di
  mov di, PaletteRam
  mov dx, 0xFFFF
  mov [0x0000], dx
  sti         ;Enable Interupts


infinite_loop:
  mov dx, [0x0000]
  add dx, 0x0001
  mov [0x0000], dx
 
  hlt
  jmp infinite_loop

;========================================================================
;Section Data
;========================================================================

section data vstart=0 align=16

;========================================================================
;Section Reset
;========================================================================

section reset start=0x7FFF0 vstart=0

  cli
  jmp (section.code.start >> 4):main_code
 
  times 16-($-$$) db 0

;========================================================================
;Section RAM
;========================================================================

segment bss start=0xE0000 vstart=0 nobits align=16

;Define Stuff:
  WorkRamStart         equ 0xE000
  VideoHardwareRamStart      equ 0xF000

  SpriteRam         equ 0x8000
  PaletteRam         equ 0x8800
  SpriteControlRam      equ 0x9000

  ScreenWidth          equ 320
  ScreenHieght          equ 240

I think I just totally forgot how 20 bit addressing works...
Re: Attempting To Code For The Irem M92. Again...
by on (#157469)
Espozo wrote:
Code:
  mov dx, 0xFFFF
  mov [0x0000], dx

This isn't a 6502-family CPU, you can move immediate values directly to memory:
Code:
    mov [0x0000], word 0xffff

Espozo wrote:
I think I just totally forgot how 20 bit addressing works...

It looks like you're confusing yourself.

When you try to set the first color, you set ES to 0xF000 and DI to 0x8800, like you're expecting those to be implicitly used as the destination address. Only string instructions like stos and movs do that; everything else uses DS (or sometimes SS) as the segment by default, and requires you to explicitly code the offset.

So, when you do mov [0x0000], word 0xffff you're writing to 0x0000:0x0000 instead of 0xF000:0x8800 like you intended.

If you set DS to 0xF880 at the beginning, it should at least turn the screen white at the beginning. You'll also see the color cycle if any interrupts are occurring. (Recent fixes to MAME's M92 emulation may require you to set up the interrupt controller before you can receive any interrupts.)
Re: Attempting To Code For The Irem M92. Again...
by on (#157647)
Okay, sorry for not replying in a while (I have another certain issue...), but I tried this, but it didn't work for whatever reason. I thought I did everything right.

Code:
;========================================================================
;Section IVT
;========================================================================

cpu 80186

section ivt start=0 ; you will need this later

idt:
   dw diverr_handler, (section.code.start >> 4)
   dw brk_handler, (section.code.start >> 4)
   dw nmi_handler, (section.code.start >> 4)
   dw int3_handler, (section.code.start >> 4)
   dw into_handler, (section.code.start >> 4)
   dw bound_handler, (section.code.start >> 4)
   dw undefinst_handler, (section.code.start >> 4)
   dw nocoprocessor_handler, (section.code.start >> 4)
   dw vbl_handler, (section.code.start >> 4)
   dw sprbuf_handler, (section.code.start >> 4)
   dw raster_handler, (section.code.start >> 4)
   dw sound_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw coprocessorerror_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw vbl_handler, (section.code.start >> 4)
   dw sprbuf_handler, (section.code.start >> 4)
   dw raster_handler, (section.code.start >> 4)
   dw sound_handler, (section.code.start >> 4)

;========================================================================
;Section Code (Pointers)
;========================================================================

section code vstart=0 align=16

diverr_handler:
  iret

brk_handler:
  iret

nmi_handler:
  iret

int3_handler:
  iret

into_handler:
  iret

bound_handler:
  iret

undefinst_handler:
  iret

nocoprocessor_handler:
  iret

vbl_handler:
  iret

sprbuf_handler:
  iret

raster_handler:
  iret

sound_handler:
  iret

def_handler:
  iret

coprocessorerror_handler:
  iret

;========================================================================
;Section Code (Main Code)
;========================================================================

main_code:

;Set Stack Location
  mov sp, 0xe000
  mov ss, sp
  mov sp, 0x0000

;White Color Upload
  mov di, VideoHardwareRamStart
  mov es, di
  mov di, 0x0000
  mov [PaletteRam], word 0xFFFF
  sti         ;Enable Interupts


infinite_loop:
  add [PaletteRam], word 0x0001
 
  hlt
  jmp infinite_loop

;========================================================================
;Section Data
;========================================================================

section data vstart=0 align=16

;========================================================================
;Section Reset
;========================================================================

section reset start=0x7FFF0 vstart=0

  cli
  jmp (section.code.start >> 4):main_code
 
  times 16-($-$$) db 0

;========================================================================
;Section RAM
;========================================================================

segment bss start=0xE0000 vstart=0 nobits align=16

;Define Stuff:
  WorkRamStart         equ 0xE000
  VideoHardwareRamStart      equ 0xF000

  SpriteRam         equ 0x8000
  PaletteRam         equ 0x8800
  SpriteControlRam      equ 0x9000

  ScreenWidth          equ 320
  ScreenHieght          equ 240
Re: Attempting To Code For The Irem M92. Again...
by on (#157649)
Well, part of the problem is you're setting ES but all of your instructions that access memory are using DS...

Maybe I should write up an overview of x86 addressing modes that apply to the 80186.
Re: Attempting To Code For The Irem M92. Again...
by on (#157650)
Yay, it works! :) I'm glad we finally got vblank to work correctly. Next up, sprites...

Now, imagine how slow a 24 bit color would change by adding 1...

Joe wrote:
Maybe I should write up an overview of x86 addressing modes that apply to the 80186.

I wasn't too bad until I lost my document I was using as a reference.
Re: Attempting To Code For The Irem M92. Again...
by on (#157682)
Code:
[bx+si] [bx+si+off8] [bx+si+off16]
[bx+di] [bx+di+off8] [bx+di+off16]
[bp+si] [bp+si+off8] [bp+si+off16]
[bp+di] [bp+di+off8] [bp+di+off16]
[si]    [si+off8]    [si+off16]
[di]    [di+off8]    [di+off16]
[off16] [bp+off8]    [bp+off16]
[bx]    [bx+off8]    [bx+off16]
All modes containing BP use SS, the rest use DS.

I couldn't find a single good 80186 reference in my archives or bookmarks - they're all for the 80386 and newer, which would probably just confuse you further. I wish I'd kept those Turbo Assembler books now.
Re: Attempting To Code For The Irem M92. Again...
by on (#157692)
Rahsennor wrote:
All modes containing BP use SS, the rest use DS.

Unless you're worried about instruction size, it's a lot easier to think of it like this:
Code:
none   none
 BX  +  SI  +  offset
 BP     DI
You can choose a "base" of 0, BX, or BP, an "index" of 0, SI, or DI, and an offset of any value. If you choose BP, the default segment is SS instead of DS.

The "base" and "index" names are for remembering which registers are allowed in each column.
Re: Attempting To Code For The Irem M92. Again...
by on (#157712)
Well, I found this old topic just now, and it looks like it should hold the reference I was using...

viewtopic.php?f=5&t=12595
Re: Attempting To Code For The Irem M92. Again...
by on (#157729)
Hey, I'm just curious, but are hardware registers like ax zeroed out on startup? It's not the end of the world, I'm honestly just curious if I should do it or not for one occasion. Also, I think I heard something like "mov ax, 0x0000" is as fast as "xor ax, ax" on the 80186, or am I wrong? I suppose it doesn't matter, I just personally like the look of "mov ax, 0x0000" better.

You know though, I'm trying to get sprites to display now, but I remembered the problem... I know the format for each sprite ram entry, (it's on the last page of the topic I linked) but does anyone remember how "sprite control" works? I remember there's a "switch" that DMA's a part of ram (0xF8000) to wherever to make sprites display, but I don't remember what bit does this at what register, and we never figured out how this works, because I remember I tried to activate it during active display and nothing happened, so I tried during vblank, but that's when that wasn't working.
Re: Attempting To Code For The Irem M92. Again...
by on (#157736)
Espozo wrote:
are hardware registers like ax zeroed out on startup?
The V33 clears DS, ES, and SS, sets CS to 0xFFFF, and sets IP (and the prefetch pointer) to 0x0000. I don't know about other members of the family; it'd be best if you assumed you needed to initialize things.

Quote:
[is] "mov ax, 0x0000" [...]as fast as "xor ax, ax" on the 80186[?]
No need to ask us: consult the V33A datasheet itself.
V33 datasheet wrote:
MOV   reg, imm   encoded as: 1 0 1 1 W reg | imm  2-3 bytes   2 cycles   operation: reg←imm
[...]
XOR   reg, reg   0 0 1 1 0 0 1 W | 1 1 reg reg'   2 bytes   2 cycles   operation: reg←reg ⊕ reg'
So: If the instruction before it is computation limited (rather than prefetch limited), they'll both take two cycles. Otherwise using the 16-bit literal will be slower by the extra byte.
Re: Attempting To Code For The Irem M92. Again...
by on (#157740)
lidnariq wrote:
No need to ask us: consult the V33A datasheet itself.

Oh, oops... :lol: I didn't mean to ask questions I could easily answer myself...

lidnariq wrote:
computation limited (rather than prefetch limited)

You mean there's more than just the number of cycles I need to be worried about now? :( Well, I'll just sick with "xor ax, ax" I'm sure it also takes less memory, not like I really care though.
Re: Attempting To Code For The Irem M92. Again...
by on (#157962)
Well, sorry for not posting on this in a while, but I saw this:

I wrote:
Well, relating to sprites, I forgot about how I found something called "sprite control" located at 0xF9000 through 0xF900F, so it's only 16 bits long. I look at the other file, and this is what I found:

Code:
62 WRITE16_MEMBER(m92_state::m92_spritecontrol_w)
63 {
64    COMBINE_DATA(&m_spritecontrol[offset]);
65    // offset0: sprite list size (negative)
66    // offset1: ? (always 0)
67    // offset2: sprite control
68    // offset3: ? (always 0)
69    // offset4: sprite dma
70    // offset5: ?
71
 
72    /* Sprite control - display all sprites, or partial list */
73    if (offset==2 && ACCESSING_BITS_0_7)
74    {
75       if ((data & 0xff) == 8)
76          m_sprite_list = (((0x100 - m_spritecontrol[0]) & 0xff) * 4);
77       else
78          m_sprite_list = 0x400;
79
 
80       /* Bit 0 is also significant */
81    }
82
 
83    /* Sprite buffer - the data written doesn't matter (confirmed by several games) */
84    if (offset==4)
85    {
86       /* this implementation is not accurate: still some delayed sprites in gunforc2 (might be another issue?) */
87       m_spriteram->copy();
88       m_sprite_buffer_busy = 0;
89
 
90       /* Pixel clock is 26.6666MHz (some boards 27MHz??), we have 0x800 bytes, or 0x400 words to copy from
91       spriteram to the buffer.  It seems safe to assume 1 word can be copied per clock. */
92       timer_set(attotime::from_hz(XTAL_26_66666MHz) * 0x400, TIMER_SPRITEBUFFER);
93    }
94 //  logerror("%04x: m92_spritecontrol_w %08x %08x\n",space.device().safe_pc(),offset,data);
95 }

So if you write a number to offset 0, (which is 0xF9000?) the number of sprites will be the same as the number you moved there? What's up with this then?

Code:
67    // offset2: sprite control
...
72    /* Sprite control - display all sprites, or partial list */
73    if (offset==2 && ACCESSING_BITS_0_7)

And I saw

Quote:
Joe wrote:
That code says you need to write a value to 0xF9000 that will determine how many sprites to draw, then write 8 (or a word with 8 in the low byte) to 0xF9004 to make the sprite drawing logic use that number. Afterwards, write any value to 0xF9008 to copy the sprites from sprite RAM to the internal drawing buffer.

It looks like this logic was designed specifically for rep movsw.

Edit: these registers start at 0xF9000, not 0xF0000.

So I wrote (should I keep copying the whole thing, or do you think we're good?)

Code:
;========================================================================
;Section IVT
;========================================================================

cpu 80186

section ivt start=0 ; you will need this later

idt:
   dw diverr_handler, (section.code.start >> 4)
   dw brk_handler, (section.code.start >> 4)
   dw nmi_handler, (section.code.start >> 4)
   dw int3_handler, (section.code.start >> 4)
   dw into_handler, (section.code.start >> 4)
   dw bound_handler, (section.code.start >> 4)
   dw undefinst_handler, (section.code.start >> 4)
   dw nocoprocessor_handler, (section.code.start >> 4)
   dw vbl_handler, (section.code.start >> 4)
   dw sprbuf_handler, (section.code.start >> 4)
   dw raster_handler, (section.code.start >> 4)
   dw sound_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw coprocessorerror_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw def_handler, (section.code.start >> 4)
   dw vbl_handler, (section.code.start >> 4)
   dw sprbuf_handler, (section.code.start >> 4)
   dw raster_handler, (section.code.start >> 4)
   dw sound_handler, (section.code.start >> 4)

;========================================================================
;Section Code (Pointers)
;========================================================================

section code vstart=0 align=16

diverr_handler:
  iret

brk_handler:
  iret

nmi_handler:
  iret

int3_handler:
  iret

into_handler:
  iret

bound_handler:
  iret

undefinst_handler:
  iret

nocoprocessor_handler:
  iret

vbl_handler:
  iret

sprbuf_handler:
  iret

raster_handler:
  iret

sound_handler:
  iret

def_handler:
  iret

coprocessorerror_handler:
  iret

;========================================================================
;Section Code (Main Code)
;========================================================================

main_code:

;Set Stack Location
  mov sp, 0xE000
  mov ss, sp
  xor sp, sp

;White Color Upload
  mov di, VideoHardwareRamStart
  mov ds, di
  xor di, di
  mov [PaletteRam], word 0xFFFF
  sti            ;Enable Interupts

;Display Sprite
  mov [SpriteControlRam + 0], word 0xFFFF
  mov [SpriteControlRam + 4], byte 0x08
  mov [SpriteControlRam + 8], byte 0xFF

infinite_loop:
  add [PaletteRam], word 0x0001
 
  hlt
  jmp infinite_loop

;========================================================================
;Section Data
;========================================================================

section data vstart=0 align=16

;========================================================================
;Section Reset
;========================================================================

section reset start=0x7FFF0 vstart=0

  cli
  jmp (section.code.start >> 4):main_code
 
  times 16-($-$$) db 0

;========================================================================
;Section RAM
;========================================================================

segment bss start=0xE0000 vstart=0 nobits align=16

;Define Stuff:
  WorkRamStart         equ 0xE000
  VideoHardwareRamStart      equ 0xF000

  SpriteRam         equ 0x8000
  PaletteRam         equ 0x8800
  SpriteControlRam      equ 0x9000

  ScreenWidth          equ 320
  ScreenHieght          equ 240

But nothing happened, and yes, I have graphics at the beginning of chr rom for sprites. I think I remember running into the same situation and thinking that maybe it needed to go in vblank (which at the time wasn't set up right) but I noticed this:

Code:
65    // offset0: sprite list size (negative)

What does it mean be "(negative)"? I just wrote 0xFFFF and it didn't seem to work, so I'm assuming I did this wrong. You know, is it me, or have I already asked this exact same thing before? I just can't find it...

Another thing is I wonder if I could try to contact someone again. I remember I went to some MAME forum and asked them some stuff about this, and they basically told me that they didn't have a clue and that I should look at the "official" MAME developer's forum and asked, but it's one of those places where you sign up and wait to be approved, and I checked it after two weeks and I had still never been verified... I have a sad feeling that I know just about as much as this arcade board as anyone else...
Re: Attempting To Code For The Irem M92. Again...
by on (#158029)
Espozo wrote:
(should I keep copying the whole thing, or do you think we're good?)

Can you put it on GitHub or something? It's really tough to scroll through these posts... (Plus, version control is always a good idea.)

Espozo wrote:
But nothing happened,

Probably because you didn't put any sprites in the sprite RAM before starting the sprite DMA. :wink:

Espozo wrote:
vblank (which at the time wasn't set up right)

Technically it's still not set up right. You run your vblank "handler" after every interrupt, whether it's vblank or not. Code that needs to run during vblank needs to go in the vblank handler, especially now that you're working with sprites and receiving an interrupt from that as well.

Of course, if you run any code in an interrupt handler, you must save and restore any registers it changes. Fortunately, the V33 is compatible with the 80186, which means you can use pusha and popa to save and restore all 7 of the general-purpose registers. You'll probably want to access memory (or memory-mapped hardware) during vblank, so you'll also need to save and restore at least one segment register.

Espozo wrote:
What does it mean be "(negative)"?

It means this:
Code:
m_sprite_list = (((0x100 - m_spritecontrol[0]) & 0xff) * 4);
You wrote -1, so you should get 1 sprite.

Espozo wrote:
I have a sad feeling that I know just about as much as this arcade board as anyone else...

If anyone knows more, they haven't fixed the remaining bugs in MAME's implementation. (Incidentally, you're only receiving interrupts because of one of those bugs: on a real M92, you would need to configure the interrupt controller.)
Re: Attempting To Code For The Irem M92. Again...
by on (#158096)
Joe wrote:
Can you put it on GitHub or something? It's really tough to scroll through these posts... (Plus, version control is always a good idea.)

I don't have a GitHub account or whatever and I don't feel like getting one, so I'll just post whatever I changed from the last time.

Joe wrote:
Probably because you didn't put any sprites in the sprite RAM before starting the sprite DMA. :wink:

There are graphics at the first tile in sprite chr data, so the tile number can be 0, and I'm pretty sure the location (0,0) is the top left corner, so something should show even if sprite ram is all zeroed. :wink:

Joe wrote:
Espozo wrote:
What does it mean be "(negative)"?

It means this:
Code:
m_sprite_list = (((0x100 - m_spritecontrol[0]) & 0xff) * 4);
You wrote -1, so you should get 1 sprite.

What? Could you just tell me the number value (0xXXXX) for 1 sprite? :oops:

Edit: Oh, wait, I remember, "negative" numbers are just regular numbers with the values of every bit being flipped, right? Well, in that case, shouldn't every sprite be visible if you just wrote 0x00? Wait, also, if this number is an 8 bit number, that means that you always display at least one sprite no matter what, because there are 256 sprites.
Re: Attempting To Code For The Irem M92. Again...
by on (#158097)
Espozo wrote:
I don't have a GitHub account or whatever and I don't feel like getting one, so I'll just post whatever I changed from the last time.

If you say so. :|

Espozo wrote:
There are graphics at the first tile in sprite chr data, so the tile number can be 0, and I'm pretty sure the location (0,0) is the top left corner, so something should show even if sprite ram is all zeroed. :wink:

Are you sure? There are several bits in there besides coordinates and tile number, and some of them might need to be set for anything to render.

Espozo wrote:
What? Could you just tell me the number value (0xXXXX) for 1 sprite? :oops:

-1. Your assembler understands that. In hex, that's FF. (It's only a byte. Your assembler might complain, but it will generate the correct value for any number from -1 to -255.)

Espozo wrote:
Oh, wait, I remember, "negative" numbers are just regular numbers with the values of every bit being flipped, right?

Not quite.

Espozo wrote:
Well, in that case, shouldn't every sprite be visible if you just wrote 0x00? Wait, also, if this number is an 8 bit number, that means that you always display at least one sprite no matter what, because there are 256 sprites.

Nope. MAME says writing 0 gets you 0 sprites. If you want all 256 sprites, you have to set spritecontrol+4 to some value other than 8.
Re: Attempting To Code For The Irem M92. Again...
by on (#158098)
Joe wrote:
Espozo wrote:
I don't have a GitHub account or whatever and I don't feel like getting one, so I'll just post whatever I changed from the last time.

If you say so. :|

Is that really that bad? :lol:

Joe wrote:
Espozo wrote:
There are graphics at the first tile in sprite chr data, so the tile number can be 0, and I'm pretty sure the location (0,0) is the top left corner, so something should show even if sprite ram is all zeroed. :wink:

Are you sure? There are several bits in there besides coordinates and tile number, and some of them might need to be set for anything to render.

This is it:

Code:
  fedc ba98 7654 3210
0 LLLW WHHy yyyy yyyy
1 tttt tttt tttt tttt
2        YX plll llll
3         x xxxx xxxx

L - layer
W,H - width, height (0,1,2,3 = 1,2,4,8 16x16 tiles)
X,Y - reflect X,Y
x,y - x,y coordinate
t - tile
p - priority
l - color

Joe wrote:
Nope. MAME says writing 0 gets you 0 sprites. If you want all 256 sprites, you have to set spritecontrol+4 to some value other than 8.

I was talking about spritecontrol+8.
Re: Attempting To Code For The Irem M92. Again...
by on (#158107)
Espozo wrote:
Is that really that bad? :lol:

Your code is terrible and ugly. :roll: It won't be so much of a problem once you're more familiar with x86.

Espozo wrote:
This is it:

I saw something in the sprite logic that looked funny, but I didn't trace it out to see which of those values controlled its behavior. Since you have documentation on the format, you can easily try different combinations of parameters while ensuring the X and Y coordinates remain on-screen.

Espozo wrote:
Joe wrote:
Nope. MAME says writing 0 gets you 0 sprites. If you want all 256 sprites, you have to set spritecontrol+4 to some value other than 8.

I was talking about spritecontrol+8.

I was talking about spritecontrol+0, since that's the byte that controls how many sprites are displayed when you write 8 to spritecontrol+4. The hardware doesn't care what value you write to spritecontrol+8. Writing any value there begins sprite DMA.
Re: Attempting To Code For The Irem M92. Again...
by on (#158130)
Joe wrote:
Your code is terrible and ugly. :roll:

Thanks... :lol: If it makes you feel any better, I might get a GitHub account, but only if you're a good boy. :wink:

Joe wrote:
I saw something in the sprite logic that looked funny, but I didn't trace it out to see which of those values controlled its behavior.

Oh yeah, you still have all the Irem M92 stuff that I do, don't you... What do you mean by something in the sprite logic "looked funny" though? Where you looking at the Mame C++ code?

Joe wrote:
Since you have documentation on the format, you can easily try different combinations of parameters while ensuring the X and Y coordinates remain on-screen.

Well, unless I want to make 300 files with one parameter changed, (which would take for ever because I have to put the .asm file through yasm, and then put the output file through the word splitter, and then rename both of those files and then put them in a folder with the rest of the games files like the tile data and then compress all of that and then put it in the Mame roms folder and then run my batch file to run Mame in debug mode) I would have to change them while the demo is running, which would require reading the controllers... Well, I've gotten BGs to display, so I could test if the controllers are working by manipulating BG positions or something.

Joe wrote:
I was talking about spritecontrol+0, since that's the byte that controls how many sprites are displayed when you write 8 to spritecontrol+4. The hardware doesn't care what value you write to spritecontrol+8. Writing any value there begins sprite DMA.
Oops, yeah, I meant spritecontrol+0.
Re: Attempting To Code For The Irem M92. Again...
by on (#158153)
Espozo wrote:
Oh yeah, you still have all the Irem M92 stuff that I do, don't you... What do you mean by something in the sprite logic "looked funny" though? Where you looking at the Mame C++ code?

I saw something that controlled priority and couldn't tell what it was supposed to do. I just now noticed an explanation for it at the top of this file, so I guess that's not a problem.

Espozo wrote:
Well, unless I want to make 300 files with one parameter changed, I would have to change them while the demo is running, which would require reading the controllers...

Or you can cycle through possible values every vblank. Cycling through all possibilities would take a while, but only cycling a few bits would take seconds to repeat.

Also, filling the sprite ROMs so you didn't have to worry about tile numbers might be a good idea.
Re: Attempting To Code For The Irem M92. Again...
by on (#158158)
Well, I honestly think that it would be good to try and read the controllers, so I was trying to turn on BGs like I did last time, but then I remembered that the registers to enable the BGs exist on some sort of separate address space somehow, same with the controllers: http://patpend.net/technical/arcade/m92.html How do I write to the BG control? Also, I imagine it would be about the same for controllers, except your taking in values instead of sending them.
Re: Attempting To Code For The Irem M92. Again...
by on (#158162)
The x86 architectures has two address spaces: memory and I/O. Everything you've done so far has been in the memory space, which isn't surprising since it's the more commonly used of the two. The one you're looking at now is the I/O address space.

You can only access the I/O space with a few instructions. They are in, out, insb, insw, outsb, and outsw. You'll mostly only want to use in and out for now. Those two instructions haven't changed much in the lifespan of the x86 architecture, so even modern resources can teach you how to use them. (Of course, ignore the parts that reference 32-bit anything, since the V33 is 16-bit.)
Re: Attempting To Code For The Irem M92. Again...
by on (#158170)
Wait a minute, I just saw something...

Quote:
Master Control registers:
Word 0: Playfield 1 control
Bit 0x40: 1 = Rowscroll enable, 0 = disable
Bit 0x10: 0 = Playfield enable, 1 = disable
Bit 0x04: 0 = 512 x 512 playfield, 1 = 1024 x 512 playfield
Bits 0x03: Playfield location in VRAM (0, 0x4000, 0x8000, 0xc000)
Word 1: Playfield 2 control (as above)
Word 2: Playfield 3 control (as above)
Word 3: Raster IRQ position.

If a bit has to be 0 to enable BGs, doesn't that mean that they should already be enabled? Unless everything starts out 1 filled.

Edit: Oh, wait, everything does start out 0 filled, so every BG is enabled by default. I just moved graphics into the first tile of BG chr rom.
Re: Attempting To Code For The Irem M92. Again...
by on (#210729)
I somewhat randomly decided to work on this again, this time ignoring sprites and working on everything else first. I've got reading from the controllers to work (not hard, just check different bits in a register) and have also been able to write to the tilemap and change its position and size in vram in addition to changing the palette. My question though, is that while I can successfully change VRAM (where the tilemap is stored) and CGRAM (or whatever it's called here) whenever I want to during active display in MAME, would it be unlikely that this would work on an actual system?

Also, something I noticed is that there doesn't appear to be a brightness register, which means fadeouts have to be done by changing CGRAM. Potentially, you would need to upload 4KB of color data (2048, 15 bit colors) in one frame, and if you can only update CGRAM during VBlank, it may not be possible. Unless you want to have a huge mass of palettes in ROM, you have to make a routine that darkens them as well, which for simplicity, would be subtracting 1 from red, green, and blue at the same time for every color. I imagine modern video games and image processing programs (unless otherwise specified) make bright color elements and overall colors turn darker faster than already dark ones.
Re: Attempting To Code For The Irem M92. Again...
by on (#210750)
I know nothing about this hardware, and little about MAME internally, so hopefully someone else can chime in with better information.

In general though, I would be extremely cautious about using an emulator for testing a new program. This likely would lead to some headaches. Other than not knowing when it's safe to write to video memory, I can imagine other potential situations such as registers or other settings being initialized differently on the hardware, bugs or quirks in the hardware that the developers had work-arounds for (the undesirable side effects might not be emulated, because the situation never arises in the existing games). All that can be overcome, but I'd expect to run into trouble.

The best setup would be to have a ROM emulator plugged into the actual board, but if those 2 devices together cost like $500 or whatever, that's a pretty expensive hobby. If that board happens to run code from a 27C040 EPROM, I could probably loan you a ROM emulator (parallel port device and may require DOS/Win98 though).
Re: Attempting To Code For The Irem M92. Again...
by on (#210780)
Memblers wrote:
I can imagine other potential situations such as registers or other settings being initialized differently on the hardware

Luckily, there aren't to many registers to worry about: http://patpend.net/technical/arcade/m92.html This thing is incredibly straightforward compared to the SNES, but then again, what isn't. :lol:

Memblers wrote:
If that board happens to run code from a 27C040 EPROM

I've been told it runs from a 27C020 EPROM; I have no idea if there's a difference, as they look identical. Well, it uses two and interleaves the bytes, but regardless if your device can support two chips, not even my old Windows XP computer has a parallel port. I just got a bunch of 27C020 EEPROM chips and a EPROM/EEPROM programmer; I have no idea how long it takes to program and reprogram them, but hopefully not long.

Memblers wrote:
but if those 2 devices together cost like $500 or whatever, that's a pretty expensive hobby.

That'll be the cost of the supergun, Sega Genesis to Neo Geo controller converter, SCART cables, SCART to component converter, power supply, EEPROM programmer, EEPROM chips, and the board if I'm lucky. :|
Re: Attempting To Code For The Irem M92. Again...
by on (#210793)
You can forget EPROMs and get some NOR Flash chips instead unless you fancy waiting 45ish minutes each time when erasing EPROMs with your favorite UV eraser. There might be some pinout differences though and you may have to reroute a VPP line to accomodate a new address line, but that you'll find out when comparing datasheets.
020 parts are 2MBit, 040 are 8MBit. 27Cxxx are EPROMs, 28Fxxx and 29Fxxx are NOR Flash. 29L or LV parts are 3.3V and you want to stay away from those.
Re: Attempting To Code For The Irem M92. Again...
by on (#210801)
Yeah, I found some EEPROMs of the right type that I'll buy instead. I have everything in the eBay shopping cart because I figure I'll order it when I get the boards, but I haven't found a good deal yet. :(
Re: Attempting To Code For The Irem M92. Again...
by on (#210807)
Yeah my ROM emulator is just for one 8-bit ROM, sizes 27C64 through 27C040 (8kB through 512kB). It has a connector to chain multiple devices together to support multiple ROMs, but I only have one of them. And it's pretty obscure so I doubt I'll ever see another one. Was made in 1993, I bought it around '99 or '00 for about $200.

Looks like a pair of these newer ROM emulators would run you $374. Assuming the software allows you connect 2 of them.
http://www.moates.net/ostrich-20-the-new-breed-p-169.html?cPath=95
http://www.moates.net/emuc3206-emulation-cable-32pin-6inch-p-168.html?cPath=32

I'd bet if you watched ebay for a while you could probably find a suitable 16-bit ROM emulator for maybe <$100. Between missing cables, being sold in untested condition, and missing software, it might take some luck and/or improvisation. In my case I had to hand-build a 32-pin adapter (just like the one in the link above, which no one sold at the time), by using a 40-pin one, and sawing it off and epoxying it back together (was around the time I first met kevtris, he helped me with that).

Chip programming speed might take a minute or so, but it depends on the exact programmer and chips used. The EPROM eraser I use at work runs for maybe 15 minutes. On the other hand, SST39SF-series parts erase pretty much instantly. AM29F-series seems to vary widely in program/erase times, but it's still much faster than EPROM. Like TmEE said, I'd also recommend going with NOR flash, such as 39SF. But the pinout is a little bit different, so you would have to mod the the board or build some kind of adapter.

Also when it comes to swapping socketed chips often, what I've done before is buy extra IC sockets (the cheap 'dual-wipe' ones, not the machined pins type). Leave the chip permanently in one of those sockets, then plug that into the other socket on the board. The socket-to-socket connect is like a makeshift ZIF socket, instead of prying it out with a screwdriver. Assuming the 2 socket types are compatible, I've always done it with the exact same type so in other cases, who knows.
Re: Attempting To Code For The Irem M92. Again...
by on (#236160)
Old ass thread, but no point in making a third one...

I figured I'd take another stab at this after having programmed learned ARM assembly on a microcontroller and C as well as some C++ (enough to read the M92 driver in MAME, for the most part, anyway). I cleaned up the old code significantly and made a batch file that assembles the .asm file, then copies this and all the other relevant files for the game to a folder, zips it, copies the zip folder to the MAME roms directory, then runs MAME in debug mode; it's been a blessing.

I don't know what I accidentally did while modifying my old code though, because reaching the end of vblank (vblank is where it starts) forces the processor to jump to 0x00000 where the interrupt vector table is (the table should be correct; it's just a bunch of pointers to iret instructions), which obviously results in a crash. It's successfully able to return when I call subroutines though; it looks like "call" only pushes the instruction pointer and not the code segment. I have a GitHub now; I was planning on uploading this whole project when I got something presentable made, but I can do it now if needed.

speaking of which, would it be frowned upon to include free software like 7z as part of the binaries? My script depends on it, for instance.



I did notice something interesting though while looking through the debugger, and that's that clearing the sprite buffer works at least, as something like 4000 cycles are used with a write to 0x9F004. It also changes something called "sprite_buffer_busy" from 0x01 (its value at startup) to 0x00 after clearing the ram. I can't find anything on this, including what address it's located at, even after looking through MAME's sourcecode. I think I know enough x86 assembly now to look through the original game in the debugger and find out how the sprite registers are dealt with, even if the syntax is NEC's.

And having had to look at earlier threads I made on this, wow, thank everyone so much for dealing with me when I first started here.
Re: Attempting To Code For The Irem M92. Again...
by on (#236163)
Drew Sebastino wrote:
I don't know what I accidentally did while modifying my old code though, because reaching the end of vblank (vblank is where it starts) forces the processor to jump to 0x00000 where the interrupt vector table is (the table should be correct; it's just a bunch of pointers to iret instructions), which obviously results in a crash. It's successfully able to return when I call subroutines though; it looks like "call" only pushes the instruction pointer and not the code segment.

I seem to remember there being near call (E8) and far call (9A) instructions in 8086. They'd be analogous to JSR and JSL instructions in 65816.

Drew Sebastino wrote:
speaking of which, would it be frowned upon to include free software like 7z as part of the binaries? My script depends on it, for instance.

In this topic, it was suggested to make a batch file that adds free software to the PATH and then launches Command Prompt. The user would have to customize it based on where each such application is installed.

Drew Sebastino wrote:
I did notice something interesting though while looking through the debugger, and that's that clearing the sprite buffer works at least, as something like 4000 cycles are used with a write to 0x9F004.

Is this some sort of DMA trigger, like $4014 on NES or $FF46 on GB? I seem to remember another platform that put the sprite table in video memory, but just setting its base address caused problems until the program ran a DMA or other copy to VRAM so that the PPU could snoop the writes and cache the sprite table. Maybe it was the Genesis.
Re: Attempting To Code For The Irem M92. Again...
by on (#236164)
It's now on GitHub for anyone who wants to see it: https://github.com/DrewSebastino/irem_m92_starter_kit

tepples wrote:
In this topic, it was suggested to make a batch file that adds free software to the PATH and then launches Command Prompt. The user would have to customize it based on where each such application is installed.

I have no idea how you'd do that; I just included the names of what needs to be downloaded as well as the URLs to each in the readme.

tepples wrote:
Is this some sort of DMA trigger, like $4014 on NES or $FF46 on GB?

Correct. I assume it just zero fills sprite ram rather than copies memory though, as indicated by this: https://patpend.net/technical/arcade/m92.html
Re: Attempting To Code For The Irem M92. Again...
by on (#236182)
I figure this might be useful, somehow:

Attachment:
CPU Registers.png
CPU Registers.png [ 2.29 KiB | Viewed 5758 times ]

These are both the state of the processor one instruction before the interrupt for my program (to the left) and Geo Storm (It actually goes that many cycles before without an interrupt; performing sti triggers it)

Because no one knows NEC's syntax, I'll say what each register is for the ones I know;

IP: IP
SP: SP
F: F
AW: AX
BW: BX
CW: CX
DW: DX
BP: GS (I think?)
IX: SI
IY: DI
DS1: ES
PS: CS
SS: SS
DS0: DS
XA: ???

My interrupt vector table is now 256, 4 byte entries of the exact same address to an iret, so I feel it's safe to rule out the error there...

Also, unrelated, but how would anyone suggest palette conversion? yychr has something called a .pal file, which I see is just 24 bit RGB values. It'd be trivial to write a C program that reduces each color component to 5 bits then bit packs it, but then I'm not sure what I'd do from there. I don't know if it would be overboard if I had my main.asm file include a text (instead of a binary) file that is generated by the converter based on a bunch of different inputted .pal files. It would look like this: (The palette converter now just uses the top 4 nibbles of the palette address, because the bottom is assumed to be 0.)

Code:
section palette1 vstart=0 align=16
PALETTE1   equ (section.palette1.start >> 4)

  dw 0xFFFF,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007
  dw 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F

section palette2 vstart=0 align=16
PALETTE2   equ (section.palette2.start >> 4)

  dw 0xFFFF,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007
  dw 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F
Re: Attempting To Code For The Irem M92. Again...
by on (#236186)
Drew Sebastino wrote:
XA: ???
Xpansion Address is a V33/V53-specific operation flag that specifies whether the CPU just has the 8086's 20-bit address space literally, or then uses the V series's ridiculous MMU that converts the top 6 address bits of the resulting linear address (after the segment is folded in) into 10 bits (resulting in a 24-bit address space). See section 4 of the µPD70136 datasheet...
Re: Attempting To Code For The Irem M92. Again...
by on (#236190)
Code:
  mov ds, [bx + PALETTE_SOURCE]
  mov di, [bx + PALETTE_DESTINATION]

The first line changes ds, in the second line you are still (trying) to use the old ds value to read from memory.

In general, I would always specify the segment register for memory accesses, eg write "ds:[bx+imm]" instead of "[bx+imm]".
One reason is that some opcodes default to use ss instead of ds (if you don't specify ds:).
The other reason for specifying ds is that you will hopefully be more aware of where it is used (and that you shouldn't overwrite ds when still using it in the next instruction).

It is also very important which value you have loaded into ds, in your palette code it's loaded from dx, which points to ram in first loop cylce, and to video hardware in the following loop cycles?

BP is a standard 8086 register. FS and GS are additional segment registers invented on 80386.

Code:
  xor cx, cx
  mov si, cx

That is possible to do that. But you can also write "mov si,0", or "xor si,si" for faster and smaller code.

In interrupt handlers, many systems require to acknowledge the interrupt before returning from the interrupt, I don't know if that's the case here. Best leave interrupts disabled until you get more familar with writing a main program in 8086 code.

For bug searching, I would focus on the program code. The processor state that you have posted isn't so useful, at least not without having a disassembly of the corresponding program code. If you don't have a debugger or disassembler, try to output status messages or change screen color when your program does specific things - then you can see if it's ever reaching that code (or if it has crashed earlier).
Re: Attempting To Code For The Irem M92. Again...
by on (#236193)
nocash wrote:
The first line changes ds, in the second line you are still (trying) to use the old ds value to read from memory.
nocash wrote:
It is also very important which value you have loaded into ds, in your palette code it's loaded from dx, which points to ram in first loop cylce, and to video hardware in the following loop cycles?

Thanks! I had actually found those mistakes by stepping through the debugger when it refused to upload the palette correctly. It's fixed now and uploaded to GitHub. (The readme is also named correctly now) The lack of long addressing is pretty difficult adjusting to...

nocash wrote:
That is possible to do that. But you can also write "mov si,0", or "xor si,si" for faster and smaller code.

Oops, yeah, you're right. I'm definitely still in the process of learning x86.

nocash wrote:
then you can see if it's ever reaching that code (or if it has crashed earlier).

It actually completed that busted palette uploading code and goes to the halt instruction, then jumps to 0x0000. Unfortunately, even after fixing the palette code and stepping through it completely with the debugger, it still gets to the halt and then jumps to 0x0000.

nocash wrote:
In interrupt handlers, many systems require to acknowledge the interrupt before returning from the interrupt, I don't know if that's the case here. Best leave interrupts disabled until you get more familar with writing a main program in 8086 code.

I'd say that sounds like good advice...

lidnariq wrote:
Xpansion Address is a V33/V53-specific operation flag that specifies whether the CPU just has the 8086's 20-bit address space literally, or then uses the V series's ridiculous MMU that converts the top 6 address bits of the resulting linear address (after the segment is folded in) into 10 bits (resulting in a 24-bit address space). See section 4 of the µPD70136 datasheet...

Luckily I shouldn't have to worry about that. I might read it anyway though.
Re: Attempting To Code For The Irem M92. Again...
by on (#236194)
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?
Re: Attempting To Code For The Irem M92. Again...
by on (#236196)
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.
Re: Attempting To Code For The Irem M92. Again...
by on (#236198)
Maybe somehow you are executing from 0x41:0x68 instead of 0x40:0x78 ... ?
Re: Attempting To Code For The Irem M92. Again...
by on (#236200)
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...
by on (#236203)
They're the same linear address, but they'll show up differently on the stack.
Re: Attempting To Code For The Irem M92. Again...
by on (#236204)
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?
Re: Attempting To Code For The Irem M92. Again...
by on (#236239)
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.
Re: Attempting To Code For The Irem M92. Again...
by on (#236242)
Sorry for the late reply; I've been busy all day.

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.

Correct.

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.

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:
ERRIF directive at the end of the table, throwing an error if the table size isn't 400h bytes.

Do you have an idea of how to do this? I wrote:

Code:
end_of_ivt:

%if (end_of_ivt > 0x400)
  %error Interrupt Vector Table over 1KB.
%endif


But yasm writes "error: non-constant value given to `%if'"

nocash wrote:
Do you have an idea which interrupt is getting triggered? That would help to know what is happening.

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:
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.

That is only for the sound cpu program. I'm currently just using the files from Gunforce II for this.

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.

I have no idea, unfortunately.

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, 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:
For the in/out opcodes, you are always using 16bit ax, is that that intended?

Oh, oops, that's not.
Re: Attempting To Code For The Irem M92. Again...
by on (#236245)
Holy shit, look what I finally got working though:

Attachment:
Sprite.png
Sprite.png [ 1.57 KiB | Viewed 7594 times ]


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:
;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


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

Code:
   COMBINE_DATA(&m_spritecontrol[offset]);
   // offset0: sprite list size (negative)
   // offset1: ? (always 0)
   // offset2: sprite control
   // offset3: ? (always 0)
   // offset4: sprite dma
   // offset5: ?


but the offset is really the offset * 2, because it's apparently by words.
Re: Attempting To Code For The Irem M92. Again...
by on (#236531)
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...

Code:
;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


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.
Re: Attempting To Code For The Irem M92. Again...
by on (#236539)
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
Code:
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
Re: Attempting To Code For The Irem M92. Again...
by on (#236556)
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.

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.
Re: Attempting To Code For The Irem M92. Again...
by on (#236557)
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.
Re: Attempting To Code For The Irem M92. Again...
by on (#236558)
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.