* * APF 2K System BIOS * Version .009 * ------------------ * * Disassembly and comments by Adam Trionfo * * Revisions * --------- * Version .009 (July 30, 2010) * - No changes made yet * * Version .008 (July 29, 2010) * - Completely commented the Write Routine * Version .007 (July 28, 2010) * - Many Updated to comments through-out code * * Version .006 (July 26, 2010) * - Renamed labels * * Version .005 (July 23, 2010) * - Commented the Left/Right Controller Input * * Version .004 (July 22, 2010) * - Updated information about Interrupts (Not Complete) * - Added some information about Left and * Right Pad controllers * - Managed to get most everything that was defined as * bytes disassembled. However, I still don't know what * it does. * * Version .003 (August 14, 2009) * - Made various descriptive updates through-out * complete document. * * Version .002 (August 7, 2009) * - Converted strings for enhanced readability: * Menu Messages , "COMPUTER" and "FIRE" * - Followed logic of APF Logo Write routine and * comments it. * * Version .001 (August 6, 2009) - First VERY rough draft * - Disassembled using DASMx (Version 1.10) * - Fixed assembly error from DASM at $40A0-$40A1 * - Replaced all ; at beginning of lines with * * - Replaced all db (define byte) with FCB * - Removed all tabs and replaced with spaces * - Changed all opcodes to upper-case * - Make sure that source assembles correctly with AS11 * - Use BINCVT.EXE to convert S19 file to binary file * - Make sure that new source matches byte-for-byte * with original 2K BIOS ROM in APF MP-1000. * - Replaced ships image in hex format with binary * format * - Commented (VERY loosely) * - Labeled interrupt vector area ($47F8-$47FF) * - Used DASM to disassemble part of IRQ Interrupt * PIA Equates PIA_DRA EQU $2000 ; PIA Data Register A PIA_CRA EQU $2001 ; PIA Control Register A PIA_DRB EQU $2002 ; PIA Data Register B PIA_CRB EQU $2003 ; PIA Control Register B * Equates (RAM Locations - Variables) JOYDATA EQU $01F2 ; Joystick Data TOPLEFT EQU $0200 ; Top-Left of Screen * Equates for Interrupt Flags and Counters I60 EQU $01FC ; Interrupt Service Flag I60J EQU $01C5 ; Address of Interrupt Service Routine ISEC EQU $01FD ; Interrupt Seconds Flag ISECJ EQU $01C7 ; Interrupt, JSR Seconds Address T60 EQU $01F8 ; Interrupt Counter per Interrupt TIME EQU $01FB ; 1/60 Seconds Counter SECOND EQU $01F9 ; Seconds Counter MINUTE EQU $01FA ; Minutes Counter * Misc Equates TOPOFMENU EQU $02C0 ; Top of Menu (7'th Row Down, Column 1) CARTRIDGE EQU $8000 ; First Byte of Cartridge Memory CARTMENU EQU $8001 ; Cartridge Menu Location MENUCHOIC EQU $8003 ; Number of Cartridge Menu Choices NUMPLAY EQU $8004 ; Display "Number of Players?" EXECCART EQU $8005 ; Beginning of Code in Cartridge Area EOS EQU $FF ; End of String ORG $4000 ; Start of APF BIOS Area CLRA ; Clear accum A STAA I60 ; Clear Interrupt Service Flag STAA ISEC ; Clear Interrupt Second Flag LDS #$01E4 ; Load Stack Pointer with $01E4 SEI ; Stop servicing IRQ interrupts LDAB #%00110101 ; Load Accum B with %00110101 STAB PIA_CRB ; Initialize PIA Control Reg. B LDAA #%11111111 ; Load Accum A STAA PIA_DRB ; Initialize PIA #1 CLR PIA_CRB ; Clear PIA Control Reg. B STAA PIA_DRB ; Store %11111111 in PIA #1 STAB PIA_CRB ; Store %00110101 in PIA Control Reg. B LDAB #%00110100 ; Load Accum B with %00110100 STAB PIA_CRA ; Store %00110100 in PIA Control Reg. A LDAA #$EF ; Load Accum A with $EF STAA $01F7 ; Store $EF at $01F7 CLR $01F4 ; Clear $01F4 CLR $01F6 ; Clear $01F6 LDAA #%00011111 ; Load Accum A with %00011111 STAA PIA_DRB ; Store %00011111 in PIA #1 CLI ; Begin servicing IRQ interrupts JMP BIOSSTART ; Jump to Beginning of BIOS Set-Up * Set-Up Write APF Top-of-Menu MENUTOP JSR FILLSCRN ; "Fill Screen" with Black LDX #APFTOPROW ; Load Index Reg with starting byte * of top row of APF Message string STX $01E6 ; Store Index Reg beginning at $01E6 LDX #$0208 ; Ninth byte of Screen Row 0. The is * where the top of 'a' in APF begins LDAA #$06 ; Write six bytes JSR WRITEAPF ; Jump to Write APF Graphic Logo Routine LDX #TVMICRO ; Beginning of "TV MICRO-COMPUTER" String STX $0006 ; Store Address of "TV MICRO-COMPUTER" String LDX #$0268 ; Screen Address to write "TV MICRO-COMPUTER" JMP WRITESTR ; Use "Write String Routine" to write menu BIOSSTART BSR MENUTOP ; Write APF Top-of-Menu * Is a Cartridge Inserted? * ------------------------ * If first byte of cartridge area ($8000) is $BB, then a * cart is inserted. LDAA CARTRIDGE ; Load first byte of cart into Accum A CMPA #$BB ; Is the first byte of cart a $BB? BNE NOCART ; No cart inserted, so branch here LDX CARTMENU ; It IS a cart, get cart menu location STX $0006 ; Store Cart Menu Location LDX #TOPOFMENU ; Load Text Mode Screen Location, * $02C0, 7'th Row Down STX $0004 ; Store Text Mode Screen Location JSR READSTR ; Use "Write String Routine" * Get Cartridge Menu Choice * ------------------------- * What choice did the user make from the cartridge menu? GETCHOIC BSR ISJOYUSED ; Get menu Choice from user CMPA #'0' ; Was the choice a zero (not valid)? BEQ GETCHOIC ; If zero, then get another choice CMPA MENUCHOIC ; How many menu choices are there? BGT GETCHOIC ; Is the choice > number of choices? * Valid Choice Made. Now What? ANDA #%00001111 ; Mask. Keep LSB STAA $0000 ; Store the user's choice LDAA NUMPLAY BEQ STARTCART ; If Players = 0, then start cartridge * Display "Number of Players?" * ---------------------------- * No cartridge EVER used this routine. This is because it does * NOT work as it should. Do NOT use it! * Perhaps this is a routine that APF meant to use, but never got * around to fixing. Make sure that $8004 is ALWAYS zero. However, * for fun, (and you know that you want to), try putting the number * of possible players into byte $8004 and see what happens... BSR MENUTOP ; Write APF Top-of-Menu <--- BAD CALL HERE LDX #PLAYERS ; "HOW`MANY`PLAYERS?" String STX $0006 ; Store location of string LDX #TOPOFMENU ; Top of Menu location JSR WRITESTR ; Write menu GETNUMPY BSR ISJOYUSED ; Get menu Choice from user CMPA #'0' ; Was the choice a zero (not valid)? BLE GETNUMPY ; Less then zero? Try Again. CMPA $8004 ; How many possible players? BGT GETNUMPY ; Too Many Players? Try Again. LDAA #%00001111 ; Mask ANDA JOYDATA ; Keep LSB of Joystick Data STAA $0001 ; Store Number of Players STARTCART JSR FILLSCRN ; Fill Screen JMP EXECCART ; Begin executing code in the cart area * Branch here after the menu is on the screen and there is no * cart present at $8000 NOCART BSR ISJOYUSED ; Has either joystick been used? ANDA #%00000011 ; Mask. Keep bits 0 and 1 STAA $0000 ; Store choice JMP L4380 * Was Either Joystick Used? * If Carry is Set, then the Joystick was used in some way * If Carry is Clear, the the Joystick was NOT used in some way ISJOYUSED JSR RIGHTPAD ; Get Input from Rightpad Controller BCS RJOYUSED ; Branch here if Right Controller was used JSR LEFTPAD ; Get Input from Leftpad Controller BCC ISJOYUSED ; Loop until there is input from a controller RJOYUSED LDAA JOYDATA ; Get Joystick Data is Joystick is used L40B8: RTS ; Return from Subroutine PLAYERS FCC "HOW`MANY`PLAYERS?" ; Screen Message FCB EOS ; End of String * Write APF Graphic Logo to Menu Screen * ------------------------------------- * This routine prints the APG logo to the screen. It loops * three times, one for each line of the APF logo, before * exiting when hitting a $FF (End of String). * * Important memory locations (still tentitive): * $0108,$0109 = Where to write on screen * $01EA = Holds number of bytes to write * $01ED = Holds result of Width of screen - length * of string * $01EB = Current byte of string (I think) * $0004 = Also current byte of string?? * $01EE,$01EF = Holds next byte to write to WRITEAPF STAA $01EA ; Store how many bytes to write STX $01E8 ; Store Index Reg to $01E8 and $01E9 LDAA #32 ; Load Accum A with Width of Screen SUBA $01EA ; Subtract contents of $01EA STAA $01ED ; Store new value of Accum A to 01ED L40D9: LDX $01E6 ; Load Index Reg with String address LDAA $00,X ; Load Accum A with first byte of string CMPA #EOS ; Does Accum A hold $FF (End of String)? BEQ L40B8 ; If End of String, branch to RTS STAA $01EB ; Current byte of string INX ; Increment position in String STX $01E6 ; Store Index Reg to $01E6 and $01E7 LDAB $01EA ; Store how many bytes to write L40EC: LDAA $00,X ; Load Accum A with next byte of string INX ; Point to next byte of string STX $0004 ; Store "Next Byte of String" address LDX $01E8 ; Load where to write string data STAA $00,X ; Store byte of string to screen INX ; Increment screen memory by one STX $01E8 ; Store current screen memory location LDX $0004 ; Load "Next Byte of String" address DECB ; Subtract 1 from number of bytes left to write BNE L40EC ; Finished writing string? If not, loop LDAA $01ED ; Load Accum A with string width size LDX $01E8 ; Load current screen write location JSR L411D ; Jump to Subroutine STX $01E8 ; Store Next Write location LDX $01E6 ; Load first byte of string after $01 LDAB $01EA ; Load number of bytes to write DEC $01EB ; Decrement current byte of string BNE L40EC ; Current byte of string <> 0? LDX $0004 ; Load Current byte of string STX $01E6 ; Store current byte of string BRA L40D9 ; Branch always L411D: STX $01EE ; Holds next screen byte to write to ADDA $01EF ; Add A with second byte of next * write byte location STAA $01EF ; Store added number in $01EF BCC L412B ; Branch if carry clear (?) INC $01EE ; Increment next screen byte to * write to (??) L412B: LDX $01EE ; After first run, holds location of * next write for 2'nd APF line RTS ; Return to Main APF Logo Write Routine L412F: PSHA STX $01EE LDAA $01EF SBA STAA $01EF BCC L413F DEC $01EE L413F: LDX $01EE PULA RTS * Write String * ------------ * This routine will: * * 1) Write a string using any valid "ASCII" characters * from $00-$7F. HOWEVER, the characters from $00-$3F * (Light Green character on Dark Green Background) are * AUTOMATICALLY changed to ASCII $40-7F (Dark Green * character on Light Green Background). However, this * does NOT change what the character is, just the * foreground and background color of the character. * 2) Write consecutive byte(s) of any fill-byte (any "ASCII" * character, 00-$FF) using control codes. * 3) Write one or more "spaces," $20, (Dark Green) using * control codes. * * This routine will begin printing with the byte found at the * first byte of the string and continue until an $FF (End of * String delimiter), Control Byte, or an invalid * Control Byte is reached. * * INVALID Control Bytes are Most Significant four Bits are (where * x is "don't care"): * * $8x, $9x, $Ax, $Bx * * Invalid control bytes are IGNORED and skipped (nothing is * written to memory). The next byte is then read in the string. * * Valid Control Bytes are Most Significant four Bits. They are * (where x is "don't care"): * * $Cx, $Dx, $Ex, $Fx * * The Least Significant four Bits can be any value. These will * represent the number of "spaces" (dark green) or "fill-bytes" * to write to memory. * * How to use the Control Bytes (CB): * 1) If the Control Byte's MSBs are $E or $F, then write * "Space," $20, which is the color "Dark Green" * 2) If the Control Byte's MSBs are $C or $D, then write * the next byte in the string (the "fill-byte"). * * The Control Byte determines how many "spaces" or "fill-bytes" to * write by AND'ing the Control Byte with $1F. * * An example of using a "Fill-Byte:" * * Control Byte is $D3 and the next character is $8F * * $D3 = 1101 0011 * AND $1F = 0001 1111 * --------- * Result = 0001 0011 = $13 = 19 in decimal * * So, Control Byte $D3, followed by $8F, will fill nineteen * consecutive bytes with $8F (Light Green). * * An example of using a "Space:" * * $F4 = 1111 0100 * AND $1F = 0001 1111 * --------- * 0001 0100 = $14 = 20 in decimal * * Control Byte $F4 will fill 20 consecutive bytes with * "Spaces," ($20), which is the color "Dark Green." * * The maximum number of "spaces" or "fill-bytes" varies depending on * the Control Byte used: * * $F = Max 30 "spaces" $D = Max 31 spaces of "fill-byte" * $E = Max 15 "spaces" $C = Max 31 spaces of "fill-byte" * * Keep in mind that $FF can't be used as a Control Byte as it is * already an "End of String" delimiter. * * Memory locations used in this routine: * * $0004 = Text Mode Memory Screen Location Address * $0006 = Current Byte of String Address WRITESTR STX $0004 ; Store Screen Location Address READSTR BSR LOADCHAR ; Load Current Byte and Make Checks LDX $0006 ; Load Current Byte of String Address LDAA $00,X ; Get Current Byte of String CMPA #EOS ; Is Current Byte the "End of String?" BNE READSTR ; Not "End of String,"" so read next byte RTS ; Reached "End of String" * LOADCHAR BSR CHECKEOS ; Check if current byte is "End of String" BLT CONTLBYT ; If MSb is high, (80-$FF), then is * it a Control Byte? LDX $0004 ; Load Memory Screen Location Address ORAA #%01000000 ; Mask STAA $00,X ; Write current byte of string to screen INX ; Increment Memory Screen Location Address STX $0004 ; Store Memory Screen Location Address BRA LOADCHAR ; Get another byte from string * Check if current byte is "End of String" * If not EOS, then update Current Byte of String Address CHECKEOS LDX $0006 ; Load String Location LDAA $00,X ; Get Current Byte of String CMPA #EOS ; Is Current Byte the "End of String?" BEQ EXITEOS ; Yes, it IS "End of String," so no Update INX ; Not "EOS," so increment String Address STX $0006 ; Store as Current Byte of String Address EXITEOS TAB ; Copy Current Byte of String to Accum B RTS * Check if Current Byte is Control Byte CONTLBYT CMPA #EOS ; Is Current Byte the "End of String?" BEQ EXITCONTL ; Yes it is EOS, so exit subroutine ANDA #%00011111 ; Mask $1F. Get # of Chars to write ANDB #%01100000 ; Mask $60 LSRB ; Logical Shift Right Accum B for LSRB ; a total of five times. LSRB LSRB LSRB BEQ EXITCONTL ; Bad Input: Is $8x, $9x, $Ax, or $Bx DECB ; BEQ LOADCHAR ; Not a Control Byte DECB ; BEQ GETFILL ; Valid Control Byte ($Cx or $Dx), Get Fill-Byte LDAB #$20 ; Valid Control Byte ($Ex or $Fx) so use Space GOTFILL LDX $0004 ; Get Screen Location Address * Write Character Loop (Fill-Byte or Space) CHARLOOP STAB $00,X ; Write character to screen INX ; Advance to next Screen Location Address DECA ; Decrease number of characters left to write BNE CHARLOOP ; Any more characters left to write? STX $0004 ; No, store Current Screen Location Address EXITCONTL RTS * Get Fill-Byte Character to Write for Write Character Loop GETFILL LDX $0006 ; Load Current Byte of String Address LDAB $00,X ; Get Fill-byte character to write in loop INX ; Increment to next Byte of String Address STX $0006 ; Store as Current Byte of String Address BRA GOTFILL ; Go loop through memory with this byte * Joystick Column and Row Data Table * ---------------------------------- * This holds the 16 possible locations of * the Joystick: * South, East, North and West * ? = CL * ! = First Button / EN * Numbers 0-9 JOYTABLE FCC "1047" FCC "SENW" FCC "3?69" FCC "2!58" L41A8: LDAA #$04 STAA $01EB STX $01EC LDAA $01,X BNE L41B8 LDAA #$F7 STAA $00,X L41B8: LDAA $00,X STAA $01F7 RTS * Get Input from Leftpad Controller LEFTPAD LDX #$01F3 BSR L41A8 L41C3: BSR L4220 LDAA PIA_DRA ; Read Controller Row LSRA LSRA LSRA LSRA CMPA #%00001111 ; Mask $0F BNE L41F7 BSR L424C DEC $01EB BNE L41C3 BRA L41F0 * This subroutine is run as soon as there is no cart present * Get Input from Rightpad Controller RIGHTPAD LDX #$01F5 BSR L41A8 L41DE: BSR L4220 LDAA PIA_DRA ; Read Controller Row ANDA #%00001111 ; Mask $0F CMPA #%00001111 ; Compare to $0F BNE L41F7 BSR L424C DEC $01EB BNE L41DE L41F0: LDX $01EC CLR $01,X CLC RTS L41F7: LDAB #$03 BSR L425B ADDB $01F1 STAB $01F1 LDX $01F0 LDAB $00,X LDX $01EC CMPB $01,X BEQ L4219 LDAA $01F7 STAA $00,X STAB $01,X L4214: STAB JOYDATA ; Joystick Data SEC RTS L4219: CMPB #$45 BGE L4214 CLC RTS FCB $01 ; NOP? * Has a button been pressed? (I THINK) * First time branched here from $41DE L4220: LDAA #%11100000 ; Set-up mask ANDA PIA_DRB ; Mask bits 5,6 and 7 * ; Bit 5 - A/G * ; Bit 6 - GM0 * ; Bit 7 - Int / Ext STAA $01F0 ; Store Mask results LDAA #%00011111 ; Set-up mask ANDA $01F7 ; Mask bits 0-4 * ; Bit 4 - Unknown * ; Bit 3 - Unknown * ; Bits 0-2 - Controller * scan row ORAA $01F0 ; STAA PIA_DRB ; PIA Data Register B LDAB #$04 ; Load Accum B with $04 BSR L425B LDX #JOYTABLE ; First Byte of Joystick Column/Row Table STX $01F0 CLC ; Clear the Carry Bit ASLB ; Shift Left Accum B ASLB ; Shift Left Accum B ADDB $01F1 STAB $01F1 BCC L424B ; Branch if Carry Clear INC $01F0 L424B: RTS L424C: LDAB $01F7 SEC RORB BCC L4257 L4253: STAB $01F7 RTS L4257: LDAB #$F7 BRA L4253 L425B: CLR $01E5 SEC L425F: LSRA BCC L4268 INC $01E5 DECB BNE L425F L4268: LDAB $01E5 RTS * Sounds * ------ * The newsletters say that sounds to be made: * * $426E - "Beep" * $4282 - "Beep" and "Whistle Noise" * $428B - "Click" L426C: LDAB #$05 L426E: STAB $01EC ; "Beep" BSR L428B L4273: DECB BNE L4273 BSR L428B INC $01EC LDAB $01EC L427E: DECB BNE L427E LDAB $01EC BSR L428B CMPB #$5F BNE L4273 RTS L428B: SEI ; "Click" LDAA PIA_CRB ; PIA Control Register B EORA #$08 STAA PIA_CRB ; PIA Control Register B CLI RTS * Fill Screen * ----------- * Blank the screen by filling the shape table from * ($3FF-$200) with '$80' (Black) * * If the first line of this rotuine is skipped, then this * routine can be used to fill the screen with all one code. * Just place the code to-be-filled-with in Accum A before * branching to ONECODE. FILLSCRN LDAA #$80 ; Load Accum A with $80 (black) ONECODE LDX #$0400 ; Load Index Reg with last byte of screen +1 FILLLOOP DEX ; Subtract 1 from the Index Reg. On * first screen write this will be $0399 STAA $00,X ; Store fill-code at screen location CPX #TOPLEFT ; Compare Index Reg to start of screen BNE FILLLOOP ; Screen not totally full? Then loop RTS ; Screen totally blanked. Return * IRQ Interrupt Servicing Routine * ------------------------------- * * Information taken from the "APF Programming and Technical * Assistance Manual," pages 10-11. See the manual for * additional information and examples on how to use * this IRQ routine. * * The interrupt system is driven by the field sync output of * the VDG. This occurs every 1/60 of a second. It is fed to * the MC6800 IRQ via the MP1000 PIA. * * This IRQ routine: * 1) Allows jumps to subroutines whose addresses are set * by the user. * 2) Keeps count of number of interrupts as well as seconds * and minutes. * * Flags and Counters: * * I60 - Interrupt Service Flag - If non-zero, causes an * immediate JSR from interrupt routine. The JSR * address is contained in I60J. Both I60 and I60J * are user set. * I60J - Address of Interrupt Service Routine - JSR Address * if I60 is non-zero. * ISEC - Interrupt Seconds Flag - If ISEC is non-zero, then * every 60 interrupts (1 second) a JSR will occur. * The JSR address is contained in ISECJ. Both ISEC * and ISECJ are user set. * ISECJ - Interrupt, JSR Seconds Address - The JSR address if * ISEC is non-zero and 1/60 second counter overflows. * T60 - Interrupt Counter per Interrupt - Incremented by * each interrupt. Clears to zero when overflows (at * 256th interrupt) and starts count again. * TIME - 1/60 Seconds Counter - Keeps count of 1/60 of * seconds. Clears when reaches 60 and then causes * SECOND to be incremented. * SECOND - Seconds Counter - Incremented every second. Clears * when reaches 60 and increments MINUTE. * MINUTE - Minutes Counter - Increments every 60 seconds. * Clears when reaches 60. L42A4: LDAA PIA_DRB ; PIA Data Register B TST I60 ; Is there an IRQ Service Request? BEQ NOIRQ ; If no IRQ request, then branch * Service the IRQ Service Request LDX I60J ; Address of Interrupt Service Routine JSR $00,X ; Jump to Interupt Service Routine * No Service Needed for IRQ Service Request NOIRQ INC T60 ; Increment Interrupt Counter BVC T60OVR ; Overflow of Interrupt Counter? CLR T60 ; If = 256, Clear Interrupt Counter * Overflow of Interrupt Counter T60OVR INC TIME ; Increment 1/60 Seconds Counter LDAA #59D ; Set-up for TIME compare CMPA TIME ; Is 1/60 Seconds Counter = 60? BGT NOT60 ; Branch if TIME > 60 * TIME is > 60 TST ISEC ; Interrupt, Seconds Flag BEQ NOISEC * Service Interrupt Seconds Flag LDX ISECJ ; Interrupt, JSR Seconds Address JSR $00,X ; Service Routine for Seconds Address * ISEC Does NOT Need to be serviced, so clear time * and update SECOND and MINUTE. NOISEC CLR TIME ; Clear 1/60 Seconds Counter CLC ; Clear Carry LDAA SECOND ; Seconds Counter CMPA #$59 ; BEQ L42DF ; ADDA #$01 ; DAA ; Decimal Adjust Accum A STAA SECOND ; Seconds Counter NOT60 RTI ; Return from IRQ Interrupt L42DF: CLR SECOND ; Clear Seconds Counter LDAA MINUTE ; CMPA #$99 ; BEQ L4306 ; ADDA #$01 ; DAA ; STAA MINUTE ; RTI ; Return from IRQ Interrupt L42F0: PSHA SEI STS $01E8 LDS $01E6 DES L42F9: PULA STAA $00,X ; Eventually, this reads the first byte of * the Rocket Patrol ship INX DECB BNE L42F9 LDS $01E8 CLI PULA RTS L4306: CLR MINUTE ; Clear Minutes Counter RTI ; Return from IRQ Interrupt * Large APF graphic used on Menu Screen * ------------------------------------- * APF Graphic, Line 1 APFTOPROW FCB $01 ; Start of String (?) FCB $EC, $EA, $EE, $EA, $EE, $E8 * APF Graphic, Line 2 FCB $01 ; Start of String (?) FCB $9E, $9A, $9E, $98, $9E, $98 * APF Graphic, Line 3 FCB $01 ; Start of String (?) FCB $DC, $D8, $D8, $80, $D8, $80 FCB EOS ; End of String * Rocket Patrol Menu String * ------------------------- TVMICRO FCC "TV MICRO-COMPUTER" FCB $CF ; Control Byte - Fill 15 spaces with next byte FCB $80 ; Fill-Byte - ASCII $80, (Black) FCC "COPYRIGHT APF1978" FCB $DB ; Control Byte - Fill 27 spaces with next byte FCB $80 ; Fill-Byte - ASCII $80, (Black) FCB $CC ; Control Byte - Fill 12 spaces with next byte FCB $80 ; Fill-Byte - ASCII $80, (Black) FCB $E8 ; Control Byte - Fill 8 spaces with * ASCII $20, "Space" (Dark Green) FCC "ROCKET PATROL" FCB $F4 ; Control Byte - Fill 20 spaces with * ASCII $20, "Space" (Dark Green) FCB $F7 ; Control Byte - Fill 23 spaces with * ASCII $20, "Space" (Dark Green) FCC "1. TWO PLAYER" FCB $D3 ; Control Byte - Fill 19 spaces with next byte FCB $8F ; Fill-Byte - ASCII $8F, (Light Green) FCC "2. PLAYER AND COMPUTER" FCB $CA ; Control Byte - Fill 10 spaces with next byte FCB $8F ; Fill-Byte - ASCII $8F, (Light Green) FCB EOS ; Control Byte - End of String * Run after Menu Choice is selected * Is this the beginning of Rocket Patrol? L4380: LDAA PIA_DRB ; PIA Data Register B ANDA #%00111111 ; Mask $3F ORAA #%11000000 ; Mask $C0 STAA PIA_DRB ; PIA Data Register B LDAA PIA_CRA ; PIA Control Register A ANDA #%11000111 ; Mask $C7 ORAA #%00111000 ; Mask $38 STAA PIA_CRA ; PIA Control Register A * Fill screen with zeros CLRA ; Prepare to fill Screen with '0' JSR ONECODE ; Fill Screen with Zeros * Write Rocket Patrol Score Area LDX #SCOREAREA ; Top four rows of Rocket Patrol Score Area STX $0006 LDX #TOPLEFT ; Top-Left Corner of Screen JSR WRITESTR ; Use Write String Routine * LDX #GETRIGHT ; Address of JSR for Input from Rightpad Controller LDAA $0000 DECA BEQ L43B8 LDX #COMPUTER ; Location of "COMPUTER" message LDAB #$08 LDAA #$31 JSR L447F LDX #L4545 L43B8: STX $0190 * Fill from $0000-$0180 with $54 LDX #$0000 ; Start fill of memory at $0000 LDAA #$54 ; Place a $54 into Accum A FILL54 STAA $00,X ; Store $54 INX ; Increment to next area of memory for fill CPX #$0180 ; Has $0000-$0180 been filled with $54? BNE FILL54 ; If not, then loop until done * Set-up to set zero to 30 Consecutive Bytes at $0142 CLRA ; Setup to Store Zero LDAB #30 ; Setup to write for 30 consecutive bytes LDX #$0142 ; Setup to Start Address in memory JSR SETSAME ; Set zero to 30 Consecutive Bytes at $0142 LDX #$4551 STX I60J ; Interrupt JSR Service Address LDX #$012F LDAA #$02 STAA $0192 STX $015D BSR L444B LDAA #$C0 LDX #$0350 STAA $07,X LDX #$47A0 ; This is a "unknown" byte - Data? STX $01E6 LDX #$0181 LDAB #$0C JSR L42F0 JSR L4652 LDX #$47AC STX $01E6 LDX #$0142 LDAB #$0A JSR L42F0 INC I60 ; Increment Interrupt Service Flag CLR MINUTE ; Clear Minutes Counter CLR SECOND ; Clear Seconds Counter CLR $018E CLR $018F LDX #$0142 STX $0140 JSR L469B L4422: LDAA MINUTE ; Minutes Counter CMPA #$02 BLT L4433 CMPA #$03 BGT L4463 LDX #$44BC STX $0190 L4433: LDAB $015F BEQ L4442 JSR L428B LDAB #$DF L443D: DECB BNE L443D BRA L4433 L4442: BSR L444B LDX $0190 JSR $00,X ;INFO: INDEX JUMP BRA L4422 L444B: LDX #$0770 JSR L4779 LDAA #$18 STAA $077C LDAA #$7E STAA $077D LDX $015D LDAA #$57 STAA $00,X RTS L4463: CLR MINUTE ; Minutes Counter L4466: LDAA #$07 CMPA MINUTE ; Minutes Counter BNE L4466 CLR I60 ; Clear Interrupt Service Flag LDAA PIA_DRB ; PIA Data Register B ANDA #$7F STAA PIA_DRB ; PIA Data Register B LDAA #$80 ; Prepare to fill Screen with '$80' (Black) JSR ONECODE ; Fill Screen with $80 (Black) L447D: BRA L447D L447F: STAA $01E9 LDAA #$02 STAA $01E8 STX $01E6 LDX $01E8 JMP L42F0 L4490: STAA $01E8 LSRA LSRA LSRA LSRA BEQ L44A5 ABA L449A: STAA $00,X LDAA $01E8 ANDA #$0F ABA STAA $01,X RTS L44A5: LDAA #$60 BRA L449A L44A9: RTS GETRIGHT JSR RIGHTPAD ; Get Input from Rightpad Controller L44AD: LDAA #$8F LDAB #$CF BSR L44EF LDAB #$3D LDX #$018E BCS L44F7 BRA L44CC JSR LEFTPAD LDAA #$CF LDAB #$8F BSR L44EF LDAB #$21 LDX #$018F BCS L44F7 L44CC: LDAA $015C BEQ L44A9 L44D1: JSR L428B LDAA #$70 L44D6: DECA BNE L44D6 DEC $015C BNE L44D1 LDAA $00,X ADDA #$01 DAA STAA $00,X STAB $0193 LDX $0192 LDAB #$70 BRA L4490 L44EF: LDX #TOPLEFT ; Top-Left Corner of Screen STAA $20,X STAB $3C,X RTS L44F7: LDX $015D LDAA JOYDATA ; Load Direction of Joystick CMPA #$45 ; Is the direction East? BEQ L4520 CMPA #$21 BEQ L452C CMPA #$57 ; Is the direction West? BNE L44A9 DEX CPX #$0125 BEQ L44A9 LDAA #$54 STAA $01,X L4513: STX $015D LDAA #$57 STAA $00,X LDAB #$50 JSR L426E L451F: RTS L4520: CPX #$013A BEQ L451F LDAA #$54 STAA $00,X INX BRA L4513 L452C: LDAA #$C5 STAA $015F LDX $015D STX $0158 LDAA #$57 STAA $00,X LDX #FIRE ; Location of "Fire" String LDAA #$2C LDAB #$04 JMP L447F L4545: LDAA #$06 BITA $01F8 BEQ L454E BSR L452C L454E: JMP L44AD LDAA PIA_CRB ; PIA Control Register B ANDA #%11111100 ; Mask $FC ORAA #%00000011 ; Mask $03 STAA PIA_CRB ; PIA Control Register B LDX #$4566 STX $01C5 JSR L4627 BRA L45A0 LDX #$4551 STX $01C5 LDAA PIA_CRB ; PIA Control Register B ANDA #%11111100 ; Mask $FC ORAA #%00000001 ; Mask $01 STAA PIA_CRB ; PIA Control Register B LDX #$0064 L4579: DEX BNE L4579 LDAA PIA_DRB ; PIA Data Register B ANDA #%01111111 ; Mask $7F STAA PIA_DRB ; PIA Data Register B LDX #$01A0 L4587: DEX BNE L4587 LDAA PIA_DRB ; PIA Data Register B ORAA #%10000000 ; Mask $80 STAA PIA_DRB ; PIA Data Register B JSR L467C LDAA #$01 BITA $01FA BEQ L459F JSR L467C L459F: RTS L45A0: LDAA $015F BEQ L459F DEC $015F BNE L45B3 LDX $0158 LDAB #$54 STAB $00,X BRA L461D L45B3 LDX #$0142 BSR L45DA LDX #$014C BSR L45DA LDX #$0152 BSR L45DA ANDA #$03 BNE L4626 LDX #$0770 LDAA $00,X BNE L45EC L45CD: LDAA $02,X STAA $00,X CLR $02,X INX CPX #$077E BNE L45CD RTS L45DA: STX $015A LDX $00,X INX LDAB #$04 L45E2: CPX $0158 BEQ L460C INX DECB BNE L45E2 RTS L45EC: LDAA $00,X STAA $0E,X LDAA $01,X STAA $0F,X CLR $00,X CLR $01,X LDX $0158 LDAA #$54 STAA $00,X LDAB #$20 JSR L412F STX $0158 LDAA #$57 STAA $00,X RTS L460C: LDX $015A LDAB #$BF STAB $015C LDAB #$20 STAB $04,X CLR $05,X CLR $015F L461D: LDX #$8F8F STX $022C STX $022E L4626: RTS L4627: LDX #$0350 CLC ROR $07,X BCS L4630 RTS L4630: LDAA #$C0 STAA $07,X LDAA #$54 BSR L4654 LDX #$0181 LDAB #$06 L463D: LDAA $01,X ANDA #$1F CMPA #$1F BNE L464B LDAA $01,X ANDA #$E0 STAA $01,X L464B: INC $01,X INX INX DECB BNE L463D L4652: LDAA #$55 L4654: LDAB #$06 LDX #$0181 STX $01C9 STAA $015A L465F: LDX $00,X LDAA $00,X CMPA #$55 BEQ L466B CMPA #$54 BNE L4670 L466B: LDAA $015A STAA $00,X L4670: LDX $01C9 INX INX STX $01C9 DECB BNE L465F RTS L467C: LDX #$0142 STX $0140 LDX $08,X LDAB #$10 L4686: CLC ROL $40,X ROL $30,X ROL $20,X ROL $10,X ROL $00,X BCS L4698 INX DECB BNE L4686 L4697: RTS L4698: LDX $0140 L469B: LDX $08,X JSR L4779 LDX $0140 LDX $06,X STX $01E6 LDX $0140 LDX $08,X LDAA #$10 JSR L411D LDAB #$40 JSR L42F0 LDX #$0142 STX $0140 BSR L4706 LDX #$014C LDAA $00,X ADDA $01,X BEQ L46CD STX $0140 BSR L4706 L46CD: LDX #$0152 TST $01,X BEQ L46D9 STX $0140 BRA L4706 L46D9: LDX #$0142 LDAA $04,X CMPA #$08 BNE L46F0 LDX #$00DF STX $014C STX $014E LDX #$014C BRA L4700 L46F0: CMPA #$0C BNE L4697 LDX #$00BF STX $0152 STX $0154 LDX #$0152 L4700: LDAA #$48 STAA $05,X BRA L471C L4706: LDX $00,X DEX STX $015A LDX $0140 LDAA $015A STAA $00,X LDAA $015B STAA $01,X L4719: LDX $0140 L471C: LDAA $05,X LDAB $04,X INC $04,X CMPB #$1F BGT L4745 DECB BLT L4735 BEQ L4734 DECB BEQ L4733 DECB BEQ L4732 INCA L4732: INCA L4733: INCA L4734: INCA L4735: LDAB $05,X LDX $00,X L4739: STAB $00,X INX INCB CBA BGE L4739 LDAA #$54 STAA $00,X RTS L4745: SUBB #$1F CMPB #$05 BEQ L4760 ABA LDAB $05,X ADDB #$04 PSHB LDX $00,X LDAB #$54 STAB $05,X PULB L4758: STAB $04,X DEX DECB CBA BLE L4758 RTS L4760: LDX $00,X LDAA #$54 STAA $05,X LDX $0140 LDAA #$48 STAA $05,X CLR $04,X LDAA $02,X STAA $00,X LDAA $03,X STAA $01,X BRA L4719 L4779: CLRA LDAB #$10 * Set Same Value to a Consecutive Group of addresses * -------------------------------------------------- * (Details in Tech Manual in chapter 8, Page 8) * * Enter Routine with: * X Reg - Start Address in memory to get set * B Reg - Number of Consecutive Bytes * A Reg - Value to be Stored SETSAME STAA $00,X ; Store Value INX ; Increment to next address to store value DECB ; Decrement number of times through loop BNE SETSAME ; If not done, then keep setting to same value RTS * Rocket Patrol Score Area * ------------------------ * Data for Top Four Rows of Rocket Patrol Game Screen * This data is referred to from $4398. SCOREAREA * Row 0 ($0200-$021F) FCB $DF ; Control Byte - Fill 31 fill-bytes of next byte FCB $83 ; Fill-Byte - (Top-Half Black, Bottom-Half Light Green) FCB $C1 ; Control Byte - Fill 1 fill-byte of next byte FCB $83 ; Fill-Byte - (Top-Half Black, Bottom-Half Light Green) * Row 1 ($0220-$023F) FCB $DF ; Control Byte - Fill 31 fill-bytes of next byte FCB $8F ; Fill-Byte - (Solid Light Green Block) FCB $C1 ; Control Byte - Fill 1 fill-byte of next byte FCB $8F ; Fill-Byte - (Solid Light Green Block) * Row 2 ($0240-$025F) FCB $DF ; Control Byte - Fill 31 fill-bytes of next byte FCB $8C ; Fill-Byte - (Top-Half Light Green, Bottom-Half Black) FCB $C1 ; Control Byte - Fill 1 fill-byte of next byte FCB $8C ; Fill-Byte - (Top-Half Light Green, Bottom-Half Black) * Row 3 ($0260-$027F) FCB $DF ; Control Byte - Fill 31 fill-bytes of next byte FCB $80 ; Fill-Byte - (Solid Black) FCB $C1 ; Control Byte - Fill 1 fill-byte of next byte FCB $80 ; Fill-Byte - (Solid Black) FCB EOS ; End of String * Strings COMPUTER FCC "COMPUTER" FIRE FCC "FIRE" * This unknown area is referenced from $43EB FCB $00, $45, $00 FCB $74, $00, $89, $00 FCB $D9, $00, $E7, $00 FCB $F2, $01, $00, $00 FCB $FF, $00, $48, $47 FCB $B6, $02, $80 * The Rocket Patrol ship is made up of four parts. * Each part of the ship is 8 bits wide by 16 tall. ROCKET: * Rocket Patrol Ship - 1 of 4 SHIP01: FCB %00000000 FCB %00000000 FCB %00000000 FCB %00000000 FCB %00000000 FCB %00000000 FCB %00000000 FCB %00000011 FCB %00001111 FCB %11111111 FCB %00001111 FCB %00000111 FCB %00000000 FCB %00000000 FCB %00000000 FCB %00000000 * Rocket Patrol Ship - 2 of 4 SHIP02: FCB %11111111 FCB %11000000 FCB %00000000 FCB %00000001 FCB %00000011 FCB %00000111 FCB %00111111 FCB %11111111 FCB %11111111 FCB %11111111 FCB %11111111 FCB %11111111 FCB %00111111 FCB %00000001 FCB %11000000 FCB %11111111 * Rocket Patrol Ship - 3 of 4 SHIP03: FCB %11111111 FCB %00111111 FCB %01111111 FCB %11111110 FCB %11111011 FCB %11111110 FCB %11111011 FCB %11111111 FCB %11111111 FCB %11111111 FCB %11111111 FCB %11111111 FCB %11111111 FCB %11111110 FCB %00111011 FCB %11111111 * Rocket Patrol Ship - 4 of 4 SHIP04: FCB %11110000 FCB %11000000 FCB %11000000 FCB %10000000 FCB %01000000 FCB %10000000 FCB %01000000 FCB %11000111 FCB %10001111 FCB %11111111 FCB %11111000 FCB %11001000 FCB %11000011 FCB %10000000 FCB %10000000 FCB %11110000 FCB $FF, $00 ; BYTES STILL UNKNOWN * Interrupt Vectors FDB $42A4 ; IRQ Interrupt Vector FDB $4000 ; SWI Interrupt Vector FDB $4000 ; NMI Interrupt Vector FDB $4000 ; Reset Interrupt Vector