AdamCatalyst Posted June 15 Report Posted June 15 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. For folks that use Gens. Do you know of any any settings that I might be missing, that improves it's accuracy? For folks that recommend Gens, have you compared it against Exodus? Would you still recommend Gens? 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. For folks who DON’T recommend Gens, what emulator do you recommend for debugging & hacking? For everyone: do you know of a Mac native build of Exodus? For everyone: do you know of a build of Genesis Plus GX with debugging / hacking tools? Any and all advice appreciated! cheers, -a 1 Quote
smozoma Posted June 16 Report Posted June 16 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? Quote
AdamCatalyst Posted June 16 Author Report Posted June 16 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. Quote
smozoma Posted June 16 Report Posted June 16 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. 1 Quote
AdamCatalyst Posted June 16 Author Report Posted June 16 (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 June 16 by AdamCatalyst 1 Quote
kingraph Posted June 16 Report Posted June 16 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. I 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. 1 Quote
AdamCatalyst Posted June 16 Author Report Posted June 16 IDA Pro looks awesome, and Chaos tried to hook me up, but alas it was beyond my skill level and comprehension at this point. 1 Quote
chaos Posted June 16 Report Posted June 16 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. 1 Quote
smozoma Posted June 16 Report Posted June 16 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)? Quote
chaos Posted June 16 Report Posted June 16 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. Quote
AdamCatalyst Posted June 16 Author Report Posted June 16 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. Quote
chaos Posted June 16 Report Posted June 16 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 1 Quote
smozoma Posted June 17 Report Posted June 17 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? Quote
smozoma Posted June 17 Report Posted June 17 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? Quote
AdamCatalyst Posted June 17 Author Report Posted June 17 (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 June 17 by AdamCatalyst Quote
chaos Posted June 17 Report Posted June 17 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? Quote
AdamCatalyst Posted June 17 Author Report Posted June 17 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. 2 Quote
smozoma Posted June 18 Report Posted June 18 $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.. Quote
AdamCatalyst Posted June 18 Author Report Posted June 18 (edited) I agree. I can't recall what $30A is used for, but definitely we've seen that value before. Edited June 18 by AdamCatalyst Quote
chaos Posted June 18 Report Posted June 18 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. 1 Quote
smozoma Posted June 19 Report Posted June 19 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. 1 Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.