I never saw this thread before, but if you're still looking to improve the PS2 stuff, I can take a look around. A couple of things I noticed at a glance:
- The site seems to convert 32-bit master-level writes to 8-bit regular writes for AR MAX. It should just be 32-bit regular writes.
- The AR MAX doesn't do master/hook writes because it's capable of executing any cheat command during hook processing, which is different from most or all other devices. If you want a code to be done only once, the only way to pull that off is by embedding it in the enable code. Typically, all this does is free a few cycles by eliminating some codes from the main loop, so it only really matters in a few extreme cases. There's also not a good way to automate conversions for cases where it might matter.
- The AR Version 2 can do master (one-time) writes with the exact same format the CodeBreaker uses. I'm somewhat certain the AR Version 1 can as well. I've never seen direct confirmation, though. The Japanese lived and died by the ARv1 for a long time, and I recall seeing a lot of A commands in their codes.
- Pointer Writes are being chewed up and spit out somehow during conversion. They're a low-use code type, and I can never remember the different formats offhand.
- Minor quibble, but the mirror RAM location is wrong. It looks to me like you added decimal 20000000 instead of 0x20000000 to the address.
Pointer writes on CodeBreaker. I think a version of the code type was available in Version 6, but version 7 tweaks the format a bit and offers the ability to do multiple levels.
I have the format for GS3+ somewhere. I know I posted it in a limited-access forum on CMP because it's broken and worth a laugh, but I don't even have an account there right now, and I have no idea if the forum even exists anymore. I'll have to see if I can dig it up from my archives somewhere. It's basically like—fake edit, the old CMP forum still exists in archive mode:
...additional offsets (valid on devices 7.0 and up only)
* aaaaaaa: 25-bit pointer address.
* xxxxxxxx: Value to be written. May be referenced as xx or xxxx as well.
* w: Width of the data to be written.
* cccc: Number of levels of indirection. (Number of pointers to be used, and also the number of offsets entered into the code).
* oooooooo: 32-bit offset from pointer. There can be a variable number of these.
Implementation: The starting pointer, located at aaaaaaa will be loaded and the offset oooooooo will be added to it, giving the temp_address. The pointer-count, cccc is decremented, and if it is zero, then the value xxxxxxxx will be stored at temp_address. If the pointer-count is not zero, the value at temp_address is loaded as a pointer, and the next offset is added to it. The process is repeated until the pointer-count is zero, at which time whatever value temp_address has will be overwritten with the value xxxxxxxx.
Allowed Width (w) Values
* 0 - 8-bits.
* 1 - 16-bits.
* 2 - 32-bits.
w - optional size (bit width) parameter 0/1 - 16-bit, 2 - 32-bit
a - location of pointer (less 0x1000000 if > 0xFFFFFF)
l - load offset, will be added to a before loading pointer (p)
d - destination offset added to pointer
x - data to write at p + d
a & 0xFFFFFF (byte aligment)
d & 0xFFFFFFF (byte alignment)
lw p, l(a)
sh x, d(p)
Why is there a load offset? Well, because they've cut themselves off from the second 16 MB of RAM by their choice of location for the size parameter. It's probably pretty rare that this data will be needed, so it's essentially wasted space mostly set to 0s.
Now an observant person might have noticed that the bit width parameter requires 2 bits of the same nibble (hex digit) that is normally split 3 to 1 for the encryption flags and the upper bit of the 25-bit address. Even though they've taken away 1 bit from the address, you still can't divide 4 bits among a 3-bit field and a 2-bit field and expect good results. The least significant bit of the encryption is actually being shared with this parameter, and since most encryptions bitwise-and their results with 0xF1FFFFFF, the code will never make it to the cheat engine in the state desired. Basically, they took the time and trouble to allow for 32-bit pointer-based writes, and then fucked it all up.
They could have solved this by making the second word of the code the size parameter. Then they could have done 8-bits, 16-bits, 32-bits, whatever their little hearts desired, and maybe even multiple levels of indirection. I'm sort of curious to see if they fixed this bug in later versions.