• Welcome to Final Fantasy Hacktics. Please login or sign up.
 
March 28, 2024, 08:44:54 pm

News:

Use of ePSXe before 2.0 is highly discouraged. Mednafen, RetroArch, and Duckstation are recommended for playing/testing, pSX is recommended for debugging.


Assembly hacking for lazy people

Started by nitwit, July 18, 2014, 01:24:11 am

nitwit

July 18, 2014, 01:24:11 am Last Edit: July 18, 2014, 01:47:34 am by nitwit
http://ffhacktics.com/wiki/36_%2BPA_%28Y%29
http://ffhacktics.com/wiki/3A_%2BBrave_%28Y%29
http://ffhacktics.com/wiki/39_%2BSP_%28Y%29

I noticed that all three of these formulas are identical except for 1 line.  Even though I don't understand everything that's going on, the comments and them all being copies of one another means that this is the format I can use to make a formula that increments a stat by 1.  Using this information, I can copy and paste this into another formula, change the stat being incremented, and then zero out what's left of the formula.  That's if I have more room in the formula I'm replacing.

If I don't have room in the formula I want to replace, then I jump to free space using a jal, paste the increment-stat formula there, change the stat being incremented, and then (correct me on this if I'm wrong) jal back to where I left off and zero out what's left?

http://ffhacktics.com/wiki/59_%E2%80%93Lvl%281%29_Hit_%28MA%2BX%29%25
This formula is only used for powergamers.  If my guess is correct, I can turn this into a +MA hack and have room to spare.

Does this make sense to anyone?

Glain

July 18, 2014, 03:34:37 pm #1 Last Edit: July 18, 2014, 07:33:24 pm by Glain
Firstly, I like that thought process a lot.  You don't necessarily have to understand everything to make the changes you want.  You also got the process at a high level pretty spot on.

If you have enough space in the formula you're overwriting, you can probably just replace that without needing free space.  But, if you do decide to use free space, there are some things about j and jal to note.


Jumps/branches won't take effect until the statement after the jump is executed (branch delay).
jal (jump and link) is basically the routine call statement, and will set the return value register (r31) to be 2 statements beyond the jal statement itself, which is where the code would resume after the call.  (j doesn't, but they're otherwise the same). The routine calling code might be something like:


jal routine_address
nop (executed before the jump. often times this will be a nop, but you can put something else here)
(code to be executed after routine call)


Then the routine can just jump back to the return address register automatically filled in by the jal statement.  (jr jumps to the memory address given by the value of a register):


(code doing work in the routine)
jr r31
nop (same deal with branch delay)



Edit - Oh, and you don't actually have to zero out the rest of the routine you're overwriting, since you should have a return (jr r31) with appropriate delay slot at the end of your routine, so anything past that just won't execute.
  • Modding version: Other/Unknown

nitwit

July 18, 2014, 09:14:54 pm #2 Last Edit: July 18, 2014, 11:44:42 pm by nitwit
Quote
Edit - Oh, and you don't actually have to zero out the rest of the routine you're overwriting, since you should have a return (jr r31) with appropriate delay slot at the end of your routine, so anything past that just won't execute.

How would I adjust pointers to the formulas so I can move stuff back and make room in routines I need to expand?  Or should I just stick with jal to free space and paste the portion I deleted for the jal there along with whatever stuff I added?

Which is less work?

Quote from: Glain on July 18, 2014, 03:34:37 pmJumps/branches won't take effect until the statement after the jump is executed (branch delay).
jal (jump and link) is basically the routine call statement, and will set the return value register (r31) to be 2 statements beyond the jal statement itself, which is where the code would resume after the call.  (j doesn't, but they're otherwise the same). The routine calling code might be something like:


jal routine_address
nop (executed before the jump. often times this will be a nop, but you can put something else here)
(code to be executed after routine call)


Then the routine can just jump back to the return address register automatically filled in by the jal statement.  (jr jumps to the memory address given by the value of a register):


(code doing work in the routine)
jr r31
nop (same deal with branch delay)

I get it!  I assume that with a jal, it will return from the linked statement once it hits a nop, so I don't have to jump back when I'm done in free space.  I just need a single nop!

j is when I want to skip something, I assume it's used for conditional statements.

What would jr be used for?  How large of a memory address can be stored in a register?  32 bits?

I assume that jr jumps that address, starts executing code there, and doesn't jump back to where it came from if it hits a nop?

http://ffhacktics.com/wiki/Equipment_Attribute_Setting
http://ffhacktics.com/wiki/Item_Attribute
These are the only two articles in the wiki that contain the word "attribute".  ALMA must be where I can find more about them.

Glain

You could do either one (Have a formula point to free space or jump to free space from the formula code).  I've always done the latter but the former may be simpler, really.

You do manually jump back from routines (that's what jr r31 does).  nop ("no operation") has no effect, and certainly doesn't jump back anywhere!
j is an unconditional jump.  It just jumps to whatever address is specified.  There are other conditional branch statements.
jr is used for returning from a routine (jr r31) or really long jumps.  Yes, registers are 32 bits wide.
Nothing jumps back after hitting a nop, so neither does jr (jr is the command generally used to do a jump back, though).

For more information on the assembly commands, go here and look for "MIPS assembly language" and the table that follows.
  • Modding version: Other/Unknown

nitwit

July 19, 2014, 02:42:28 am #4 Last Edit: September 03, 2014, 10:25:10 pm by nitwit
This sums up jal nicely.
QuoteFor procedure call - used to call a subroutine, $31 holds the return address; returning from a subroutine is done by: jr $31. Return address is PC + 8, not PC + 4 due to the use of a branch delay slot which forces the instruction after the jump to be executed

PC stands for program counter.

http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/Mips/jump.html

This doesn't seem that hard once you understand the vocabulary.

jr can go to any address from 00000000h to FFFFFFFFh, but how do you load something 32 bits wide into a register?  There isn't anything left for an opcode.

Are registers all the same width in bits?

Glain

Yep, the program counter (PC) is the address of the instruction being executed.

If you want to load a 32-bit immediate into a register, you'll have to use two commands, since as you say, there's not enough room for the opcode and the immediate in one command.  One way this is done is to use lui and ori.
Example: if I wanted to load 0xbaadf00d into r4:

lui r4, 0xbaad
ori r4, r4, 0xf00d

Some assemblers (including MassHexASM's encoding) recognize a pseudoinstruction called li that will take a 32-bit immediate, and automatically split into lui/ori behind the scenes, thus you could just use li r4, 0xbaadf00d.

The registers for the PSX CPU are all 32 bits wide, yes.

  • Modding version: Other/Unknown

Xifanie

http://cgi.cse.unsw.edu.au/~cs3231/doc/R3000.pdf
Dropping this here because why not. It's what I used to make my MIPS analyzer which detects faulty, console-breaking coding.

jr being jump return, you don't really want to use that...
You're more thinking of jalr, where you can use "jalr r2, r31" to jump to r2, and store the return address in r31 to use with jr.
  • Modding version: PSX
Love what you're seeing? https://supportus.ffhacktics.com/ 💜 it's really appreciated

Anything is possible as long as it is within the hardware's limits. (ie. disc space, RAM, Video RAM, processor, etc.)
<R999> My target market is not FFT mod players
<Raijinili> remember that? it was awful

Choto

nitwit, The undocumented routines on the wiki are ones that I have but never uploaded. If you look in the ASM Starter Kit thread in important links, one of the files in there is "battle bin routines 2", which have most of those red routines that are up on the wiki.

Once you get past knowing what the commands do, and you get used to where information is stored in memory (data locations.txt), asm hacking gets SO much easier. That's when you really feel comfortable and confident making the changes that you want to make.

Also I'm not sure what spreadsheet hacks are not compatible other than ALMA - RAD. Aside from the ARH, all the other spreadsheets are pretty simple so they should be easy to move if needed.

nitwit

I'll check out that thread next.  There are still a few things I think I should now.

How do you use a debugger?  What is the vocabulary of a debugger (the names of different things in and associated with it and it's usage)?

How does the PS1 load files into RAM?  How does FFT load files into ram?

This last one a hypothetical.  I noticed that there is an attempt to rewrite many of the routines in FFT, to free space, remove hardcoding, and add new features.  I also noticed that ALMA has some scripting tools used only within the workbook itself, to select features to add to the game.

What would a general purpose rom hacking tool need?  What would it be?

A spreadsheet is a general purpose tool, which can be used for accounting, calculation, some database things.  Dedicated accounting software is an application specific tool, only useful for accounting.

In the same sense FFTPatcher is a application specific tool, used only for editing FFT.  If FFTPatcher is the romhacking equivalent of accounting software, then what is the rom hacking equivalent of a spreadsheet?

I ask this because it is brilliant what you did with spreadsheets, and the collection of tools in the FFTPatcher suite are all very clever.  But I wonder what you could do if you had a tool that combines a spreadsheet, a database manager, an assembler, a game editor, and scripting of some sort to make all these parts work together.  I really want to have a long discussion about this with people who know what they're doing, and I know that this will probably never happen but it's still fun to do it.

If this presumes too much, I could ask at other general purpose romhacking sites, but I don't think there are any others with the following that this one has.

Choto

Pokeytax describes how to use a debugger a bit in his ASM tutorial which can be foudn here:
http://ffhacktics.com/smf/index.php?topic=9204.0

Disassembly: This shows the ASM code in RAM. Hit ctrl-G to go to a certain address to read the code. If you manage to stop the code from running using a breakpoint, you can step through each command individually (in the debug menu).

Memory: This shows RAM just like disassembly, but only shows the raw hex values. It's better for reading things like tables of data or hex that isn't ASM encoding. You can also use ctrl-g to go to specific addresses.

Registers: This window shows you the current value in each of the 31 registers used by PSX. It also shows the PC and some other special registers. This will continually change while code is running.

Breakpoints: These are used to freeze the game at certain desirable locations or times. "Read/Write" breakpoints will freeze the game when the address you specify is used in a load or store command. This is good for seeing when a value is used by the code, or when it is changed by the code.

execute breakpoints will freeze the game when the command at the specified address is used. So if I want to look at what a routine does, I set an execute at the beginning of the routine. When the game calls this routine it will freeze and I will be able to step through each command individually to see what it's doing, or what values are in what registers.

------------------------------------------------------------------------------------------

The PS1 loads files using this routine:

Load File into RAM
*Note: Loads sections of 0x800 of the file at a time
00020650: 3c028003 lui r2,0x8003
00020654: 8c421b40 lw r2,0x1b40(r2)         load cdreg0
00020658: 3c060002 lui r6,0x0002
0002065c: a0400000 sb r0,0x0000(r2)         send command?
00020660: 3c038003 lui r3,0x8003
00020664: 8c631b4c lw r3,0x1b4c(r3)         load cdreg3
00020668: 34020080 ori r2,r0,0x0080
0002066c: a0620000 sb r2,0x0000(r3)         store ??
00020670: 3c028003 lui r2,0x8003
00020674: 8c421b74 lw r2,0x1b74(r2)         1f801018 - hardware register (?)
00020678: 34c60943 ori r6,r6,0x0943
0002067c: ac460000 sw r6,0x0000(r2)         store 20943 in register
00020680: 3c038003 lui r3,0x8003
00020684: 8c631b50 lw r3,0x1b50(r3)         1f801020 - hardware register
00020688: 34021323 ori r2,r0,0x1323
0002068c: ac620000 sw r2,0x0000(r3)         store 1323 in register
00020690: 3c038003 lui r3,0x8003
00020694: 8c631b78 lw r3,0x1b78(r3)
00020698: 00000000 nop
0002069c: 8c620000 lw r2,0x0000(r3)         load from hardware register
000206a0: 00000000 nop
000206a4: 34428000 ori r2,r2,0x8000         add flag
000206a8: ac620000 sw r2,0x0000(r3)         store new
000206ac: 3c028003 lui r2,0x8003
000206b0: 8c421b7c lw r2,0x1b7c(r2)         load address in RAM to load file
000206b4: 00000000 nop
000206b8: ac440000 sw r4,0x0000(r2)         store address in 1f8010b0 CD-rom DMA register
000206bc: 3c020001 lui r2,0x0001
000206c0: 3c038003 lui r3,0x8003
000206c4: 8c631b80 lw r3,0x1b80(r3)         load dma block control register
000206c8: 00a22825 or r5,r5,r2
000206cc: ac650000 sw r5,0x0000(r3)         store values + 0x00010000 in register
000206d0: 3c038003 lui r3,0x8003
000206d4: 8c631b40 lw r3,0x1b40(r3)         load CDreg0

000206d8: 00000000 nop
000206dc: 90620000 lbu r2,0x0000(r3)      load cdreg0
000206e0: 00000000 nop
000206e4: 30420040 andi r2,r2,0x0040
000206e8: 1040fffb beq r2,r0,0x000206d8      branch if not ?? (loop until complete?)
000206ec: 3c021100 lui r2,0x1100

000206f0: 3c038003 lui r3,0x8003
000206f4: 8c631b84 lw r3,0x1b84(r3)         load dma channel control register (cdrom)
000206f8: 00000000 nop
000206fc: ac620000 sw r2,0x0000(r3)         ** LOAD FILE MOTHAFUCKA!!!!*************************
00020700: 3c048003 lui r4,0x8003
00020704: 8c841b84 lw r4,0x1b84(r4)         load dma channel control register address
00020708: 00000000 nop
0002070c: 8c820000 lw r2,0x0000(r4)         load values of register
00020710: 3c030100 lui r3,0x0100
00020714: 00431024 and r2,r2,r3            check flag
00020718: 10400007 beq r2,r0,0x00020738      branch if complete
0002071c: 00801821 addu r3,r4,r0
00020720: 3c040100 lui r4,0x0100

00020724: 8c620000 lw r2,0x0000(r3)
00020728: 00000000 nop
0002072c: 00441024 and r2,r2,r4
00020730: 1440fffc bne r2,r0,0x00020724      loop until complete
00020734: 00000000 nop

00020738: 3c038003 lui r3,0x8003
0002073c: 8c631b50 lw r3,0x1b50(r3)         1f801020 - hardware register
00020740: 34021325 ori r2,r0,0x1325
00020744: ac620000 sw r2,0x0000(r3)         store new
00020748: 03e00008 jr r31
0002074c: 00001021 addu r2,r0,r0         return 0


I had been looking for how it does this for a long time so you can see how overjoyed I was to find it. It does this by using some hardware registers. These are addresses used for things like the GPU, SPU, and other hardware rather than the 31 registers used for regular code. The command at 206FC is when the data to be loaded actually appears in RAM at an address specified earlier. In order to do this correctly I think there is a process to follow but I haven't looked into it enough to figure it out. There is a document online called "thepsxdoc" or something like that that describes all of the hardware involved and addresses they use as registers.

--------------------------------------------------------------------------------------------
There isn't really an attempt to rewrite routines to save space. To be honest, there is pretty much plenty of space to use as long as you know how to move hacks around in free space. I haven't seen an instance where somebody has maxxed out that space (in fact i'm not sure there are enough hacks to do it in the first place). Some routines have been rewritten to provide better functionality (and in doing so one can usually save space because of redundancies in the code that FFT's compiler created).

So a general purpose rom hacking tool.... I'm not sure exactly what you mean. FFTPatcher is basically a giant hex editor. It modifies a whole ton of data that are in data tables. Pretty much everything in there is in some data table.

FFTorgASM can do this to, but it is more used to place large amounts of ASM code into the game.

Shishi modifies spritesheets and visual graphics data, something that the previous two programs can't do.

The point is that in order to have a general-purpose or all-purpose tool, you'd have to combine all of these programs into one. It wouldn't really be a big benefit from the amount of effort needed to do so. What you are describing would take a massive amount of work. If you want to talk about it from a hypothetical view, pop on #ffh (IRC chat) and if I'm on I can give what I know about it. But I don't know enough about databases and such to really give a thorough answer. Lirmont or Glain may be able to give you a better description.

Also the reason we use spreadsheets is that it allows you to use logic to create ASM code or modify data held in tables. It's really just a user-friendly version of manually writing out the hex values for the table so that people that aren't programmers can do it without having intimate knowledge of how it does it. It also makes the process easier and more convenient.

nitwit

July 20, 2014, 06:07:26 pm #10 Last Edit: July 20, 2014, 07:31:03 pm by nitwit
QuoteSo a general purpose rom hacking tool.... I'm not sure exactly what you mean. FFTPatcher is basically a giant hex editor. It modifies a whole ton of data that are in data tables. Pretty much everything in there is in some data table.

From what I understand, FFTPatcher only edits tables of fixed size.  It is a hex editor for tables of fixed size, with a user-friendly GUI, and a patch applier for edits to tables of fixed size.

FFTOrgasm is the assembler, and the patch applier for assembly hacks, hacks to custom tables, and hacks to data not supported by FFTPatcher.

FFTactext deals with text compression, rearranges files (?) and data within files, and edits tables of variable size related to text.  It previews the text, but not as it would appear in-game.

Shishi exports and previews images.

Spreadsheets generate patches for FFTOrgasm and can provide a gui for assembly hakcs, hacks to custom tables, and hacks to data not supported by FFTPatcher.

There aren't any database tools used for hacking FFT.

This is true?

QuoteIt wouldn't really be a big benefit from the amount of effort needed to do so. What you are describing would take a massive amount of work. If you want to talk about it from a hypothetical view, pop on #ffh (IRC chat) and if I'm on I can give what I know about it. But I don't know enough about databases and such to really give a thorough answer. Lirmont or Glain may be able to give you a better description.

I agree with that, and I'm not saying it should be done.  I'm just wondering how is the best way to do it for a game that doesn't have a set of tools already, and how the ways things are currently done could be better for the next game.

Sorry for all the edits.

Choto

July 21, 2014, 06:43:31 pm #11 Last Edit: July 21, 2014, 07:47:21 pm by Choto
I suppose what you have posted is accurate. None of the tools use a database aside from .xml lists and resource files.

Edit: Cept Tactext does edit how the text appears in game. It's THE text editor

In regards to the best way to do it... it's really a matter of opinion. However, I would argue that the natural tendency of things would be to make programs in parts as new knowledge is discovered about the game. For example if we found out all the FFTPatcher stuff but none of the shishi stuff, we would have developed FFTPatcher without any support for images. Of course a program could be developed with the intention of later additions (and indeed the way the programs are laid out accounts for this, albeit not all-inclusively in one program). Having everything in one program makes things more convenient in terms of open applications and windows, but it can also make things cluttered. I'm not really sure what the "best way" would be.

nitwit

July 21, 2014, 08:19:25 pm #12 Last Edit: July 21, 2014, 08:30:30 pm by nitwit
Quote from: Choto on July 21, 2014, 06:43:31 pm
I suppose what you have posted is accurate. None of the tools use a database aside from .xml lists and resource files.

Edit: Cept Tactext does edit how the text appears in game. It's THE text editor

I mean that Tactext doesn't have a way to preview the text.  You can't click something and then a dialog box pops up and you can scroll through it to see how it looks and fix your line breaks.

Quote from: Choto on July 21, 2014, 06:43:31 pmIn regards to the best way to do it... it's really a matter of opinion. However, I would argue that the natural tendency of things would be to make programs in parts as new knowledge is discovered about the game. For example if we found out all the FFTPatcher stuff but none of the shishi stuff, we would have developed FFTPatcher without any support for images. Of course a program could be developed with the intention of later additions (and indeed the way the programs are laid out accounts for this, albeit not all-inclusively in one program). Having everything in one program makes things more convenient in terms of open applications and windows, but it can also make things cluttered. I'm not really sure what the "best way" would be.

Neither am I.  Glain made a point earlier.

QuoteAlso the reason we use spreadsheets is that it allows you to use logic to create ASM code or modify data held in tables. It's really just a user-friendly version of manually writing out the hex values for the table so that people that aren't programmers can do it without having intimate knowledge of how it does it. It also makes the process easier and more convenient.

Spreadsheets are the best tools available, but they need tweaks to make them more user-friendly.  You can limit the type of input of input a cell accepts, but you must do it manually for every single cell.  You can set the defaults for a table to match those found in the game... manually for every cell.

You can make a pseudoGUI which works reasonably well.  And you can use logic to convert values in your spreadsheet into something that FFTOrgasm can use, but it's very tedious and time-consuming because using logic in spreadsheet cells is painful.

You can edit tables of variable size in a spreadsheet surprisingly well with count() functions to calculate the number of empty cells.

The most flexible (not the best) tool is a spreadsheet that has features a hacker needs, and which decouples logic from cells.  Features like using forms to create GUIs and regexes to validate input; importing and interpreting a hex table to determine default values for an entire range of forms in a spreadsheet (similar to how FFTPatcher uses XML to flag a value as changed if it varies from what's in the table it has stored); and a plugin system so people can design useful functions and addons as they need them.

I may be wrong about decoupling logic from cells.  It's a pain to copy and paste formulas in cells and to modify them for every single cell.  Cells also can't accept output; I can't tell a cell to do something from another cell (I can't tell A1 to write something to B1 if something's true and C1 if something's false, I must instead do my math in A1 and then do my predicates and print statements in B1 and C1).  Though I like the simplicity of spreadsheet logic.

A lot of other stuff normally found in spreadsheets can be tossed.  It doesn't need to be the next Libre Office, it just needs to be a minimalist spreadsheet, with markup for form creation, default data importing, and plugins.

This would be useful because it would make already productive people more productive (don't need to do it all manually).  It would also make it easier for less productive (lazy) end-users to make editing tools.  And it would provide a layer of dummy proofing for people who are used to a GUI (people who are already lazy to begin with).

I'm lazy and I don't try to change it; I exploit it.

Those are my thoughts.  Do you think this is a worthwhile project to pursue, instead of an editor?  I eventually want to make editors for Kartia, Azure Dreams, and FFXII (of course I need to locate the data first and learn the right programming languages, but I'm taking classes this fall so it doesn't seem like a pipe dream).  Should I make editors for each of them, or should I make something that will make it easy for me or anyone else to make editors for them?

nitwit

http://ffhacktics.com/wiki/Item_quantity_increment_for_steal/break%3F


Is the hyphen just before the word to be loaded in lw a typo?

0018e9e8: 3c028019 lui r2,0x8019
0018e9ec: 8c42f5fc lw r2,-0x0a04(r2)


I notice the same thing isn't found here.

Pride

Its a minus symbol, so its loading the word at x18f5fc
  • Modding version: PSX
Check out my ASM thread. Who doesn't like hax?