(solved)An attempt to decode sega system1 roms

Georgian2

Active member
Feedback
12 (100%)
Credits
1,761CR
Here I want to decode some encrypted roms that I can't find online so I can play them with an standard Z80.

Based on this info from the mame source code:
Code:
 Ninja Princess:

  there is a (bootleg?) board which has a standard Z80 + 2 bipolar PROMs
  instead of the custom CPU. The encryption table is different from the
  original Ninja Princess; it is actually the same as Flicky.

  The first PROM is 32x8 and contains the number (0..5) of the table to
  use depending on M1, A0, A4, A8, A12:

  00: 11 00 33 22 00 44 44 00 11 33 33 22 44 44 44 22
  10: 11 55 55 33 44 22 55 22 11 33 55 33 44 44 11 22

  The second PROM is 256x4 and contains the 6 different XOR tables:

       A  D  B  C  C  B  D  A
  00: 09 09 0A 0A 0A 0A 09 09
  08: 0E 08 0B 0D 0D 0B 08 0E
  10: 0A 0C 0A 0C 0C 0A 0C 0A
  18: 0B 0E 0E 0B 0B 0E 0E 0B
  20: 0C 0C 0F 0F 0F 0F 0C 0C
  28: 08 0D 0B 0E 0E 0B 0D 08
  [the remaining bytes are all 0F]
  bit 3 is not used.
  bits 0-2 is the XOR code inverted (0 = 0xa8, 1 = 0xa0 ... 6 = 0x08 7 = 0x00)

  Here is a diagram showing how it works:

  data to                             XOR
  decode                             value
                      A ---
  D7  --------------- 0|   |
  D3  --------------- 1|   |
  D5  --------------- 2| P |D
          A --- D      | R |0 ---|>--- D3
  M1  --- 0| P |0 --- 3| O |1 ---|>--- D5
  A0  --- 1| R |1 --- 4| M |2 ---|>--- D7
  A4  --- 2| O |2 --- 5| 2 |3 ---
  A8  --- 3| M |3 --- 6|   |
  A12 --- 4| 1 |4 --- 7|   |
            ---         ---
Dose this method work for all the games? if yes, what should the 2 proms contain for the I am sorry romset?

Or maybe someone knows where to get already decrypted romsets...

Thank you.
 

GadgetFreak

Active member
vacBacker
Feedback
7 (100%)
Credits
952CR
Yes I have decrypted all the main versions and also converted each one to either PPI or PIO, so I have versions on my multi for either main board type.
Each game has it's own decryption table which are in Mame "segacrpt_device.cpp" & "segacrp2_device" source files.
I have never worked with the PAL / CPU option but perhaps looking at the table in the Mame source for the right encoded cpu would give you some clues as to how to modify it to work with different versions.
 

Georgian2

Active member
Feedback
12 (100%)
Credits
1,761CR
This is what I came up with: I didn't try the roms since I doubt that my approch is functioning.

I don't understand what this 2 parameters are:
decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
C:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <ctype.h>
#include <conio.h>

unsigned char *rom = NULL;
unsigned char *romd = NULL;
int fsize = NULL;

int main(int argc, char *argv[])
{
    if (argc < 2)
    {
        printf("\nSega System1 ROM decrypting tool - Georgian Borca 2024\n");
        printf("Usage: decrypt <rom>\n");
        return 1;
    }
    //Try to open the rom file
    FILE *file = fopen(argv[1], "rb");
    if (file == NULL)
    {
        printf("error opening %s\n", argv[1]);
        return 2;
    }

    //Get the file size
    fseek(file, 0, SEEK_END);
    fsize = ftell(file);
    fseek(file, 0, SEEK_SET);

    //Read file
    rom = (unsigned char*)malloc(fsize);
    romd = (unsigned char*)malloc(fsize);
    fread(rom, 1, fsize, file);
    fclose(file);

    //Some log...
    printf("\nopen: %s, bytes: %d\n\n", argv[1], fsize);

    //decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
    sega_315_5110_device_decrypt();


    printf("\n\nDONE??\n");
    return 0;
}

void sega_315_5110_device_decrypt()
{
    static const uint8_t convtable[32][4] =
    {
        /*       opcode                   data                     address      */
        /*  A    B    C    D         A    B    C    D                           */
        { 0x88,0x08,0x80,0x00 }, { 0x00,0x20,0x80,0xa0 },   /* ...0...0...0...0 */
        { 0x00,0x20,0x80,0xa0 }, { 0x88,0x08,0x80,0x00 },   /* ...0...0...0...1 */
        { 0x88,0x08,0xa8,0x28 }, { 0x00,0x20,0x80,0xa0 },   /* ...0...0...1...0 */
        { 0x00,0x20,0x80,0xa0 }, { 0x88,0x08,0xa8,0x28 },   /* ...0...0...1...1 */
        { 0x00,0x20,0x80,0xa0 }, { 0x08,0x00,0x88,0x80 },   /* ...0...1...0...0 */
        { 0x00,0x20,0x80,0xa0 }, { 0x20,0x28,0xa0,0xa8 },   /* ...0...1...0...1 */
        { 0x20,0x28,0xa0,0xa8 }, { 0x00,0x20,0x80,0xa0 },   /* ...0...1...1...0 */
        { 0x20,0x28,0xa0,0xa8 }, { 0x88,0x08,0xa8,0x28 },   /* ...0...1...1...1 */
        { 0x88,0x08,0x80,0x00 }, { 0x08,0x00,0x88,0x80 },   /* ...1...0...0...0 */
        { 0x08,0x00,0x88,0x80 }, { 0x88,0x08,0x80,0x00 },   /* ...1...0...0...1 */
        { 0x08,0x28,0x00,0x20 }, { 0x08,0x28,0x00,0x20 },   /* ...1...0...1...0 */
        { 0x88,0x08,0x80,0x00 }, { 0x08,0x28,0x00,0x20 },   /* ...1...0...1...1 */
        { 0x08,0x28,0x00,0x20 }, { 0x08,0x00,0x88,0x80 },   /* ...1...1...0...0 */
        { 0x08,0x28,0x00,0x20 }, { 0x20,0x28,0xa0,0xa8 },   /* ...1...1...0...1 */
        { 0x20,0x28,0xa0,0xa8 }, { 0x08,0x28,0x00,0x20 },   /* ...1...1...1...0 */
        { 0x20,0x28,0xa0,0xa8 }, { 0x08,0x28,0x00,0x20 }    /* ...1...1...1...1 */
    };


    decode(rom, romd, 0x4000, convtable, 0, 0);
}

void decode(uint8_t *data, uint8_t *opcodes, int size, const uint8_t convtable[32][4], int bank_count, int bank_size)
{
    for (int A = 0x0000;A < size + bank_count*bank_size;A++)
    {
        int xorval = 0;

        uint8_t src = data[A];
        int adr;
        if(A < size || !bank_count)
            adr = A;
        else
            adr = size + ((A - size) % bank_size);

        /* pick the translation table from bits 0, 4, 8 and 12 of the address */
        int row = (adr & 1) + (((adr >> 4) & 1) << 1) + (((adr >> 8) & 1) << 2) + (((adr >> 12) & 1) << 3);

        /* pick the offset in the table from bits 3 and 5 of the source data */
        int col = ((src >> 3) & 1) + (((src >> 5) & 1) << 1);
        /* the bottom half of the translation table is the mirror image of the top */
        if (src & 0x80)
        {
            col = 3 - col;
            xorval = 0xa8;
        }

        /* decode the opcodes */
        //opcodes[A] = (src & ~0xa8) | (convtable[2*row][col] ^ xorval);

        /* decode the data */
        data[A] = (src & ~0xa8) | (convtable[2*row+1][col] ^ xorval);
        printf("%X ", data[A]);
        if (convtable[2*row][col] == 0xff)  /* table incomplete! (for development) */
            opcodes[A] = 0xee;
        if (convtable[2*row+1][col] == 0xff)    /* table incomplete! (for development) */
            data[A] = 0xee;
    }
}

Output:
1723374554846.png
 

Georgian2

Active member
Feedback
12 (100%)
Credits
1,761CR
If I copy evreything from mame Memory window using physical address 0 to BFFF, I schould then have the whole program rom, right? This matches the end of epr-6678.96 which is unecrpyted and the begining of the epr-6676.116 encrypted rom....

1723376965883.png
 

Georgian2

Active member
Feedback
12 (100%)
Credits
1,761CR
Using the save debug command dose not work.... It dose save the program data between address 0 and BFFF but the game dosen't work with the resulted data. I might be on the wrong track here...
Code:
save combined.bin,0,C000,":maincpu"
 

GadgetFreak

Active member
vacBacker
Feedback
7 (100%)
Credits
952CR
It is only the first 0x8000 bytes of rom space that is encrypted.
But you will also notice if you look more closely at the mame code that Opcode & Data are decrypted using different values. So in order to do a full decode you need to have acurrate disassembley of the memory area so you can work out which areas are actual code and which are data areas.
 

Georgian2

Active member
Feedback
12 (100%)
Credits
1,761CR
It is only the first 0x8000 bytes of rom space that is encrypted.
But you will also notice if you look more closely at the mame code that Opcode & Data are decrypted using different values. So in order to do a full decode you need to have acurrate disassembley of the memory area so you can work out which areas are actual code and which are data areas.
Thanks for your time but I have no ideea how to do what you said. I did see the the mame have a programm memory and opcodes memory. Still I have no ideea what to do.

Maybe some else will take over from here. My knowledge and skills end here.
 

Georgian2

Active member
Feedback
12 (100%)
Credits
1,761CR
One more try... @GadgetFreak
Using the dasm command in mame, I generate an dissansembly file. Here are the first lines of it:
Code:
0000: C3 3B 88    jp   $003B
0003: C3 7A A0    jp   $007A
0006: C3 9F 88    jp   $00B7
0009: 5F          ld   e,a
000A: 77          ld   (hl),a
000B: 5F          ld   e,a
000C: 77          ld   (hl),a
000D: 5F          ld   e,a
000E: 77          ld   (hl),a
000F: 5F          ld   e,a
0010: 77          ld   (hl),a
0011: D7          rst  $10
0012: 77          ld   (hl),a
0013: D7          rst  $10
0014: 77          ld   (hl),a
0015: D7          rst  $10
0016: 77          ld   (hl),a
0017: D7          rst  $10
0018: 77          ld   (hl),a
0019: D7          rst  $10
001A: 77          ld   (hl),a
001B: D7          rst  $10
001C: 77          ld   (hl),a
001D: D7          rst  $10
001E: 77          ld   (hl),a
001F: D7          rst  $10
0020: 77          ld   (hl),a
0021: 5F          ld   e,a
0022: 77          ld   (hl),a
0023: 5F          ld   e,a
0024: 77          ld   (hl),a

Let me see if I understood what you wrote.
At the address 0x0 there is 0xC3. Is this OPCODE?
At the address 0x1 and 0x2 there is 0x3B and 0x88. Is this DATA?
At the address 0x3 there is 0xC3. Again OPCODE? because it is an instruction?
At the address 0x4 and 0x5 there is 0x7A and 0xA0. Again this is data?

and so on...

So if I'm right, on the decode function posted above I should feed in the 116 and 109 rom files and compare each address with this file to see if at that position there is data or opcode. I hope I got it right.
 

Georgian2

Active member
Feedback
12 (100%)
Credits
1,761CR
Another night, another fail...

Using the asm file generated by mame with the dasm command, I exctracted all the addresses that are there.
I then simply checkt if the current address in loop is in that array or not, if it is, then decrypt as opcode, if it is not decrypt as data.

The binary file looks good to my eye but the Z80 still dosen't understand it.


C:
if (is_found(A, result)) {
            data[A] = (src & ~0xa8) | (convtable[2*row][col] ^ xorval);
            //printf("Address: 0x%X DATA:%X ",A, data[A]);
        } else {
            data[A] = (src & ~0xa8) | (convtable[2*row+1][col] ^ xorval);

Meanwhile, my multi game kit is 95% done. Still waiting for the tiles PCB. Nothing fancy here, just an HEX coded switch to select between eprom banks.

IMG_20240812_221816.jpgIMG_20240812_221822.jpg
 

Georgian2

Active member
Feedback
12 (100%)
Credits
1,761CR
Code:
Ninja Princess:

  there is a (bootleg?) board which has a standard Z80 + 2 bipolar PROMs
  instead of the custom CPU. The encryption table is different from the
  original Ninja Princess; it is actually the same as Flicky.

  The first PROM is 32x8 and contains the number (0..5) of the table to
  use depending on M1, A0, A4, A8, A12:

  00: 11 00 33 22 00 44 44 00 11 33 33 22 44 44 44 22
  10: 11 55 55 33 44 22 55 22 11 33 55 33 44 44 11 22

  The second PROM is 256x4 and contains the 6 different XOR tables:

       A  D  B  C  C  B  D  A
  00: 09 09 0A 0A 0A 0A 09 09
  08: 0E 08 0B 0D 0D 0B 08 0E
  10: 0A 0C 0A 0C 0C 0A 0C 0A
  18: 0B 0E 0E 0B 0B 0E 0E 0B
  20: 0C 0C 0F 0F 0F 0F 0C 0C
  28: 08 0D 0B 0E 0E 0B 0D 08
  [the remaining bytes are all 0F]
  bit 3 is not used.
  bits 0-2 is the XOR code inverted (0 = 0xa8, 1 = 0xa0 ... 6 = 0x08 7 = 0x00)

  Here is a diagram showing how it works:

  data to                             XOR
  decode                             value
                      A ---
  D7  --------------- 0|   |
  D3  --------------- 1|   |
  D5  --------------- 2| P |D
          A --- D      | R |0 ---|>--- D3
  M1  --- 0| P |0 --- 3| O |1 ---|>--- D5
  A0  --- 1| R |1 --- 4| M |2 ---|>--- D7
  A4  --- 2| O |2 --- 5| 2 |3 ---
  A8  --- 3| M |3 --- 6|   |
  A12 --- 4| 1 |4 --- 7|   |
            ---         ---


  My Hero:

  the bootleg does the decryption using a single 256x4 PROM, mapped in the
  obvious way:

  data to            XOR
  decode            value
          A ---
  D3  --- 0|   |
  D5  --- 1|   |D
  D7  --- 2| P |0 --- D3
  A0  --- 3| R |1 --- D5
  A4  --- 4| O |2 --- D7
  A8  --- 5| M |3 ---
  A12 --- 6|   |
  M1  --- 7|   |
            ---

It would be a lot easier to build this circuit and use an arduino to tap into the address lines and M1 pin. This way I could create a table with all the addresses where the M1 pin is asserted. But what should I put in the PROMs?

Looking at the myherobl "prom.a2" file and the convtable for the 315-5132, I see no relation at all between what that prom has and the convtable in mame.
 

GadgetFreak

Active member
vacBacker
Feedback
7 (100%)
Credits
952CR
I have already produced a multi with on screen selection of 16 games, all modified to have Freeplay, on screen dips and high score saving. Not sure why you want to reinvent the wheel.
 

Georgian2

Active member
Feedback
12 (100%)
Credits
1,761CR
I sort of got it!
one needs to decrypt the 116 and 109 eproms one time as data and one time as opcodes. Combine each with the unencrypted 96 eprom. Burn the opcoded in the lower part of an 27C010 and code in the upper part. One need to add an empty 27C128 file to each side so each half in equal in size. After that conect the M1 to A16 and it work. This method only works if one uses an single rom for program.

If 3 eproms are used, burn each opcodes and data the same way in an 27C256. Do this three time for the 116, 109, and 96. Connect A14 to Z80 M1.

This is not exactly what I itended to do but it's a good walkaround that works for me.

Have fun and hope you are not disapointed with this outcome.

 
Last edited:

GadgetFreak

Active member
vacBacker
Feedback
7 (100%)
Credits
952CR
I don't like to buy stuff. I prefer to make it myself. It's a hobby after all.
Hobbies always involve spending money. How else do you get the arcade boards.
Anyway I give plenty of my work away free of charge with the patcher, 100's of hours have gone into the various pacthes I have made.
But a few projects required constant dedicated work & hardware so these are the ones I sell such as the Sega System 1 multi, Atari System 1 multi, Bezerk/Fenzy Multi & Gauntlet multi.
 
Top