{"id":23,"date":"2022-12-30T12:36:58","date_gmt":"2022-12-30T12:36:58","guid":{"rendered":"http:\/\/192.168.1.222\/Capitoline\/?page_id=23"},"modified":"2024-06-27T16:28:55","modified_gmt":"2024-06-27T15:28:55","slug":"skick-rtb","status":"publish","type":"page","link":"http:\/\/capitoline.twocatsblack.com\/index.php\/skick-rtb\/","title":{"rendered":"skick\/RTB"},"content":{"rendered":"\n<p>If a ROM is fully understood (all the components have hash files), then you can create an RTB file for use with <a href=\"https:\/\/aminet.net\/package\/util\/boot\/skick346\">skick <\/a>this will allow you do &#8220;softload&#8221; a kickstart ROM, you&#8217;ll need a spare 512k chunk of memory available (and kickstart 2+), apparently you can use RTB files with <a href=\"http:\/\/whdload.de\/\">WHDLoad <\/a>too, but I haven&#8217;t really done too much work in this area.<br><br>In the GUI just click [Save RTB] or use &#8220;savertb&#8221; from CapCLI to generate an RTB file.<br><br>It&#8217;s important to note that skick often requires both a RTB and PAT (patch) file to make a kickstart work properly, but Cap doesn&#8217;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&#8217;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. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Known\/Existing skick Files<\/h2>\n\n\n\n<p>In the official bundle, there&#8217;s 19 official skick configurations, unfortunately some of the ROMs are betas that seem rare or impossible to find, so I can&#8217;t evaluate them or test that my RTB generation works exactly as it should. To be fair the ones I don&#8217;t have ROMs for are a little bit obscure so they probably aren&#8217;t that useful, but it also means that I haven&#8217;t got a complete history of the ROMs so if you have any more details I&#8217;d appreciate it.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>kick33180.A500.RTB       - OK\nkick34005.A500.RTB       - OK\n<\/strong>kick36143.A3000.RTB      - 0xb333d3c6 creates an almost identical RTB, but the C= checksum doesn't match\n<strong>kick37175.A500.RTB       - OK<\/strong>\nkick39046.A500.BETA.RTB  - I don't have any r39.46 ROMs\n<strong>kick39106.A500.BETA.RTB  - OK<\/strong> (This is actually an A600 ROM, not A500)\n<strong>kick39106.A1200.RTB      - OK<\/strong>\nkick39110.A500.BETA.RTB  - I don't have any r39.110 ROMs\nkick39115.A3000.BETA.RTB - I have the TOSEC r39.115, but checksum doesn't match (TOSEC appears to be an A600 hack)\n39115_ROMKick.RTB        - This appears identical to kick39115.A3000.BETA.RTB with a different checksum\n<strong>kick40003.A600.BETA.RTB  - OK<\/strong>\n<strong>kick40003.A3000.BETA.RTB - OK\nkick40009.A600.BETA.RTB  - OK\nkick40009.A4000.BETA.RTB - OK\nkick40038.A4000.BETA.RTB - OK<\/strong>\n<strong>kick40038.A600.BETA.RTB  - OK<\/strong>\n<strong>kick40063.A600.RTB       - OK\nkick40068.A1200.RTB      - OK\nkick40068.A4000.RTB      - OK<\/strong><\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">RTB file format<\/h2>\n\n\n\n<p>This is just a brief summary, there&#8217;s also some extra data in the original skick files that I don&#8217;t replicate, so I&#8217;m not documenting it here.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>nn nn nn nn              &#91;C= Checksum] four bytes, this MUST match the ROM you want to use it with, to for how the checksum\n                         is calculated (it's a checksum of the ROM not .RTB) see \"Kickstart -&gt; Kickstart Structure\"\n00 00 00                 Three binary zeroes\n<strong>(                        Reloc positions are now stored here, they are stored as delta's (distance from the last reloc) \n                         If the delta to the next reloc position &lt;256 then you'll see a single byte\nnn                       Single byte delta to the next (or first) reloc\n00                       If the byte is 00, then the (delta) position of the the next reloc is 256 or more  \n(00)                     If the file size is now odd, write another binary 00, I assume to word-align two byte deltas\nnn nn                    Two byte delta 0xnnnn to the next (or first) reloc, must be written at an even position in the RTB\n)<\/strong>\n00 00 00 00              Four binary zeroes (end of 32bit relocs)\nFF FF FF FF              Four binary FF's\n<strong>(                        Optional BCPL reloc section (typically only for early dos.library)\nnn nn nn nn              Four byte ROM offsets to the address that needs to be relocated, 0x00033e18 = 212504\n...                      They point at a BCPL address (x4 to get the ROMBASE relevant address 0x003FD2A2 = 0xFF4A88)\n00 00 00 00              Four binary zeroes (end of BCPL relocs)\n)<\/strong>\n00 00 00 00              Four binary zeroes (normal end of file)\n<strong>(\nnn nn nn nn              Four additional bytes, not often present - unknown purpose?\n)<\/strong><\/code><\/pre>\n\n\n\n<p>I&#8217;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 &#8211; 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 &#8220;large delta&#8221;, the next 00 means &#8220;keep the file even&#8221; and the next two, 00nn is the large delta, it&#8217;s pretty academic how you read the file to be honest. <br><br>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 &gt;255 delta to keep it even.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Example (far too small!) file, just to illustrate\n\nnn nn nn nn              C= Checksum\n00 00 00\n44                       Position of first reloc 68               File is now even\n10                       Position of next reloc 68 + 16 = 84      File is now odd\n12                       Position of next reloc 84 + 18 = 102     File is now even\n22                       Position of next reloc 102 + 34 = 136    File is now odd\n00 01 10                 Position of next reloc 136 + 272 = 408   Three bytes written to make file even\n08                       Position of next reloc 408 + 8 = 416     File is now odd\n04                       Position of next reloc 416 + 4 = 420     File is now even\n00 00 01 10              Position of next reloc 420 + 272 = 692   Four bytes written to keep file even\n00 00 00 08              Position of next reloc 692 + 8 = 700     Four bytes written to keep file even (last reloc, one byte would be odd)\n00 00 00 00              Four binary zeroes\nFF FF FF FF              Four binary FF's\n00 00 00 00              Four binary zeroes<\/code><\/pre>\n\n\n\n<p>Here&#8217;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&#8217;t claim it as your own, consider it in the public domain, it&#8217;s a bit shonky&#8230;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;unistd.h&gt;\n#include &lt;stdio.h&gt;\n#include &lt;fcntl.h&gt;\n#include &lt;stdio.h&gt;\n#include &lt;stdlib.h&gt;\n#include &lt;sys\/stat.h&gt;\n#include &lt;sys\/types.h&gt;\n\nint main(int argc,char *argv&#91;])\n{\nunsigned int iCnt,iOffset,iBreak,iKick;\nint iRTBChan,iKickChan,iKickSize;\nunsigned short int iSint;\nunsigned char cChar,cChar4&#91;4],*pcKick;\n\nif(argc==1)\n   {\n   printf(\"ERROR: checkrtb &#91;RTB file] &lt;kickstart&gt;\\n\");\n   exit(1);\n   }\n\nif(argc==3)\n   {\n   printf(\"Validating %s with kickstart %s\\n\",argv&#91;1],argv&#91;2]);\n   iKickChan=open(argv&#91;2],O_RDONLY);\n   if(iKickChan&lt;0)\n      {\n      printf(\"ERROR: Can't open kickstart\\n\");\n      exit(1);\n      }\n   }\nelse\n   iKickChan=-1;\n\niRTBChan=open(argv&#91;1],O_RDONLY);\n\nif(iRTBChan&gt;0)\n   {\n   iOffset=0;\n   printf(\"RTB Checksum:\");\n   for(iCnt=0;iCnt&lt;4;iCnt++)\n      {\n      read(iRTBChan,&amp;cChar,1);\n      cChar4&#91;iCnt]=cChar;\n      printf(\"%02x\",cChar);\n      }\n   printf(\"\\n\");\n   if(iKickChan&gt;0)\n      {\n      iKickSize=lseek(iKickChan,0,SEEK_END);\n      pcKick=malloc(iKickSize);\n      lseek(iKickChan,0,SEEK_SET);\n      read(iKickChan,pcKick,iKickSize);\n      close(iKickChan);\n\n      printf(\"Kickstart size:%d\\n\",iKickSize);\n      printf(\"Kickstart Checksum:\");\n      for(iKick=0;iKick&lt;4;iKick++)\n         printf(\"%02x\",pcKick&#91;iKickSize -24 +iKick]);\n      printf(\"\\n\");\n      if(memcmp(&amp;pcKick&#91;iKickSize -24],cChar4,4))\n         {\n         printf(\"\\nTerminal error, checksums don't match\\n\");\n         exit(1);\n         }\n      }\nprintf(\"Validating relocs\\n\");\n   while(read(iRTBChan,&amp;cChar,1))\n      {\n      iCnt++;\n      if(cChar)\n         {\n         iOffset+=cChar;\n         printf(\"RELOC=%d\",iOffset);\n         if(iKickChan&gt;0)\n            {\n            printf(\"\\t0x\");\n            for(iKick=0;iKick&lt;4;iKick++)\n               printf(\"%02x\",pcKick&#91;iOffset +iKick]);\n            }\n         printf(\"\\n\");\n         }\n      else\n         {\n         if(iCnt &amp; 1)\n            {\n            read(iRTBChan,&amp;cChar,1);\n            if(cChar)\n               printf(\"ERROR at position %d, byte should be 0x00 but is 0x%02x\\n\",iCnt,cChar);\n            iCnt++;\n            };\n         read(iRTBChan,&amp;cChar,1);\n         iCnt++;\n         iSint=cChar;\n         iSint&lt;&lt;=8;\n         read(iRTBChan,&amp;cChar,1);\n         iCnt++;\n         iSint+=cChar;\n         iOffset+=iSint;\n         if(iSint)\n            {\n            printf(\"RELOC=%d\",iOffset);\n            if(iKickChan&gt;0)\n               {\n               printf(\"\\t0x\");\n               for(iKick=0;iKick&lt;4;iKick++)\n                  printf(\"%02x\",pcKick&#91;iOffset +iKick]);\n               }\n            printf(\"\\n\");\n            }\n         else\n            {\n            printf(\"End of relocs\\n\");\n            iBreak=0;\n            while(read(iRTBChan,&amp;cChar,1))\n               {\n               printf(\"%02x\",cChar);\n               if(++iBreak == 4)\n                  {\n                  iBreak=0;\n                  printf(\" \");\n                  }\n               }\n            printf(\"\\n\");\n            }\n         }\n      }\n   close(iRTBChan);\n   }\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">PAT file format<\/h2>\n\n\n\n<p>I don&#8217;t really care too much about the .PAT file (I don&#8217;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;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>nn nn nn nn              &#91;C= Checksum] four bytes, this MUST match the ROM you want to use it with, to for how the checksum\n                         is calculated (it's a checksum of the ROM not .RTB) see \"Kickstart -&gt; Kickstart Structure\"\n(                        \nnn nn nn nn              Absolute offset position in the ROM that you want to patch\nnn nn nn nn              The four bytes you want to overwrite with, if you only want to change one byte, you still need four\n)\n00 00 00 00 00 00 00 00  Eight binary zeroes (end of file)<\/strong><\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>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 &#8220;softload&#8221; a kickstart ROM, you&#8217;ll need a spare 512k chunk of memory available (and kickstart 2+), apparently you can use RTB files with WHDLoad too, but I &hellip;<\/p>\n<p class=\"read-more\"> <a class=\"\" href=\"http:\/\/capitoline.twocatsblack.com\/index.php\/skick-rtb\/\"> <span class=\"screen-reader-text\">skick\/RTB<\/span> Read More &raquo;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":40,"comment_status":"closed","ping_status":"closed","template":"","meta":{"site-sidebar-layout":"default","site-content-layout":"default","ast-global-header-display":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","footnotes":""},"class_list":["post-23","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"http:\/\/capitoline.twocatsblack.com\/index.php\/wp-json\/wp\/v2\/pages\/23","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/capitoline.twocatsblack.com\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"http:\/\/capitoline.twocatsblack.com\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"http:\/\/capitoline.twocatsblack.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/capitoline.twocatsblack.com\/index.php\/wp-json\/wp\/v2\/comments?post=23"}],"version-history":[{"count":19,"href":"http:\/\/capitoline.twocatsblack.com\/index.php\/wp-json\/wp\/v2\/pages\/23\/revisions"}],"predecessor-version":[{"id":867,"href":"http:\/\/capitoline.twocatsblack.com\/index.php\/wp-json\/wp\/v2\/pages\/23\/revisions\/867"}],"wp:attachment":[{"href":"http:\/\/capitoline.twocatsblack.com\/index.php\/wp-json\/wp\/v2\/media?parent=23"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}