+retroclouds Posted July 18, 2010 Share Posted July 18, 2010 This thread describes my progress on turning Bouncing Babies into a cartridge ROM image. Warning: Only runs with 32K memory expansion RAM. This ZIP file contains the ROM image and source code baby_cart_conversion.zip Windows tools used for doing the conversion * classic99 (and its great debugger) * HxD hex editor * winasm99 (cross-assembler from Cory Bur included with the win994a emulator) * PERL The following reference material was used for doing the conversion * Graphics Programming Language (GPL manual, see Development Resources thread) * TMS9900 Assembler auf dem TI-99/4A (great assembler manual written in german) Others * Spectra2 alpha, my own assembler library for writing games Here we go: 1. I copied the #EA5 files (BABY5 and BABY6) in my classic99 DSK1 directory and started classic99. 2. Started the Editor/Assembler cartridge in classic99 and also opened the classic99 debugger window. 3. Selected #EA5 (RUN PROGRAM FILE) and entered DSK1.BABY5 4. The game started and while it was running I inspected high memory from >A000->FFFF Noticed that the first instruction starts at >CFDE. 5. Reset emulator and set breakpoint at >CFDE, then repeated step 3 6. The debugger halts execution at >CFDE, that's before the game does something. I press the "Dump RAM" button in the emulator and confirm the dialog requesting if I do want a dump. 7. A 64 kilobyte file MEMDUMP.bin is written in the classic99 directory, that's the one I'm looking for. 8. Started HxD hex editor and opened MEMDUMP.bin, I looked for the memory range >CFDE->FFFF. 9. I split this memory range and dumped it from HxD in the binary files "baby_0000_to_17FF.bin" and "baby_1800_to_3021.bin" They are pretty much a dump of the game split in two files. 10. Time to do some perl now, I recalled I had a short PERL script I used for turning bytes into assembly language data statements. With the PERL script I created "baby_0000_to_17FF.a99" and "baby_1800_to_3021.a99" 11. It's obvious that the game won't fit in a 8K ROM image, we'll need 2 banks so we'll be switching banks. Time to start notepad++ and do some hacking. I don't want to start from scratch so I used SPECTRA2 for doing things like memory setup, setting VDP registers, doing the bank switching, etc. 12. For each bank I create a new project in winasm99, called "baby_bank0.apf" and "baby_bank1.apf" 13. Ready to roll, assemble both projects and important, select option for creating binary files "baby_bank0.bin" and "baby_bank1.bin" 14. Ready to run our newly created bank-switched ROM image, reset classic99 after adding the below to your classic99.ini [usercart2] name=Bouncing Babies rom0=C|6000|2000|D:\projekte\baby_cart_conversion\baby_bank0.bin rom1=X|6000|2000|D:\projekte\baby_cart_conversion\baby_bank1.bin Here's the extract for the code in bank0 *************************************************************** * Cartridge header ********@*****@*********************@************************** AORG >6000 GRMHDR BYTE >AA,1,1,0,0,0 DATA PROG BYTE 0,0,0,0,0,0,0,0 PROG DATA 0 DATA KERNEL BYTE 15 TEXT 'BOUNCING BABIES' *////////////////////////////////////////////////////////////// * KERNEL MEMORY SETUP *////////////////////////////////////////////////////////////// * KERNEL ..: *************************************************************** * KERNEL - Spectra2 Kernel memory setup *************************************************************** * B @KERNEL ********@*****@*********************@************************** KERNEL LIMI 0 ; Turn off interrupts LWPI WS1 ; Activate workspace 1 LI TMP0,VM1 ; Graphics mode 1 BL @LOADVR ; Load shadow registers LI STACK,BASE1 ; Set data stack to base MOV @JPCODE,@SWBANK ; Bank switching trampoline code MOV @JPCODE+2,@SWBANK+2 ; Bank switching trampoline code B @MAIN ********@*****@*********************@************************** * VDP graphics mode 1 - See table definitions VM1 BYTE >00,>E0,>00,>0E,>01,>06,>00,>F3,32,>00 ; Graphic mode 1 JPCODE DATA >04D4,>0455 ; CLR *R4 and B *R5 * :.. MAIN BL @PUTVR ; Put shadow registers BL @FILMEM ; Clear memory A000-FFFF DATA >A000,>00,>FFFF->A000 BL @CPYM DATA BABY0,>CFDE,>17FF ; Copy part 1 to HIMEM >CFDE LI TMP0,BANK1 LI TMP1,>6070 ; Jump to copy code in bank 1 B @SWBANK .... BABY0 COPY "D:\Projekte\baby_cart_conversion\baby_0000_to_17FF.a99" END And this is the code for the second bank: *************************************************************** * Cartridge header ********@*****@*********************@************************** AORG >6000 GRMHDR BYTE >AA,1,1,0,0,0 DATA PROG BYTE 0,0,0,0,0,0,0,0 PROG DATA 0 DATA KERNEL BYTE 15 TEXT 'BOUNCING BABIES' *////////////////////////////////////////////////////////////// * KERNEL MEMORY SETUP *////////////////////////////////////////////////////////////// * KERNEL ..: *************************************************************** * KERNEL - Spectra2 Kernel memory setup *************************************************************** * B @KERNEL ********@*****@*********************@************************** KERNEL LIMI 0 ; Turn off interrupts LWPI WS1 ; Activate workspace 1 LI STACK,BASE1 ; Set data stack to base MOV @JPCODE,@SWBANK ; Bank switching trampoline code MOV @JPCODE+2,@SWBANK+2 ; Bank switching trampoline code B @MAIN ********@*****@*********************@************************** JPCODE DATA >04D4,>0455 ; CLR *R4 and B *R5 GPLWS BYTE >13,>F5,>09,>F0,>00,>A0,>43,>81 BYTE >CF,>DE,>02,>70,>06,>64,>4F,>F3 BYTE >00,>00,>00,>1E,>38,>00,>06,>1C BYTE >00,>00,>98,>00,>01,>08,>8C,>02 ********@*****@*********************@************************** MAIN LI TMP0,BANK0 LI TMP1,>6024 ; Start of code B @SWBANK BL @CPYM DATA BABY1,>E7DE,>17FF ; Copy part 2 to HIMEM >E7DE BL @CPYM DATA GPLWS,>83E0,30 ; Setup GPL Workspace as in Editor Assembler MOV @GPLWS+30,@>83FE ; 32 would have overwritten return stack B @>CFDE ; Start game in HIMEM ... BABY1 COPY "D:\Projekte\baby_cart_conversion\baby_1800_to_3021.a99" END I didn't include the SPECTRA code in the above snippets as it might distract from what we are trying to explain here Basically you don't know which bank will be selected when the TI-99/4A is powered up, that is the reason both banks include a cartridge header. If the second bank is selected first, all it does is a bank-switch to the first bank. This is what happens: BANK 1 ===== 1. If we start in BANK1 by coincidence, then all we do is setup workspace & stack and copy bank-switch trampoline code into scratch-pad memory. 2. We use the trampoline code in scratch-pad memory to select BANK0 and jump to the KERNEL subroutine there. BANK 0 ===== 1. This kernel actually only does a basic scratch-pad memory setup (workspace, bank-switch trampoline code, etc.) and sets VDP shadow registers the same way as in Editor/Assembler, when done it jumps to MAIN 2. In MAIN, we set the hardware VDP registers based on the values in the VDP shadow registers 3. Clear high memory >A000 to >FFF by filling it with >00 4. Copy >17FF bytes from game code in BANK0 to high memory >CFDE 5. We use the trampoline code in scratch-pad memory to select BANK1 and jump to >6070 (MAIN) BANK 1 ===== 1. We copy the remaining >17FF bytes from game code in BANK1 to high memory >E7DE 2. Almost done now, we only need to set the GPL workspace in scratch-pad memory the same was as if we would be using the Editor/Assembler module. So copy 32 bytes to >83E0 3. Ready to go, jump to start of game in high memory: B @>CFDE Below is the PERL script I used for turning the raw bytes into assembly data statements. It's nothing fancy just a quick hack. #!/usr/bin/perl use Data::Dumper; our @rom = (); our $size = 0; readdump('baby_1800_to_3021.bin'); #datadump('780','800'); datadump('0','17FF'); exit; sub readdump { my $fname = shift; if (-e "$fname") { my $image = ""; open(ROMH, "$fname") or die("Could not open \"$fname\"\n"); binmode ROMH; $size = read(ROMH, $image, 16384); @rom = unpack("C*", $image); close(ROMH); } else { die("no ROM!"); } } sub datadump { my $start = hex shift; my $end = hex shift; my $nl = 0; my $cm = ''; for (my $l=$start; $l<=$end; $l+=2) { if ($nl == 0) { print " DATA "; $cm = sprintf(" ; >%X - >%X\n", $l, $l+7); } printf("%s>%02X%02X",$nl > 0 ? ',' : '',$rom[$l],$rom[$l+1]); if ($nl == 3) { printf($cm); $nl = 0; } else { $nl++; } } } Quote Link to comment Share on other sites More sharing options...
+retroclouds Posted July 18, 2010 Author Share Posted July 18, 2010 I didn't have time to test it out on other emulators (MESS) nor did I try it on the real deal yet. You should be able to run this image when using a GRAM kracker device. Also if both ROM images are concatened as a single binary image and burned on a 16K EPROM it should work with the newer boards from Jon (keeping my fingers crossed) Quote Link to comment Share on other sites More sharing options...
jchase1970 Posted July 18, 2010 Share Posted July 18, 2010 Retroclouds, that is great instructions. I had no idea how to do that and you make it so clear. Thank you. When you talk about putting both files in 1 file for a 16k eprom, do you just attach the 2nd file to the end of the first? John Quote Link to comment Share on other sites More sharing options...
+retroclouds Posted July 19, 2010 Author Share Posted July 19, 2010 Retroclouds, that is great instructions. I had no idea how to do that and you make it so clear. Thank you. When you talk about putting both files in 1 file for a 16k eprom, do you just attach the 2nd file to the end of the first? John Thanks. Yes, you just add the 2nd file to the end of the first. If you are on windows you can do that by typing: copy /B baby_bank0.bin+baby_bank1.bin baby.bin Quote Link to comment Share on other sites More sharing options...
Tursi Posted July 19, 2010 Share Posted July 19, 2010 Wow! It's great to see a different approach to the cartridge problem, I think you did some thinking outside the box and it was very cool to read about! 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.