Shawn Jefferson Posted September 9, 2012 Share Posted September 9, 2012 (edited) Hi, While playing with getting Lode Runner to work as a cartridge image, I was using cc65 and was wondering about something to do with the new loader (since Wookie's great work cracking the encryption key, the loader is much smaller-49 bytes, and directly loads into RAM the first directory entry.) I used cc65 to generate the loader and initial cartridge image, manually edited the directory entry, and spliced the two together to form a LYX file. What should the directory entry look like? For Lode Runner, the destination address is $0200 and the size is $BA00. However, I couldn't figure out how to create a directory entry that would work. The loader code checks whether the length of the file is negative or not, and if it isn't XORs it with $FF. $BA however, is negative. If you xor the length with $FFFF beforehand it's not negative ($45FF), so the bootloader XORs it! The end result is that the cc65 loader (with my directory entry) does not load the whole file. I'm wondering if this is a bug in the loader or just me not understanding what the directory entry should look like! In the end, I had to patch the loader to get things to work properly. directory entry I used: 00 E7 00 88 00 02 00 BA code snippet from the cc65 bootloader: ; 4. Read in the main exe to RAM lda _FileDestAddr ldx _FileDestAddr+1 sta _FileDestPtr stx _FileDestPtr+1 lda _FileFileLen ldx _FileFileLen+1 phx ; The BLL kit uses negative counts plx ; while the basic Lynx uses positive bmi @3 ; make all counts negative (here's what I had to patch for LR... set it to bra $4 instead) eor #$FF pha txa eor #$FF bra @4 @3: pha txa @4: tay plx jsr seclynxread0 Edited September 9, 2012 by Shawn Jefferson Quote Link to comment Share on other sites More sharing options...
+karri Posted September 10, 2012 Share Posted September 10, 2012 (edited) Good find. I have to change this in the cc65 loader code. Perhaps the best solution would be to always used non-xored values for values in the directory. They are human readable. And it is easier to deal with non-xored stuff as the upper commands like open, read etc. will use actual sizes anyway. The way it is now makes it impossible to load in larger code snippets than $7fff which seems to be a bad design decision. I will fix this asap. Then you can load in the entire RAM if you want to. -- Karri Edited September 10, 2012 by karri Quote Link to comment Share on other sites More sharing options...
+karri Posted September 11, 2012 Share Posted September 11, 2012 Done. The daily snapshot will now contain a bootloader that is 20 bytes smaller than the previous one and the size limitations are gone. I also did the same changes to open() and read() commands. All take now positive arguments from the directory structure. So if you create your own directories with cc65 do not XOR the length and the offset values with $FF anymore like you do in the BLL-style directories. -- Karri Quote Link to comment Share on other sites More sharing options...
+karri Posted September 11, 2012 Share Posted September 11, 2012 Here is a small description about the new fileformat/bootloader of a Lynx cart. This is in tomorrows snapshot at cc65.org: 32 bytes Lynx header with info about the author etc. The same format as usually. 4c 59 4e 58 00 04 00 04 01 00 43 61 72 74 20 6e 61 6d 65 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 00 4d 61 6e 75 66 61 63 74 75 72 65 72 20 20 20 00 00 00 00 00 00 00 52 bytes encrypted miniloader that will load the secondary loader to $F000 ff 30 73 35 4a a8 54 ef 54 20 f5 38 f4 35 7e 31 7a c3 f6 eb ee 30 e3 e5 81 91 85 bf 4b d9 cf 80 5f 54 36 b5 8a b0 50 d6 38 22 3e c1 01 a6 dd f5 4b 5e 6b 21 151 bytes secondary loader that will be read starting at $F000 a2 00 a0 08 ad b2 fc 95 26 e8 88 d0 f7 a5 26 85 2e 20 62 f0 a5 28 49 ff a8 a5 27 49 ff aa 20 39 f0 a5 2a a6 2b 85 31 86 32 a5 2d 49 ff a8 a5 2c 49 ff aa 20 44 f0 6c 2a 00 e8 d0 03 c8 f0 57 20 57 f0 80 f5 e8 d0 03 c8 f0 4c 20 57 f0 92 31 e6 31 d0 f1 e6 32 80 ed ad b2 fc e6 2f d0 38 e6 30 d0 34 48 da 5a a5 1a 29 fc a8 09 02 aa a5 2e e6 2e 38 80 0b 90 04 8e 8b fd 18 e8 8e 87 fd ca 8e 87 fd 2a 8c 8b fd d0 ec a5 1a 8d 8b fd 64 2f a9 fc 85 30 7a fa 68 60 8 bytes first directory entry. It will be loaded into ZP RAM 00 d3 00 88 00 02 f2 0f At this point the memory is free from 0200 to EFFF. So you can now load quite a big chunk in RAM. -- Karri Quote Link to comment Share on other sites More sharing options...
Shawn Jefferson Posted September 11, 2012 Author Share Posted September 11, 2012 (edited) This is great information to go into the platform specific doc of cc65! I see those are horribly outdated... they even have my name and very old email address attached. Oh, and nice work, Karri! You've been doing an excellent job with the cc65 Lynx target, thank you! Edited September 11, 2012 by Shawn Jefferson Quote Link to comment Share on other sites More sharing options...
Wookie Posted September 14, 2012 Share Posted September 14, 2012 Yes, good work Karri. Thanks for keeping things alive. --wookie Quote Link to comment Share on other sites More sharing options...
+karri Posted September 14, 2012 Share Posted September 14, 2012 Thanks Wookie. The cracking of the private key made the life a lot easier, thanks. What about your site www.classicgamedev.com. Will it come up again? -- Karri Quote Link to comment Share on other sites More sharing options...
Shawn Jefferson Posted September 14, 2012 Author Share Posted September 14, 2012 Is there any reason to put the secondary loader at $F000? If it's only 151 byes, we could put it up higher and be able to load even larger programs. It should be able to go all the way up around $FB68 or so? Quote Link to comment Share on other sites More sharing options...
+karri Posted September 15, 2012 Share Posted September 15, 2012 (edited) There is no reason. I move it to $FB68 and try if it works from there. In the early days there was those 1k competitions. The absolute minimum would be: 64 bytes lnx header 52 bytes encrypted loader 908 bytes for the application I will make an encrypted loader that loads in 908 bytes starting at $0400 and jumps there after the load is complete. Are there any hard core coders up there for the competition? There would be just one category. It can be a game, a demo, an utility, anything. -- Karri Edited September 15, 2012 by karri Quote Link to comment Share on other sites More sharing options...
+karri Posted September 15, 2012 Share Posted September 15, 2012 (edited) The cc65 now has the secondary loader at FB68. A file game.lnx now looks like this. The lnx header. Needed for Handy only: 4c 59 4e 58 00 04 00 04 01 00 43 61 72 74 20 6e 61 6d 65 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 00 4d 61 6e 75 66 61 63 74 75 72 65 72 20 20 20 00 00 00 00 00 00 00 The bootloader at the start of the cart: ff 81 ca 33 be 80 a2 c4 6d 98 fe 8d bc 66 c0 7a 09 50 23 28 18 c8 06 70 58 4f 1b e1 c7 90 08 cd 1a 6e 5a 45 32 d7 6d c6 8a e5 d8 5c a0 e8 4f 7a 5f 73 8d 22 and the secondary loader that follows the encrypted loader a2 00 a0 08 ad b2 fc 95 26 e8 88 d0 f7 a5 26 85 2e 20 ca fb a5 28 49 ff a8 a5 27 49 ff aa 20 a1 fb a5 2a a6 2b 85 31 86 32 a5 2d 49 ff a8 a5 2c 49 ff aa 20 ac fb 6c 2a 00 e8 d0 03 c8 f0 57 20 bf fb 80 f5 e8 d0 03 c8 f0 4c 20 bf fb 92 31 e6 31 d0 f1 e6 32 80 ed ad b2 fc e6 2f d0 38 e6 30 d0 34 48 da 5a a5 1a 29 fc a8 09 02 aa a5 2e e6 2e 38 80 0b 90 04 8e 8b fd 18 e8 8e 87 fd ca 8e 87 fd 2a 8c 8b fd d0 ec a5 1a 8d 8b fd 64 2f a9 fc 85 30 7a fa 68 60 After the secondary loader you need one directory entry: 00 = block number d3 00 = offset $00d3 88 = dummy byte 00 02 = start address in RAM $0200 07 10 = length of binary to load $1007 Then you just append your binary code you want to load. You can change the start address and length to match your code. The last fc in the secondary loader should be different for different cart types. fe = 128k cart fc = 256k cart f8 = 512k cart -- Karri Edited September 15, 2012 by karri 1 Quote Link to comment Share on other sites More sharing options...
+karri Posted September 15, 2012 Share Posted September 15, 2012 I just cannot help spamming this group with the smallest bootloader EVER! This bootloader reads in a single Lynx cart block to $0400. I admit that the maximum length it can handle is a 2048 byte binary. Not very useful. But it would make a nice competition loader for minimal games . ff 5e 9b aa 96 8b f8 16 1f 4a d3 3b 03 c1 ce 35 bb 74 10 34 d2 54 09 cc 91 28 48 1f 56 5c 4e 01 4b e0 30 39 5e 00 36 58 a5 2e 0c 16 57 db 79 cd 4c b5 7a 2d Here you don't have secondary bootloader at all and no directory entries. Just the bootloader and your code starting at 0400. -- Karri Quote Link to comment Share on other sites More sharing options...
sage Posted September 15, 2012 Share Posted September 15, 2012 forget the loader and just encrypt your complete game. you would have to split it into 4 chunks of 250 bytes each and have just jump to the boot image three times. the mein problem is the initialization of the hardware on the _real_ machine, which eats up space. and, you will not even notive that it wont run if you always test in on the emulator :-b Quote Link to comment Share on other sites More sharing options...
LX.NET Posted September 17, 2012 Share Posted September 17, 2012 Great stuff, Karri. Do you have the source assembly for the loaders to share? I would be really interested to look into that. Quote Link to comment Share on other sites More sharing options...
+karri Posted September 17, 2012 Share Posted September 17, 2012 Of course. The source is in the cc65.org source tree at cc65/libsrc/lynx/bootldr.s bootldr.txt -- Karri Quote Link to comment Share on other sites More sharing options...
LX.NET Posted September 17, 2012 Share Posted September 17, 2012 Of course. The source is in the cc65.org source tree at cc65/libsrc/lynx/bootldr.s bootldr.txt -- Karri Thanks, Karri Quote Link to comment Share on other sites More sharing options...
obschan Posted September 22, 2012 Share Posted September 22, 2012 Thank you Karri for keeping it alive. To make things simple, do you have a sample of the new cc65 directory structure source file ? Quote Link to comment Share on other sites More sharing options...
+karri Posted September 22, 2012 Share Posted September 22, 2012 (edited) Thank you Karri for keeping it alive. To make things simple, do you have a sample of the new cc65 directory structure source file ? The default directory looks like this: ; ; Karri Kaksonen, 2011 ; ; A default directory with just the main executable. ; .include "lynx.inc" .import __STARTOFDIRECTORY__ .import __RAM_START__ .import __CODE_SIZE__,__DATA_SIZE__,__RODATA_SIZE__ .import __STARTUP_SIZE__,__INIT_SIZE__ .import __BLOCKSIZE__ .export __DEFDIR__: absolute = 1 ; ------------------------------------------------------------------------ ; Lynx directory .segment "DIRECTORY" __DIRECTORY_START__: off0=__STARTOFDIRECTORY__+(__DIRECTORY_END__-__DIRECTORY_START__) blocka=off0/__BLOCKSIZE__ ; Entry 0 - first executable block0=off0/__BLOCKSIZE__ len0=__STARTUP_SIZE__+__INIT_SIZE__+__CODE_SIZE__+__DATA_SIZE__+__RODATA_SIZE__ .byte <block0 .word off0 & (__BLOCKSIZE__ - 1) .byte $88 .word __RAM_START__ .word len0 __DIRECTORY_END__: If you want to make the directory larger you need to remove the line containing __DEFDIR__ in the config file. SYMBOLS { __STACKSIZE__: type = weak, value = $0800; # 2k stack __STARTOFDIRECTORY__: type = weak, value = $00CB; # start just after loader __BLOCKSIZE__: type = weak, value = 1024; # cart block size __EXEHDR__: type = import; __BOOTLDR__: type = import; __DEFDIR__: type = import; # REMOVE THIS LINE } Instead you create your own version of this file and link it in after the bootloader. You need to increase the size from 8 bytes of the DIR memory segment to 8 times number of directory entries. MEMORY { ZP: file = "", define = yes, start = $0000, size = $0100; HEADER: file = %O, start = $0000, size = $0040; BOOT: file = %O, start = $0200, size = __STARTOFDIRECTORY__; DIR: file = %O, start = $0000, size = 8; RAM: file = %O, define = yes, start = $0200, size = $BE38 - __STACKSIZE__; } SEGMENTS { EXEHDR: load = HEADER, type = ro; BOOTLDR: load = BOOT, type = ro; DIRECTORY:load = DIR, type = ro; STARTUP: load = RAM, type = ro, define = yes; LOWCODE: load = RAM, type = ro, optional = yes; INIT: load = RAM, type = ro, define = yes, optional = yes; CODE: load = RAM, type = ro, define = yes; RODATA: load = RAM, type = ro, define = yes; DATA: load = RAM, type = rw, define = yes; BSS: load = RAM, type = bss, define = yes; ZEROPAGE: load = ZP, type = zp; EXTZP: load = ZP, type = zp, optional = yes; APPZP: load = ZP, type = zp, optional = yes; } I am using a macro to calculate the offset and block number. .macro entry old_off, old_len, new_off, new_block, new_len, new_size, new_addr new_off=old_off+old_len new_block=new_off/__BLOCKSIZE__ new_len=new_size .byte <new_block .word (new_off & (__BLOCKSIZE__ - 1)) .byte $88 .word new_addr .word new_len .endmacro The directory entries are then built by calling the macro: _MAIN_FILENR=2+$1000 entry off1, 0, off2, block2, len2, len1, __CODE_LOAD__ _TITLEBG_FILENR=_MAIN_FILENR+1 entry off0, 0, titlebgoff, titlebgblock, titlebglen,__TITLE_SIZE__, __TITLE_START__ _INTRO_FILENR=_TITLEBG_FILENR+1 entry off2, len2, introoff, introblock, introlen,__STARTUP_SIZE__+__INIT_SIZE__+__INTRO_CODE_SIZE__+__INTRO_RODATA_SIZE__+__INTRO_DATA_SIZE__, __STARTUP_LOAD__ Edited September 22, 2012 by karri Quote Link to comment Share on other sites More sharing options...
obschan Posted September 22, 2012 Share Posted September 22, 2012 (edited) As always thank you Karri ! Perfect I got the directory working on the latest SVN version: 5829. Edited September 22, 2012 by obschan Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.