skick/RTB

If a ROM is fully understood (all the components have hash files), then you can create an RTB file for use with skick this will allow you do “softload” a kickstart ROM, you’ll need a spare 512k chunk of memory available (and kickstart 2+), apparently you can use RTB files with WHDLoad too, but I haven’t really done too much work in this area.

In the GUI just click [Save RTB] or use “savertb” from CapCLI to generate an RTB file.

It’s important to note that skick often requires both a RTB and PAT (patch) file to make a kickstart work properly, but Cap doesn’t know what should go into a PAT file, it only understands the relocs, so skick may or may not work with your particular ROM, that said, I’ve tried it with v2.05 (r37.350) and Hyperion 3.1.4/3.2 ROMs and it booted to Workbench OK, so you might be lucky.

Known/Existing skick Files

In the official bundle, there’s 19 official skick configurations, unfortunately some of the ROMs are betas that seem rare or impossible to find, so I can’t evaluate them or test that my RTB generation works exactly as it should. To be fair the ones I don’t have ROMs for are a little bit obscure so they probably aren’t that useful, but it also means that I haven’t got a complete history of the ROMs so if you have any more details I’d appreciate it.

kick33180.A500.RTB       - I don't generate the BCPL relocs for the DOS library so mine doesn't work
kick34005.A500.RTB       - I don't generate the BCPL relocs for the DOS library so mine doesn't work
kick36143.A3000.RTB      - 0xb333d3c6 creates an almost identical RTB, but the C= checksum doesn't match
kick37175.A500.RTB       - OK
kick39046.A500.BETA.RTB  - I don't have any r39.46 ROMs
kick39106.A500.BETA.RTB  - OK (This is actually an A600 ROM, not A500)
kick39106.A1200.RTB      - OK
kick39110.A500.BETA.RTB  - I don't have any r30.110 ROMs
kick39115.A3000.BETA.RTB - I have the TOSEC r39.115, but checksum doesn't match (TOSEC appears to be an A600 hack)
39115_ROMKick.RTB        - This appears identical to kick39115.A3000.BETA.RTB with a different checksum
kick40003.A600.BETA.RTB  - OK
kick40003.A3000.BETA.RTB - I don't have the A3000 version of r40.3
kick40009.A600.BETA.RTB  - I don't have the A600 version of r40.9
kick40009.A4000.BETA.RTB - OK
kick40038.A4000.BETA.RTB - OK
kick40038.A600.BETA.RTB  - I don't have the A600 version of r40.38
kick40063.A600.RTB       - OK
kick40068.A1200.RTB      - OK
kick40068.A4000.RTB      - OK

RTB file format

This is just a brief summary, there’s also some extra data in the original skick files that I don’t replicate, so I’m not documenting it here.

nn nn nn nn              [C= Checksum] four bytes, this MUST match the ROM you want to use it with, to for how the checksum
                         is calculated (it's a checksum of the ROM not .RTB) see "Kickstart -> Kickstart Structure"
00 00 00                 Three binary zeroes
(                        Reloc positions are now stored here, they are stored as delta's (distance from the last reloc) 
                         If the delta to the next reloc position <256 then you'll see a single byte
nn                       Single byte delta to the next (or first) reloc
00                       If the byte is 00, then the (delta) position of the the next reloc is 256 or more  
(00)                     If the file size is now odd, write another binary 00, I assume to word-align two byte deltas
nn nn                    Two byte delta 0xnnnn to the next (or first) reloc, must be written at an even position in the RTB
)
00 00 00 00              Four binary zeroes (end of 32bit relocs)
FF FF FF FF              Four binary FF's
(                        Optional BCPL reloc section (typically only for early dos.library)
nn nn nn nn              Four byte ROM offsets to the address that needs to be relocated, 0x00033e18 = 212504
...                      They point at a BCPL address (x4 to get the ROMBASE relevant address 0x003FD2A2 = 0xFF4A88)
00 00 00 00              Four binary zeroes (end of BCPL relocs)
)
00 00 00 00              Four binary zeroes (normal end of file)
(
nn nn nn nn              Four additional bytes, not often present - unknown purpose?
)

I’m assuming that the first three binary zeroes is a header, but it might be treated as a 00 00 long delta, and the first position is actually the second two bytes – the reality is that all kickstarts will have a reloc in the first 255 bytes so it will always be a short jump, i.e. if you read from the first 00 this means “large delta”, the next 00 means “keep the file even” and the next two, 00nn is the large delta, it’s pretty academic how you read the file to be honest.

Note, the block of deltas MUST end on a whole word (even file size), so if your last delta is a single byte and that would make the file size odd, then treat it as a >255 delta to keep it even.

Example (far too small!) file, just to illustrate

nn nn nn nn              C= Checksum
00 00 00
44                       Position of first reloc 68               File is now even
10                       Position of next reloc 68 + 16 = 84      File is now odd
12                       Position of next reloc 84 + 18 = 102     File is now even
22                       Position of next reloc 102 + 34 = 136    File is now odd
00 01 10                 Position of next reloc 136 + 272 = 408   Three bytes written to make file even
08                       Position of next reloc 408 + 8 = 416     File is now odd
04                       Position of next reloc 416 + 4 = 420     File is now even
00 00 01 10              Position of next reloc 420 + 272 = 692   Four bytes written to keep file even
00 00 00 08              Position of next reloc 692 + 8 = 700     Four bytes written to keep file even (last reloc, one byte would be odd)
00 00 00 00              Four binary zeroes
FF FF FF FF              Four binary FF's
00 00 00 00              Four binary zeroes

Here’s some random code to validate a RTB file against a kickstart, I wrote it without much error checking just as a quick patch to check I was generating RTB file validly, feel free to use, copy, modify etc. as long as you don’t claim it as your own, consider it in the public domain, it’s a bit shonky…

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>

int main(int argc,char *argv[])
{
unsigned int iCnt,iOffset,iBreak,iKick;
int iRTBChan,iKickChan,iKickSize;
unsigned short int iSint;
unsigned char cChar,cChar4[4],*pcKick;

if(argc==1)
   {
   printf("ERROR: checkrtb [RTB file] <kickstart>\n");
   exit(1);
   }

if(argc==3)
   {
   printf("Validating %s with kickstart %s\n",argv[1],argv[2]);
   iKickChan=open(argv[2],O_RDONLY);
   if(iKickChan<0)
      {
      printf("ERROR: Can't open kickstart\n");
      exit(1);
      }
   }
else
   iKickChan=-1;

iRTBChan=open(argv[1],O_RDONLY);

if(iRTBChan>0)
   {
   iOffset=0;
   printf("RTB Checksum:");
   for(iCnt=0;iCnt<4;iCnt++)
      {
      read(iRTBChan,&cChar,1);
      cChar4[iCnt]=cChar;
      printf("%02x",cChar);
      }
   printf("\n");
   if(iKickChan>0)
      {
      iKickSize=lseek(iKickChan,0,SEEK_END);
      pcKick=malloc(iKickSize);
      lseek(iKickChan,0,SEEK_SET);
      read(iKickChan,pcKick,iKickSize);
      close(iKickChan);

      printf("Kickstart size:%d\n",iKickSize);
      printf("Kickstart Checksum:");
      for(iKick=0;iKick<4;iKick++)
         printf("%02x",pcKick[iKickSize -24 +iKick]);
      printf("\n");
      if(memcmp(&pcKick[iKickSize -24],cChar4,4))
         {
         printf("\nTerminal error, checksums don't match\n");
         exit(1);
         }
      }
printf("Validating relocs\n");
   while(read(iRTBChan,&cChar,1))
      {
      iCnt++;
      if(cChar)
         {
         iOffset+=cChar;
         printf("RELOC=%d",iOffset);
         if(iKickChan>0)
            {
            printf("\t0x");
            for(iKick=0;iKick<4;iKick++)
               printf("%02x",pcKick[iOffset +iKick]);
            }
         printf("\n");
         }
      else
         {
         if(iCnt & 1)
            {
            read(iRTBChan,&cChar,1);
            if(cChar)
               printf("ERROR at position %d, byte should be 0x00 but is 0x%02x\n",iCnt,cChar);
            iCnt++;
            };
         read(iRTBChan,&cChar,1);
         iCnt++;
         iSint=cChar;
         iSint<<=8;
         read(iRTBChan,&cChar,1);
         iCnt++;
         iSint+=cChar;
         iOffset+=iSint;
         if(iSint)
            {
            printf("RELOC=%d",iOffset);
            if(iKickChan>0)
               {
               printf("\t0x");
               for(iKick=0;iKick<4;iKick++)
                  printf("%02x",pcKick[iOffset +iKick]);
               }
            printf("\n");
            }
         else
            {
            printf("End of relocs\n");
            iBreak=0;
            while(read(iRTBChan,&cChar,1))
               {
               printf("%02x",cChar);
               if(++iBreak == 4)
                  {
                  iBreak=0;
                  printf(" ");
                  }
               }
            printf("\n");
            }
         }
      }
   close(iRTBChan);
   }
}

PAT file format

I don’t really care too much about the .PAT file (I don’t create any), but just for completeness, this is the format of the .PAT file, basically the file contains a four byte offset, followed by four bytes to overwrite, it only does multiples of four, if you need to patch six bytes you need two patches of four bytes;

nn nn nn nn              [C= Checksum] four bytes, this MUST match the ROM you want to use it with, to for how the checksum
                         is calculated (it's a checksum of the ROM not .RTB) see "Kickstart -> Kickstart Structure"
(                        
nn nn nn nn              Absolute offset position in the ROM that you want to patch
nn nn nn nn              The four bytes you want to overwrite with, if you only want to change one byte, you still need four
)
00 00 00 00 00 00 00 00  Eight binary zeroes (end of file)
Scroll to Top