don't click here

PAR Code Handling

Discussion in 'Engineering & Reverse Engineering' started by Sappharad, Aug 29, 2010.

  1. Sappharad

    Sappharad

    Oldbie
    1,413
    70
    28
    So I noticed this post in the ERE forum mentioning that a PAR that works in Kega didn't work correctly in Gens.

    It appears that Gens does not handle PAR codes like the hardware does. In gens, the write size for RAM writes is based on how many characters are after the :, but since the real hardware forces you into FFXXXXXXXX format, you don't have a choice on that. Gens also supports 32-bit writes, which isn't possible on the real PAR hardware.

    As described in this post, if a PAR code is <= 0xFF, it is considered to be 8-bit and written that way. Thus a code with a value of :00FB would only write FB at the 8-bit address specified.

    The problem lies in gg_code.c:
    Code (Text):
    1. &nbsp;&nbsp;&nbsp;&nbsp;int data_chr_len = strlen(code) - pos_colon - 1;&nbsp;&nbsp;&nbsp;&nbsp;// Length of the data segment.
    2. &nbsp;&nbsp;&nbsp;&nbsp;
    3. &nbsp;&nbsp;&nbsp;&nbsp;if (data_chr_len <= 2)
    4. &nbsp;&nbsp;&nbsp;&nbsp;{
    5. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 1-2 characters: 8-bit code.
    6. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;datasize = DS_BYTE;
    7. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data &= 0xFF;
    8. &nbsp;&nbsp;&nbsp;&nbsp;}
    9. &nbsp;&nbsp;&nbsp;&nbsp;else if (data_chr_len <= 4)
    10. &nbsp;&nbsp;&nbsp;&nbsp;{
    11. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 3-4 characters: 16-bit code.
    12. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;datasize = DS_WORD;
    13. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data &= 0xFFFF;
    14. &nbsp;&nbsp;&nbsp;&nbsp;}
    15. &nbsp;&nbsp;&nbsp;&nbsp;else if (data_chr_len <= 8)
    16. &nbsp;&nbsp;&nbsp;&nbsp;{
    17. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 5-8 characters: 32-bit code.
    18. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;datasize = DS_DWORD;
    19. &nbsp;&nbsp;&nbsp;&nbsp;}
    Could you add
    Code (Text):
    1. if(data <= 0xFF){
    2. &nbsp;&nbsp; datasize = DS_BYTE;
    3. }
    to the end of the data_chr_len <= 4 case so that it properly handles PAR codes in the original format?

    Would you agree with this change? I guess it may break 16-bit codes designed specifically for Gens, but for accuracy it would be correct.
     
  2. GerbilSoft

    GerbilSoft

    RickRotate'd. Administrator
    2,971
    76
    28
    USA
    rom-properties
    This was a deliberate change in Gens/GS itself. The original Gens only supported 16-bit writes. I decided to use 2-character values for byte writes instead of 4-character.

    Realistically, there isn't much of a reason to force :00xx codes to be 8-bit, since the :xx format works just as well. I don't really think full PAR compatibility is needed, since it isn't too hard to convert it (just remove the 00s).
     
  3. Sappharad

    Sappharad

    Oldbie
    1,413
    70
    28
    But the problem is that any of the probably thousands of existing PAR codes with 8-bit writes aren't going to work, and anyone who doesn't know what to do with them isn't going to be able to use the codes. That's exactly what happened in the situation I linked, and I had to look at the source to find out that the input needed to be changed.

    I agree that it would be nice to be able to write a 16-bit 0000 with one code, but properly supporting the thousands of existing codes seems like a better choice to me.

    What if you change it so that you can still do what you want, but in a syntax specific to Gens as not to cause confusion against actual PAR codes? For example maybe use Address=Value instead of Address:Value to specify a literal value?
     
  4. GerbilSoft

    GerbilSoft

    RickRotate'd. Administrator
    2,971
    76
    28
    USA
    rom-properties
    I really don't think it's that difficult to "convert" the codes to the new format. Seriously. The effort of supporting yet another code format for 100% PAR compatibility is much more than the effort to just remove two zeroes from the code.

    If someone is too lazy to remove two zeroes from a *cheat* code, they shouldn't be using a computer.
     
  5. Sappharad

    Sappharad

    Oldbie
    1,413
    70
    28
    You're completely missing the point.
    The fact is that it's not intuitively obvious that you need to do that, as proven by the linked thread. I had to look at the fucking source code to see why something in a format that has been in existence for nearly 20 years wasn't working as a result of your changes.

    This is a simple case of providing backwards compatibility without needing to explain to the user that they need to do X in order for a random code to work. People don't usually read instructions, thus it seems to me like the best way to solve this would be to make the newer format slightly different.

    It's rather simple change, so if you don't agree I can always start offering binaries of a "fixed" plugin.
     
  6. GerbilSoft

    GerbilSoft

    RickRotate'd. Administrator
    2,971
    76
    28
    USA
    rom-properties
    It's actually detailed right in the included Gens/GS r7 manual in plugin-gamegenie.html. Also, it isn't called "Pro Action Replay" codes in Gens/GS, it's called "Patch Codes", so there's no guarantee of PAR compatibility.
     
  7. Overlord

    Overlord

    Now playable in Smash Bros Ultimate Moderator
    19,231
    968
    93
    Long-term happiness
    Seriously Gerbil, you should be going for the input of the original carts first and weird shorthand second.
     
  8. DigitalDuck

    DigitalDuck

    Arriving four years late. Member
    5,349
    435
    63
    Lincs, UK
    TurBoa, S1RL
    I'm with GerbilSoft on this one. If he was calling them "Pro Action Replay codes", then I'd expect 100% accurate emulation of PAR codes. However, this is a slightly different (and more logical, in fact) way of representing the codes.

    PAR method:
    xxxxxx:yyzz
    If yy!=00, write yy to address xxxxxx and write zz to address xxxxxx+1.
    If yy=00, write zz to address xxxxxx.

    "Patch code" method:
    xxxxxx:yy[zz[aabb]]
    Write yy to address xxxxxx.
    If zz, write zz to address xxxxxx+1.
    If aabb, write aa to address xxxxxx+2 and write bb to address xxxxxx+3.

    Basically, with the "Path code" method, you can write one, two, or four bytes with one code, with no restrictions on what those bytes can be (other than the obvious 0-255 limit). With PAR codes, you can write one byte, or two bytes provided the first isn't 0.

    Basically, this is a lot fucking easier.
     
  9. Sappharad

    Sappharad

    Oldbie
    1,413
    70
    28
    I was actually not aware that he wasn't referring to it as PAR codes, which does make a big difference. I agree from that standpoint that it's okay to leave as-is.

    However, the fact that he chose to use the same syntax as PAR codes still bothers me because it creates confusion. "Oh, it looks the same and sometimes works, so it must be the same." I still like the idea of changing it to =, and perhaps allowing any length of bytes after that point wouldn't be very difficult either. (Although limiting it to 8, 16, and 32 lets you flip to little endian properly, so there's an advantage to that as well.)

    I guess I'll let this rest, but I might consider coming up with a better code plugin with some of these ideas if there's enough interest. I would be interested, but at the same time I probably wouldn't use it anyway. :-)
     
  10. Sik

    Sik

    Sik is pronounced as "seek", not as "sick". Tech Member
    6,718
    1
    0
    being an asshole =P
    Yeah, if it looks like PAR then it should work like PAR. If you don't like that, then ditch it and go with something completely new that looks nothing alike. Maybe even allow multicode patches in the process (codes that affect different parts of memory).