Jump to content
NHL'94 Forums

Recommended Posts

Posted

I've been trying to solve some of the bugs in this ROM, and am graduating to slightly more powerful tools. I need some help rounding out my toolset. 

HEX editing.  I've gone from a basic HEX editor to ImHex, and despite it being a little glitchy and a pain to setup, I can't recommend it highly enough. It is vastly superior to a basic HEX editor for hacking a ROM.
https://imhex.werwolv.net

Emulation. The forums suggest using various builds of Gens for hacking, but I cannot get any build of Gens to show some errors that users have reported on original hardware, or show up in Genesis Plus GX or Exodus. I know in the past the author of Genesis Plus GX has warned about accuracy issues in Gens, and FWIW, I am finding Exodus the most powerful and accurate emulator for debugging, but this stuff is all pretty new to me, so take it with a grain of salt.
 

  1. For folks that use Gens. Do you know of any any settings that I might be missing, that improves it's accuracy?
     
  2. For folks that recommend Gens, have you compared it against Exodus? Would you still recommend Gens?
     
  3. For folks that recommend Gens, which build? In the past I've seen @smozoma suggest Gens_ReRecording_r352.zip, @kingraph suggest Gens r57shell Mod, and off-site I've been encouraged to try Gens Kmod. I've found the latter the most helpful, followed by r57shell mod, but have had accuracy problems with both.
     
  4. For folks who DON’T recommend Gens, what emulator do you recommend for debugging & hacking?
     
  5. For everyone: do you know of a Mac native build of Exodus?
     
  6. For everyone: do you know of a build of Genesis Plus GX with debugging / hacking tools?

Any and all advice appreciated!

cheers,

-a

  • Like 1
Posted

I tried exodus ages ago and gave up on it pretty fast. Can't remember why. Vaguely recall that I just couldn't get it to work.

What kind of bugs are you seeing on original hardware and other emus, but not in Gens?

Posted

I have no original hardware, but trying to fix bug(s) reported by users with original hardware. In the past I've had issues where I could replicate a bug in Genesis Plus GX, but the moment I loaded up a hacking version of Gens, I couldn't get it to happen. All ttheis time I thought I was just incompetent with Gens (fact check: true), but this past week I tried Exodus again, and bang, the error is there. 

So I staged some experiments. 

I've got my first replicable problem with Address Error $377 @0x12A40 / @0x12A40. If I run a couple dozen demos at once with some tweaked settings, I will usually get this error within 10 minutes, and will have it in virtually every game within an hour on Exodus or Genesis Plus GX. I can leave the same test sample running overnight in Gens, and still will not have an Address Error. I know Genesis Plus GX has a setting to enable or disable 68k address errors, I'm wondering if Gens has such a setting buried deep somewhere I didn't look.

Funny, I recall trying Exodus and throwing it out the window some time ago. I only went back to it this past week, and am scratching my head wondering why I discarded it before.

Posted

Looking at the Gens source code, the documentation for the starscream CPU emulator says:

Quote

Address and Bus Errors are not implemented.  For arcade game emulation,
   this is probably OK, but if you're emulating a home computer system, this
   could be cause for concern.

Something you could try is setting up the game with conditions similar to whatever makes it crash, enable the code Trace for a few seconds, and then look through the output file for usage of the 1:2A40 address (also try 1:2A3e and 1:2A42 since sometimes the addresses are off due to being for the instruction parameters instead of the start the instruction..)

Then look at the code leading up to that, and what memory it accesses (using the RAM Map... I'm not sure where that can be found... I have a copy if you need it, or maybe @chaos has a better version?). It could provide at least a hint at what's causing the crash.

 

  • Thanks 1
Posted (edited)

Thanks for looking that up! That explains it. I found the root of the problem. It was the memory allocation for teams in either the 30 team or 32 team ROM expansion. Do you know if any changes were made to memory allocations or addresses when that work was done? I've narrowed the problem to emerging with either to 30 or 32 team ROM expansion, and it having to do with a corrupt team pointer or similar data being used for the PowerPlay clock.

Edited by AdamCatalyst
  • Thanks 1
Posted

It's been a while since I've really delved into hacking, but from what I remember I liked the r57shell for the VRAM and trace/hook options.  Something was missing from Kmod, I just forgot what.  I never really had feedback on emulation accuracy or reasons to look elsewhere, so I just stuck with what I knew.  

believe with all the work that @chaos and @McMarkis (SNES, but he snoops around Genesis too) have been doing recently they are using IDA Pro, which can set breakpoints (a area of code that when triggered, pauses the game), that are extremely useful.  I'll let those guys comment as I don't have the experience of how that works or interfaces with some other emulator.

  • Like 1
Posted

IDA Pro looks awesome, and Chaos tried to hook me up, but alas it was beyond my skill level and comprehension at this point.

  • Like 1
Posted
4 hours ago, AdamCatalyst said:

I have no original hardware, but trying to fix bug(s) reported by users with original hardware. In the past I've had issues where I could replicate a bug in Genesis Plus GX, but the moment I loaded up a hacking version of Gens, I couldn't get it to happen. All ttheis time I thought I was just incompetent with Gens (fact check: true), but this past week I tried Exodus again, and bang, the error is there. 

So I staged some experiments. 

I've got my first replicable problem with Address Error $377 @0x12A40 / @0x12A40. If I run a couple dozen demos at once with some tweaked settings, I will usually get this error within 10 minutes, and will have it in virtually every game within an hour on Exodus or Genesis Plus GX. I can leave the same test sample running overnight in Gens, and still will not have an Address Error. I know Genesis Plus GX has a setting to enable or disable 68k address errors, I'm wondering if Gens has such a setting buried deep somewhere I didn't look.

Funny, I recall trying Exodus and throwing it out the window some time ago. I only went back to it this past week, and am scratching my head wondering why I discarded it before.

The instructions at $12A40 have to do with player status. The code will keep track of each player's status (injury, on bench, on ice, penalty box time).

-4 = injury for game

-3 = injury for period

-2 = bench

-1 = on ice

0+ = penalty box time (in seconds)

What it is trying to do is get how much time is left so it can display the PP time.

I wonder if it's a problem related to # of players on the team, or if it's more reproducible with more than one player in the box for a team.

EDIT: Yeah I tested with breakpoints, at RAM locations $C768 (Home) and $CACC (Away), it stores the player offset of the players in the penalty box (1 byte each, ends in $FF). This is used in the subroutine to get the player's status (in this case penalty box time, which 2 minutes = 120 seconds $78). It will check and make adjustments based on how many players are in the box and their time left.

So there must be an issue with the number of players, as there will only be space for status for 26 players.

  • Thanks 1
Posted
36 minutes ago, chaos said:

The instructions at $12A40 have to do with player status. The code will keep track of each player's status (injury, on bench, on ice, penalty box time).

-4 = injury for game

-3 = injury for period

-2 = bench

-1 = on ice

0+ = penalty box time (in seconds)

What it is trying to do is get how much time is left so it can display the PP time.

I wonder if it's a problem related to # of players on the team, or if it's more reproducible with more than one player in the box for a team

I would guess that the index of the player that is being used to index into the player data array is invalid, like a negative number (which gets interpreted as a huge positive number and tries to access an area outside of the RAM bounds)?

Posted
9 minutes ago, smozoma said:

I would guess that the index of the player that is being used to index into the player data array is invalid, like a negative number (which gets interpreted as a huge positive number and tries to access an area outside of the RAM bounds)?

Yeah, could be that. I'm thinking anything out of the range (0-25). If it's outside the range, it will pick up a different value and can't do the right math with it.

Posted

I've narrowed the problem down to the value in A2. I can manually force A2 to have a value with a valid team pointer and crashes go away, but that corrupts the graphic display for the PowerPlay clock. I think I'm pretty close to getting this sorted out now. Both mechanics are sharing A2, and for whatever reason the value used by the graphics system ($30A) isn't always cleared properly and replaced with the pointer. Been at it for quite some time, the pieces just started falling into place today.

Posted
12 minutes ago, AdamCatalyst said:

I've narrowed the problem down to the value in A2. I can manually force A2 to have a value with a valid team pointer and crashes go away, but that corrupts the graphic display for the PowerPlay clock. I think I'm pretty close to getting this sorted out now. Both mechanics are sharing A2, and for whatever reason the value used by the graphics system ($30A) isn't always cleared properly and replaced with the pointer. Been at it for quite some time, the pieces just started falling into place today.

Going into that subroutine starting at $12A2E, A2 is the start of the Home Team Struct ($C6CE) or the start of the Away Team Struct ($CA32), depending on who has the PP (A2 is the team on the penalty kill). The other team struct (PP team) will be in A3.

D0 is the end result in seconds and is returned from the function and used to calculate the displayed time.

								 ; a2 = team struct on PK
ROM:00012A2E                     ; a3 = team struct on PP
ROM:00012A2E
ROM:00012A2E                     CalcPenTime:                            ; CODE XREF: updatepwrplay+82↓p
ROM:00012A2E 4240                                clr.w   d0
ROM:00012A30 4243                                clr.w   d3
ROM:00012A32 41EA 009A                           lea     $9A(a2),a0      ; Move penalty box list start into a0 ($C768 for Home, $CACC for Away)
ROM:00012A36
ROM:00012A36                     _getstatus:                             ; CODE XREF: CalcPenTime+18↓j
ROM:00012A36                                                             ; CalcPenTime+20↓j
ROM:00012A36 4242                                clr.w   d2
ROM:00012A38 1418                                move.b  (a0)+,d2        ; move value at a0 (then increment) into d2
ROM:00012A3A 6B00 0014                           bmi.w   _endoflist
ROM:00012A3E 3432 2066                           move.w  $66(a2,d2.w),d2 ; move status of d2 player into d2 (pen time)
ROM:00012A42 0802 000E                           btst    #$E,d2          ; test bit 14 if set
ROM:00012A46 66EE                                bne.s   _getstatus      ; branch if set (player on ice, injured, on bench)
ROM:00012A48 9443                                sub.w   d3,d2           ; sub d3 from d2
ROM:00012A4A D042                                add.w   d2,d0           ; add d2 to d0
ROM:00012A4C 3602                                move.w  d2,d3           ; move d2 into d3
ROM:00012A4E 60E6                                bra.s   _getstatus      ; loop till end of list
ROM:00012A50                     ; ---------------------------------------------------------------------------
ROM:00012A50
ROM:00012A50                     _endoflist:                             ; CODE XREF: CalcPenTime+C↑j
ROM:00012A50 0C6B 0006 0024                      cmpi.w  #6,$24(a3)      ; checks how many players are on ice (6 = everyone)
ROM:00012A56 6700 2A0C                           beq.w   rtss2           ; exit if so
ROM:00012A5A 9043                                sub.w   d3,d0           ; sub d3 from d0
ROM:00012A5C 41EB 009A                           lea     $9A(a3),a0      ; same as above, opposite team
ROM:00012A60 4242                                clr.w   d2              ; clear d2
ROM:00012A62
ROM:00012A62                     _getstatusopp:                          ; CODE XREF: CalcPenTime+40↓j
ROM:00012A62 1418                                move.b  (a0)+,d2
ROM:00012A64 6B00 29FE                           bmi.w   rtss2
ROM:00012A68 0833 0006 2066                      btst    #6,$66(a3,d2.w) ; check if bit 6 is set (pen time 64 sec+)
ROM:00012A6E 66F2                                bne.s   _getstatusopp   ; branch if set
ROM:00012A70 B073 2066                           cmp.w   $66(a3,d2.w),d0 ; compare pen time a3 to d0 (total time for PP)
ROM:00012A74 6D00 29EE                           blt.w   rtss2           ; exit if less than
ROM:00012A78 D043                                add.w   d3,d0           ; add d3 to d0
ROM:00012A7A 4E75                                rts
ROM:00012A7A                     ; End of function CalcPenTime

 

 

 

 

  • Thanks 1
Posted

If the error was a bad address for instruction 00012A40, then it's this instruction that's crashing: 

ROM:00012A3E 3432 2066                           move.w  $66(a2,d2.w),d2 ; move status of d2 player into d2 (pen time)

Which I think means a2+d2.w+66 is goes to invalid memory. So maybe a2 is a garbage value, or d2.w is negative or massively positive?

Posted

ROM:00012A38 1418                                move.b  (a0)+,d2        ; move value at a0 (then increment) into d2
ROM:00012A3A 6B00 0014                           bmi.w   _endoflist
ROM:00012A3E 3432 2066                           move.w  $66(a2,d2.w),d2 ; move status of d2 player into d2 (pen time)

Looks like the BMI should protect from d2 being negative, but it's applying to a move.b instruction, so it's posisble d2.w is negative even though d2.b is positive?

Is it possible to change to "move.w $66(ad, d2.b), d2"? Or must the .w/.b match for a move?

Posted (edited)

It got it fixed guys. Will write it out when I have time. It was a strange bug, more likely to occur with line changes on. The A2 value set by the graphics for Line Changes or the PP clock was sometimes still present in A2 when it was read for the Team pointer. After seriously, an embarrassing amount of time over the past days, there was a fairly simple solution.

1. Right before A2 is used by the PP clock, I set A2 to the Home Team pointer, and A3 to Away.
2. I check the PP flag set by updatePowerPlay, and switch A2 <> A3 if A3 is on the PP.
3. Continue as it was.

That's it. Stress tested it for hours, with 30-50 simultaneous games, unrealistic extreme settings that reliably crash the ROM. No crashes. PP clock always accurate. I believe this potential "flaw" was present in the original game, but rarely if ever occurred. For whatever reason, it got exacerbated by the ROM expansion, and even more so in my ROM this year.

Original @0x012A2E
42 40 42 43 41 EA 00 9A

Revised @0x012A2E
42 40 4E B9 00 1F F8 00

New @0x01FF800
42 43 34 7C C6 CE 47 EA 03 64 08 38 00 06 C2 EE 66 02 C5 4B 41 EA 00 9A 4E 75

I couldn't figure out how to get this done inline, so relied on a patch.

Edited by AdamCatalyst
Posted
12 minutes ago, AdamCatalyst said:

It got it fixed guys. Will write it out when I have time. It was a strange bug, more likely to occur with line changes on. The A2 value set by the graphics for Line Changes or the PP clock was sometimes still present in A2 when it was read for the Team pointer. After seriously, an embarrassing amount of time over the past days, there was a fairly simple solution.

1. Right before A2 is used by the PP clock, I set A2 to the Home Team pointer, and A3 to Away.
2. I check the PP flag set by updatePowerPlay, and switch A2 <> A3 if A3 is on the PP.
3. Continue as it was.

That's it. Stress tested it for hours, with 30-50 simultaneous games, unrealistic extreme settings that reliably crash the ROM. No crashes. PP clock always accurate. I believe this potential "flaw" was present in the original game, but rarely if ever occurred. For whatever reason, it got exacerbated by the ROM expansion, and even more so in my ROM this year.

Original @0x012A2E
42 40 42 43 41 EA 00 9A

Revised @0x012A2E
42 40 4E B9 00 1F F8 00

New @0x01FF800
42 43 34 7C C6 CE 47 EA 03 64 08 38 00 06 C2 EE 66 02 C5 4B 41 EA 00 9A 4E 75

I couldn't figure out how to get this done inline, so relied on a patch.

Weird, because this code is before the call to $12A2E subroutine:

									updatepwrplay:                          ; CODE XREF: periodiceevents+46↑j
ROM:00012A7C 0838 0001 C2FA                      btst    #1,(word_FFC2FA).w
ROM:00012A82 6600 29E0                           bne.w   rtss2
ROM:00012A86 347C C6CE                           movea.w #(HmShots-M68K_RAM),a2
ROM:00012A8A 47EA 0364                           lea     $364(a2),a3
ROM:00012A8E 302A 0024                           move.w  $24(a2),d0      ; tmap
ROM:00012A92 906B 0024                           sub.w   $24(a3),d0
ROM:00012A96 6700 009A                           beq.w   _clrpwrplay     ; teams have same # of players on ice
ROM:00012A9A 6A00 001A                           bpl.w   _t0
ROM:00012A9E 0838 0006 C2EE                      btst    #6,(sflags2).w  ; #sf2pwrtm - 0 for team 1, 1 for team 2
ROM:00012AA4 6600 0026                           bne.w   _upp
ROM:00012AA8 6100 0088                           bsr.w   _clrpwrplay
ROM:00012AAC 08F8 0006 C2EE                      bset    #6,(sflags2).w
ROM:00012AB2 6000 0018                           bra.w   _upp
ROM:00012AB6                     ; ---------------------------------------------------------------------------
ROM:00012AB6
ROM:00012AB6                     _t0:                                    ; CODE XREF: updatepwrplay+1E↑j
ROM:00012AB6 C54B                                exg     a2,a3
ROM:00012AB8 0838 0006 C2EE                      btst    #6,(sflags2).w
ROM:00012ABE 6700 000C                           beq.w   _upp
ROM:00012AC2 6100 006E                           bsr.w   _clrpwrplay
ROM:00012AC6 08B8 0006 C2EE                      bclr    #6,(sflags2).w
ROM:00012ACC
ROM:00012ACC                     _upp:                                   ; CODE XREF: updatepwrplay+28↑j
ROM:00012ACC                                                             ; updatepwrplay+36↑j ...
ROM:00012ACC 08F8 0005 C2EE                      bset    #5,(sflags2).w  ; #sf2pwrplay - turn on PP
ROM:00012AD2 6600 0014                           bne.w   _uppt
ROM:00012AD6 526B 0004                           addq.w  #1,4(a3)        ; tmpwrplays
ROM:00012ADA B6FC C6CE                           cmpa.w  #$C6CE,a3       ; check if a3 is home team
ROM:00012ADE 6600 0006                           bne.w   _away
ROM:00012AE2
ROM:00012AE2                     _home:                                  ; CODE XREF: updatepwrplay:_away↓j
ROM:00012AE2 6000 0004                           bra.w   _uppt
ROM:00012AE6                     ; ---------------------------------------------------------------------------
ROM:00012AE6
ROM:00012AE6                     _away:                                  ; CODE XREF: updatepwrplay+62↑j
ROM:00012AE6 60FA                                bra.s   _home
ROM:00012AE8                     ; ---------------------------------------------------------------------------
ROM:00012AE8
ROM:00012AE8                     _uppt:                                  ; CODE XREF: updatepwrplay+56↑j
ROM:00012AE8                                                             ; updatepwrplay:_home↑j
ROM:00012AE8 6100 F0A8                           bsr.w   printz
ROM:00012AE8                     ; ---------------------------------------------------------------------------
ROM:00012AEC 0000                                dc.b 0
ROM:00012AED 0012                                dc.b $12
ROM:00012AEE 00BF                                dc.b $BF
ROM:00012AEF 0001                                dc.b   1
ROM:00012AF0 0019                                dc.b $19
ROM:00012AF1 0020                                dc.b $20
ROM:00012AF2 0020                                dc.b $20
ROM:00012AF3 0020                                dc.b $20
ROM:00012AF4 0016                                dc.b $16
ROM:00012AF5 0017                                dc.b $17
ROM:00012AF6 0018                                dc.b $18
ROM:00012AF7 0019                                dc.b $19
ROM:00012AF8 00BF                                dc.b $BF
ROM:00012AF9 0001                                dc.b   1
ROM:00012AFA 001A                                dc.b $1A
ROM:00012AFB 0020                                dc.b $20
ROM:00012AFC 0020                                dc.b $20
ROM:00012AFD 0000                                dc.b   0
ROM:00012AFE                     ; ---------------------------------------------------------------------------
ROM:00012AFE 6100 FF2E                           bsr.w   sub_12A2E

Which does what you put into the $12A2E routine. The data after printz is a string so you can ignore that. So maybe there is something strange going on there?

Posted

I can tell you the value in A2 when it crashed was $30A. When I changed the PowerPlay clock display and Line Changes to no longer load $30A, the problem went way. I can't tell you why any of this happens, only what I've observed from tests and interventions. It happens most often when a) two players on the same team receive a penalty at the same time or b) two players exit the penalty box at the same time.

 

  • Thanks 2
Posted

$30A, is that the base of the team pointers array in the ROM? It's a vaguely familiar value...

I wonder if there's an asynchronous function that has a bug and doesn't restore the values of A2 & A3, and due to timing differences with Gens's Starscream CPU emulator it happens at the bad time on an accurate emulator but is OK in Gens..

Posted (edited)

I agree. I can't recall what $30A is used for, but definitely we've seen that value before. 

Edited by AdamCatalyst
Posted
7 hours ago, smozoma said:

$30A, is that the base of the team pointers array in the ROM? It's a vaguely familiar value...

I wonder if there's an asynchronous function that has a bug and doesn't restore the values of A2 & A3, and due to timing differences with Gens's Starscream CPU emulator it happens at the bad time on an accurate emulator but is OK in Gens..

I think that's $30E. Maybe it is different in the 32 team ROMs?

I looked, I don't know what it's trying to do with $30A. Right before it enters the routine where it's crashing, it is setting A2 and A3 to the start of the team structs.

EDIT: Looks like A2 is set to $30A in 12 spots, and in all cases, few instructions after, there's a call to doBitMap.

EDIT2: OK, when looking at the 92 source code, there are instances before doBitMap called, a2 is set to #null.

null is a long variable set to 0. At $30A, it is a long word of 0. 

  • Thanks 1
Posted
19 hours ago, chaos said:

I think that's $30E. Maybe it is different in the 32 team ROMs?

I looked, I don't know what it's trying to do with $30A. Right before it enters the routine where it's crashing, it is setting A2 and A3 to the start of the team structs.

EDIT: Looks like A2 is set to $30A in 12 spots, and in all cases, few instructions after, there's a call to doBitMap.

EDIT2: OK, when looking at the 92 source code, there are instances before doBitMap called, a2 is set to #null.

null is a long variable set to 0. At $30A, it is a long word of 0. 

null pointer exception! how very "C" programming language.

  • Haha 1

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...