Autosplitter for SNES and Apple II

Check here for questions about obtaining the fastest possible times.
Post Reply
User avatar
Shauing
Calif
Calif
Posts: 431
Joined: April 5th, 2018, 10:38 pm
Contact:

Autosplitter for SNES and Apple II

Post by Shauing »

David, is it known the offsets for each of the 20-21 levels of this game? On the speedrun discord, we want to have an autosplitter for this version and the Apple II as well, and we're adapting the splitter from the DOS version, but the offsets of the levels on the DOS version are different from the Apple II and SNES and we don't know them.
NEW UPDATE! Prince Of Persia: 30th Anniversary Port v1.1.5. Download it today!: viewtopic.php?p=29053#p29053
NEW UPDATE! Prince Of Persia: The Queen Of Light v2.6. Download it today! viewtopic.php?p=33174#p33174
David
The Prince of Persia
The Prince of Persia
Posts: 2846
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Disassembly of PoP1 SNES

Post by David »

Shauing wrote: August 14th, 2021, 9:20 am David, is it known the offsets for each of the 20-21 levels of this game?
On the speedrun discord, we want to have an autosplitter for this version and the Apple II as well, and we're adapting the splitter from the DOS version,
but the offsets of the levels on the DOS version are different from the Apple II and SNES and we don't know them.
Do you mean the memory location in RAM where the number of the current level is stored?

In SNES PoP that is 7E:0579. -- The number stored here is one less than the displayed level number.
7E is the bank number and I guess that within an emulated RAM the offset will be simply 0x0579.

In Apple II PoP it's 0x03F4.

(I think the authors of splitters already know the following, but I mention it for the sake of completeness.)
Both addresses refer to the address on real hardware, or within the emulated RAM.
To find the address in an emulator you need to add the base address (where the emulated RAM starts) which depends on the emulator and its version.
User avatar
Shauing
Calif
Calif
Posts: 431
Joined: April 5th, 2018, 10:38 pm
Contact:

Re: Disassembly of PoP1 SNES

Post by Shauing »

David wrote: August 14th, 2021, 7:04 pm Do you mean the memory location in RAM where the number of the current level is stored?

In SNES PoP that is 7E:0579. -- The number stored here is one less than the displayed level number.
7E is the bank number and I guess that within an emulated RAM the offset will be simply 0x0579.

In Apple II PoP it's 0x03F4.

(I think the authors of splitters already know the following, but I mention it for the sake of completeness.)
Both addresses refer to the address on real hardware, or within the emulated RAM.
To find the address in an emulator you need to add the base address (where the emulated RAM starts) which depends on the emulator and its version.
I see, I'll figure out the address for the SNES9X 1.60 one.
There's a few other offsets that might be needed, if we're adapting it from the DOS version. Some additions or removals might have to be done to the SNES one. Here's the Autosplitter for the DOS PoP 1.4 (under the state 'DOSBOX' section, there's several addresses/bytes that are used for this autosplitter):
https://raw.githubusercontent.com/Winte ... sia1.4.asl
NEW UPDATE! Prince Of Persia: 30th Anniversary Port v1.1.5. Download it today!: viewtopic.php?p=29053#p29053
NEW UPDATE! Prince Of Persia: The Queen Of Light v2.6. Download it today! viewtopic.php?p=33174#p33174
David
The Prince of Persia
The Prince of Persia
Posts: 2846
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Disassembly of PoP1 SNES

Post by David »

Shauing wrote: August 15th, 2021, 7:08 am There's a few other offsets that might be needed, if we're adapting it from the DOS version.
Some additions or removals might have to be done to the SNES one.
Here's the Autosplitter for the DOS PoP 1.4 (under the state 'DOSBOX' section, there's several addresses/bytes that are used for this autosplitter):
To see what variable does each offset access, I converted the number in the .asl file to the offset within the data segment (DOS PoP 1.4 disassembly), by subtracting 0x19410.
Then I tried to find a variable with the same purpose in the other two versions.

Code: Select all

    byte Level          : "DOSBox.exe", 0x193C370, 0x1D0F4;          // shows level 1-14 changes as door is entered
DOS: data:3CE4 = next_level
SNES: 7E:0544 (byte) = next level
Apple II: 031C (byte) = NextLevel

Code: Select all

    byte Scene          : "DOSBox.exe", 0x193C370, 0x1A4BA;          // shows level 1-14 changes as scenes end
DOS: data:10AA = current_level
SNES: 7E:0579 (byte) = current level
Apple II: 03F4 (byte) = level

Code: Select all

    byte EndGame        : "DOSBox.exe", 0x193C370, 0x1D74A;          // 0 before endgame, 255 at endgame cutscene
DOS: data:433A = hourglass_sandflow
This is also set to 255 when the intro cutscene starts. Then it's set to 0 when the hourglass appears.
If the player interrupts the intro between the two then it remains 255 until a cutscene is shown.
This means that this variable is not a perfect indicator of whether the game ended.

Instead you could use disable_keys = data:5850 = 0x1EC60.

SNES: 7E:0629 (byte) = hourglass present -- 2 if the hourglass is present, otherwise 0.
This has a similar problem: If you interrupt the intro before the hourglass appears then it stays 0 until the next cutscene.

7E:0A84 (byte) = current cutscene -- This becomes 06 for the bad ending and 07 for the good ending.
It stays so even after the cutscene ends.

Apple II: E14A (byte) = psandcount -- Works like in the DOS version, with the same problems.
There is no equivalent of disable_keys because this version does not disable keys during the ending scene.
(The animation skips if you press a key then.)

Code: Select all

    byte Start          : "DOSBox.exe", 0x193C370, 0x1D694;          // the level you start the game at
DOS: data:4284 = start_level

SNES: 7E:0E5D (byte) = decoded level -- This is the level number decoded from an entered password.
It stays 00 if you start the training so it's not exactly the same as the DOS variable.

Apple II: There is B6F0 = SavLevel, but it's updated when loading or saving a game.

Code: Select all

    byte GameRunning    : "DOSBox.exe", 0x19175EA;                   // 0 if game isn't running
DOS: This offset is not within the emulated RAM, it's some variable of DOSBox itself.

Is this supposed to check if the player has quit PoP?

Code: Select all

    byte MinutesLeft    : "DOSBox.exe", 0x193C370, 0x1E350;          // Minutes
    int  Count          : "DOSBox.exe", 0x193C370, 0x1E354;          // Frames
    short FrameSeconds  : "DOSBox.exe", 0x193C370, 0x1E356;          // Frames in second part of time (720-0)
DOS:
* data:4F40 = rem_min
* data:4F44 = pickup_obj_type -- "Count" accesses two 16-bit integers, pickup_obj_type *and* the following rem_tick, as a single 32-bit integer!
* data:4F46 = rem_tick

SNES: 7E:052D (ushort) = FrameCount -- This is the number of elapsed ticks.
1 minute = 0x1A9 (425) ticks, 1 second = 7 ticks.

Apple II: 0306 (ushort) = FrameCount -- This is the number of elapsed ticks.
1 minute = 725 ticks, 1 second = 12 ticks.

Code: Select all

    byte Sound          : "DOSBox.exe", 0x193C370, 0x2F233;          // 0 if sound is on, 1 if sound is off
DOS: 0x2F233 is somewhere in the Sound Blaster Pro driver, not in the main data segment.
SNES: Sound cannot be turned off in this version.
Apple II: 031A (byte) = musicon, 0203 (byte) = soundon

Code: Select all

    byte Room           : "DOSBox.exe", 0x193C370, 0x1D107;          // shows current room ID
DOS: data:3CF7 = Char.room -- This is the room where the prince is. It's not necessarily the room currently shown if H/J/U/N has been used, but speedrunners don't use cheats.
SNES: 7E:0462 (byte) = CharScrn
Apple II: 004B (byte) = CharScrn

Code: Select all

    byte IsRestartLevel : "DOSBox.exe", 0x193C370, 0x1E16A;          // the is_restart_level (Ctrl+A) flag
DOS: data:4D5A = different_room -- This is set to 1 every time the prince enters a different room!
is_restart_level would be data:429C = 0x1D6AC

SNES: You can't restart the level in this version.

Apple II: 00A3 (byte) = cutplan (the equivalent of different_room)

Code: Select all

    byte LevelTextTime  : "DOSBox.exe", 0x193C370, 0x1F35E;          // frames left for showing the "Level N" text
DOS: data:5F4E = text_time_remaining -- This is for all status bar messages, not just the level number.
SNES: 7E:0518 (byte) = msgtimer
Apple II: 00DB (byte) = msgtimer

Code: Select all

    byte Level3CP       : "DOSBox.exe", 0x193C370, 0x1E050;          // Level 3 checkpoint flag (changes from 0-1)
DOS: data:4C40 = checkpoint
SNES: 7E:0627 (byte) = checkpoint on/off -- Here it's not limited to level 3, of course.
Apple II: 0212 (byte) = milestone

Code: Select all

    int RestartFlag0    : "DOSBox.exe", 0x193C370, 0x1D0E2;           // eien86's flag for restart detection
    int RestartFlag1    : "DOSBox.exe", 0x193C370, 0x1D0E6;           // eien86's flag for restart detection
    short RestartFlag2  : "DOSBox.exe", 0x193C370, 0x1D0EA;           // eien86's flag for restart detection
DOS: These variables cover one of the arrays used for collision detection.
data:3CD2 = below_row_coll_room[0]
data:3CD6 = below_row_coll_room[4]
data:3CDA = below_row_coll_room[8]

SNES:
7E:0605 (int) = SNbelow
7E:0609 (int) = SNbelow+4
7E:060D (short) = SNbelow+8

Apple II:
0380 (int) = SNbelow
0384 (int) = SNbelow+4
0388 (short) = SNbelow+8
David
The Prince of Persia
The Prince of Persia
Posts: 2846
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Autosplitter for SNES and Apple II

Post by David »

I moved the posts about the autosplitter from the SNES Disassembly thread to this new thread.
User avatar
Shauing
Calif
Calif
Posts: 431
Joined: April 5th, 2018, 10:38 pm
Contact:

Re: Autosplitter for SNES and Apple II

Post by Shauing »

Getting back to you with this but for the Apple II one, Mattcubing (who is trying to make the autosplitter for the Apple II), said that although he found the variables for the Apple II, it seems that they're different from computer to computer even if all of them were using the same emulator. Is there any solution for this?
NEW UPDATE! Prince Of Persia: 30th Anniversary Port v1.1.5. Download it today!: viewtopic.php?p=29053#p29053
NEW UPDATE! Prince Of Persia: The Queen Of Light v2.6. Download it today! viewtopic.php?p=33174#p33174
David
The Prince of Persia
The Prince of Persia
Posts: 2846
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Autosplitter for SNES and Apple II

Post by David »

Shauing wrote: August 21st, 2021, 6:25 am Getting back to you with this but for the Apple II one, Mattcubing (who is trying to make the autosplitter for the Apple II), said that although he found the variables for the Apple II, it seems that they're different from computer to computer even if all of them were using the same emulator.
Is there any solution for this?
What happens:

The array which holds the emulated RAM is allocated dynamically, and it ends up at a different address every time the emulator is started (even on the same computer).
We need to find where does the emulator store the address of that array.

How to solve it:

Here is how to find the correct address in Cheat Engine.
(I used Cheat Engine because it's recommended in the docs of LiveSplit.)

After you added the variable to the list of cheats, click on it with the right mouse button, then choose "Pointer scan for this address".
In the window that opens, you can lower the Max level. You can go down to 1, at least if the emulator is AppleWin.
But the default 7 will probably find too many results in any case.
You can also enable this option to lessen the number of results: Show advanced options -> Stop traversing a path when a static has been found.

After you press OK, Cheat Engine will want to save a file. I'm not sure what is it good for. Anyway, save it somewhere.

There will be multiple results.
To find out which is the "real" one, consider only the results with the fewest offsets (i.e. the fewest levels of indirection).
(If every result has only one offset then consider all of them.)

Add them to the cheats list, then on each of them, right click -> Find out what accesses this address -> Find out what accesses this pointer.
If there are some results then it's the pointer used by the emulator, keep it.
If the result is empty then it's a wrong one, delete it.

After you found out the correct pointer for the first variable:
Double-click its Address and copy out the base address from the bottom textbox.
You can later pick the same base in the Pointer scan results window for the other variables.

With AppleWin 1.26.2.1 (32-bit), the "real" base address is "AppleWin.exe"+0023B8EC.

How to convert the addresses into the format expected by LiveSplit:

In the list of cheats, double-click the Address of the variable.
Copy the contents of the text boxes under the Pointer checkbox, from bottom to top.

For example the current level variable has these addresses for me:
• "AppleWin.exe"+0023B8EC
• 3F4

Then combine them like this:

Code: Select all

byte CurrLevel : "AppleWin.exe", 0x0023B8EC, 0x03F4;
(The last number matches the offset I wrote in my previous post.)


I hope this helps.
User avatar
Shauing
Calif
Calif
Posts: 431
Joined: April 5th, 2018, 10:38 pm
Contact:

Re: Autosplitter for SNES and Apple II

Post by Shauing »

Will this also work to find the base address for the SNES emulator I'm writing the autosplitter (in this case snes9x-1.60-win32-x64)?
I'm having a hard time finding the base address for it.
EDIT: I tried to get the base address, but it seems that every time the emulator is reopened, it changes. I've had as base addresses in the times I tested this: 022ABFD0, 03CCAFD0, 03E4AFD0 and 03E0AFD0.
NEW UPDATE! Prince Of Persia: 30th Anniversary Port v1.1.5. Download it today!: viewtopic.php?p=29053#p29053
NEW UPDATE! Prince Of Persia: The Queen Of Light v2.6. Download it today! viewtopic.php?p=33174#p33174
David
The Prince of Persia
The Prince of Persia
Posts: 2846
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Autosplitter for SNES and Apple II

Post by David »

Shauing wrote: August 21st, 2021, 10:14 pm Will this also work to find the base address for the SNES emulator I'm writing the autosplitter (in this case snes9x-1.60-win32-x64)?
I'm having a hard time finding the base address for it.
EDIT: I tried to get the base address, but it seems that every time the emulator is reopened, it changes. I've had as base addresses in the times I tested this: 022ABFD0, 03CCAFD0, 03E4AFD0 and 03E0AFD0.
I think you're looking at the wrong number.

Look at the screenshot below.
What we need is the "snes9x-x64.exe"+008D8C38, not the 041CAFD0.
snes_address.png
snes_address.png (9.92 KiB) Viewed 6441 times
User avatar
Shauing
Calif
Calif
Posts: 431
Joined: April 5th, 2018, 10:38 pm
Contact:

Re: Autosplitter for SNES and Apple II

Post by Shauing »

David wrote: August 22nd, 2021, 8:52 pm
I think you're looking at the wrong number.

Look at the screenshot below.
What we need is the "snes9x-x64.exe"+008D8C38, not the 041CAFD0.
So it's always going to be "snes9x-x64.exe"+008D8C38, only the pointer changes depending of what are we looking for.
There still some stuff later that I have to change/delete as well it seems, seeing that there's no level skip/individual level stuff. For example there's a calculation that goes something like 60*720 ; I assume it has to do with the 60 seconds multiplied for the frames that elapse on DOS - in this case - 12?
NEW UPDATE! Prince Of Persia: 30th Anniversary Port v1.1.5. Download it today!: viewtopic.php?p=29053#p29053
NEW UPDATE! Prince Of Persia: The Queen Of Light v2.6. Download it today! viewtopic.php?p=33174#p33174
David
The Prince of Persia
The Prince of Persia
Posts: 2846
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Autosplitter for SNES and Apple II

Post by David »

Shauing wrote: August 29th, 2021, 9:50 am So it's always going to be "snes9x-x64.exe"+008D8C38, only the pointer changes depending of what are we looking for.
Yes.
Shauing wrote: August 29th, 2021, 9:50 am For example there's a calculation that goes something like 60*720 ; I assume it has to do with the 60 seconds multiplied for the frames that elapse on DOS - in this case - 12?
Yes, it's 60 minutes * 60 seconds/minute * 12 frames/second.

It's always used like this:

Code: Select all

    vars.levelRestartTimestamp = 60*720;
The levelRestartTimestamp variable stores timestamp (remaining frames) when the current level was last restarted.
It's reset to 60*720 when the game is restarted, i.e. when the timer resets to 60 minutes left.

Don't forget that while DOS PoP stores the remaining time, SNES PoP and Apple II PoP store the elapsed time.
Which means that in the latter versions, 60*720 should be replaced with 0.
That is, unless you want to calculate with the remaining time in these versions as well.

The minutesLeft, totalFramesLeft, and adjustedFramesLeft variables have to be calculated differently as well, since the time is not split into minutes and frames in these versions.
User avatar
Shauing
Calif
Calif
Posts: 431
Joined: April 5th, 2018, 10:38 pm
Contact:

Re: Autosplitter for SNES and Apple II

Post by Shauing »

David, do you have a disassembly for the Apple II? I know there's the source code, but things aren't labeled over there. It could be useful to fine-tune the Apple II autosplitter.
Also, do you know what the C11E-C3EE section in memory does? For what the guys at discord tell me, that section could be useful for the autosplitter.
NEW UPDATE! Prince Of Persia: 30th Anniversary Port v1.1.5. Download it today!: viewtopic.php?p=29053#p29053
NEW UPDATE! Prince Of Persia: The Queen Of Light v2.6. Download it today! viewtopic.php?p=33174#p33174
David
The Prince of Persia
The Prince of Persia
Posts: 2846
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Autosplitter for SNES and Apple II

Post by David »

Shauing wrote: November 10th, 2021, 4:51 am David, do you have a disassembly for the Apple II? I know there's the source code, but things aren't labeled over there. It could be useful to fine-tune the Apple II autosplitter.
The author of the C64 port of PoP made one: http://popc64.blogspot.com/2012/03/part ... -push.html

Alternatively, there is a copy of the source together with build tools here: https://github.com/adamgreen/Prince-of- ... uick-start
The build process creates an obj/ folder, and within that, *.LST files will contain the source lines together with their offsets and byte values.

Shauing wrote: November 10th, 2021, 4:51 am Also, do you know what the C11E-C3EE section in memory does? For what the guys at discord tell me, that section could be useful for the autosplitter.
On the Apple II, the CPU sees I/O and ROM at the C000-CFFF range.
Emulators probably use the C000-CFFF range of their RAM buffer for one of the RAM banks which can be paged into D000-DFFF (where the CPU sees it).

The part in the spoiler is probably irrelevant, but I noticed that only after I wrote it...
Spoiler: show
The source code lists the following things in that area:

Code: Select all

*  Main l.c.
rw18 = $d000
peelbuf1 = $d000
*  Aux l.c.
bluecopy = $d000 ;bank 1
I made a savestate from AppleWin, and from the main memory's C000 address there are the following bytes: 4C 04 D1 00 A9 01 2C A9 02 8D CB D0 A5 FE 0A 0A
This seems to match 02 POP Disk Routines/RW1835/RW1835.POP.S from the source code:
(I am quoting from obj/rw1835.pop.LST made by the build process above.)

Code: Select all

D000: 4C 04 D1    36  jmp RW18
D003: 00          38 GS? ds 1 ;bpl if not, bmi if GS
D004: A9 01       47 READ lda #1
D006: 2C          48  hex 2C
D007: A9 02       49 WRITE lda #2
D009: 8D CB D0    50  sta SPcommand
Curiously, the disassembly I linked above has something completely different at this address in its bank1_0000.bin .

C285-C384 is ZPAGEBUF, i.e. a copy of 0000-00FF.
C385-C396 is BUFTABLE.
HOWEVER, I also did a test with Cheat Engine, it seems that Apple II keeps Auxiliary Memory at base+C000, if we use the same base as for the level number variables for example.
base+C000 contains these bytes: FE 02 20 48 5A 96 DA 1E 60 78 D6 00 24 3E 76 9A
These are from MUSIC.SET2 (from the build repo I linked above).
The contents of that file end at base+C3F0.

This means the C11E-C3EE area contains only music data.
The only way it could be useful for autosplitting is if loading a different music set can signal something.
Post Reply