VCS SKELETON PROGRAM
; COPYRIGHT ATARI, 1982

   PROCESSOR 6502
   INCLUDE VCS.H

; *
; **
;********** ********************
;*********** * ASSORTED EQUATES *
;********** ********************
; **
; *

GSCON   = 45;GAME SELECT TIMER INITIAL VALUE
OVRCON  = $25;OVERSCAN TIMER INITIAL VALUE
VBLCON  = $2B;VBLANK TIMER INITIAL VALUE
GMAX    = $03;HIGHEST GAME # +1

; *
; **
;********** *****************************
;*********** * VARIABLES (RAM PAGE ZERO) *
;********** *****************************
; **
; *

   SEG.U VARS
   ORG $80

TCOL    DS 1   ;TOP SCORE COLOR
BCOL    DS 1   ;BOTTOM SCORE COLOR
GFLG1   DS 1   ;GAME STATUS BITS
              ;80 1= GAME IS IN PLAY
              ;40 1= BONZO (EASY) GAME
              ;20 1= ONE-PLAYER GAME
              ;10 1= SELECT MODE
              ;08 1= COLOR-SHIFTING ATTRACT MODE
              ;04 NOT USED YET
              ;02 NOT USED YET
              ;01 NOT USED YET
GAMNO   DS 1   ;GAME NUMBER (DECIMAL)
GSTIM   DS 1   ;GAME SELECT TIMER
TSCR    DS 2   ;TOP PLAYER'S SCORE
BSCR    DS 2   ;BOTTOM PLAYER'S SCORE
RAND    DS 1   ;"RANDOM" NUMBER SEED/LAST NUMBER
RNDIND  DS 1   ;"RANDOM" NUMBER INDEX
FRAME   DS 1   ;FRAME COUNTER
HFRAM   DS 1   ;HI BYTE OF FRAME COUNTER
ATIM    DS 1   ;ATTRACT TIMER
ATMASK  DS 1   ;ATTRACT LUM MASK
T0      DS 1   ;TEMPORARY VARIABLES
T1      DS 1

;; *
;; **
;;********** ******************
;;*********** * MACROS *
;;********** ******************
;; **
;; *
;;
;; PALIGN WILL AUTOMATICALLY ALIGN FOLLOWING CODE WITH A PAGE VOUNDARY.
;; IT WILL USUALLY BE USED AT THE TOP OF TABLES, SO THAT A TABLE WON'T
;; CROSS A BOUNDARY AND FUCK UP A KERNEL.
;;
;.MACRO PALIGN
;.=<.+0FF>&0FF00
;.ENDM
;;
;;
;; .INTSET ENABLES INTERRUPTS WHEN IN A RAM VERSION, BUT ALLOWS INTERRUPTS
;; TO BE DISABLED IN THE ROMMED VERSION, BY THE USE OF THE TERM ZZZROM.
;; AS LONG AS ZZZROM IS UNDEFINED, INTERRUPTS WILL BE ENABLED, AND A
;; PROGRAM CAN BE HALTED BY CONTROL-C. BEFORE ROMMING THE PROGRAM, MERELY
;; INSERT A DEFINITION FOR ZZZROM, SUCH AS ZZZROM = 1.
;;
;.MACRO .INTSET
;.IF NDF,ZZZROM
;CLI
;.IFF
;SEI
;.ENDC
;.ENDM
;;
;;
;; LINE WILL DECREMENT THE LINE COUNT, IF REQUESTED, WILL SET UP A
;; PLAYER, IF REQUESTED, AND WILL SET UP A MISSILE OR BALL DURING A
;; KERNEL LINE. THE LINE COUNT MAY BE DECREMENTED BY ANY VALUE, SET
;; AS ARGUMENT A1. IF A1 IS ZERO, THAT PART OF THE CODE IS NOT
;; ASSEMBLED. ARGUMENT A2 SPECIFIES THE VERTICAL POSITION OF THE
;; PLAYER, BY NAME OF RAM POSITION WHERE THAT VALUE IS LOCATED. IF
;; THAT ARGUMENT IS SET TO ZERO, THE CODE FOR HANDLING THE PLAYER
;; IS LEFT OUT.
;;
;; THERE ARE EIGHT ARGUMENTS, BUT A8 MUST NOT BE SPECIFIED WHEN
;; INVOKING THE MACRO. IT IS A DUMMY FOR CREATING A JUMP ADDRESS.
;; THE OTHERS MUST BE USED, AT LEAST TO THE POINT OF PUTTING IN A
;; COMMA AS A PLACE-HOLDER. THE ARGUMENTS AND THEIR MEANINGS ARE:
;;
;; A1 LINE COUNT DECREMENT AMOUNT (USUALLY 1 OR 2; IF 0, CODE IS
;; SKIPPED)
;; A2 NAME OF RAM LOCATION FOR VERT. POSITION OF A PLAYER. IF 0,
;; CODE FOR PLAYER SETUP IS LEFT OUT
;; A3 PLAYER'S HEIGHT
;; A4 NAME OF PLAYER'S GRAPHICS TABLE
;; A5 NAME OF A TEMPORARY STORAGE LOCATION FOR THAT PLAYER'S GRAPHICS
;; A6 NAME OF LOCATION FOR MISSILE'S OR BALL'S VERTICAL POSITION
;; A7 HEIGHT OF MISSILE OR BALL
;; A8 DUMMY JUMP ADDRESS -- DON'T PUT A VALUE IN FOR THIS ARGUMENT!!!
;;
;; AN EXAMPLE FOR THE FIRST LINE OF A DOUBLE-LINE KERNEL MIGHT BE:
;;
;; LINE 2,VP0,8,P0TAB,GP0,VM0,14.
;;
;; THE SECOND LINE OF THE KERNEL MIGHT LOOK LIKE:
;;
;; LINE 0,VP1,10.,P1TAB,GP1,VBL,4
;;
;; A LINE WITH NO PLAYER MIGHT BE CALLED AS FOLLOWS:
;;
;; LINE 1,0,,,,VM1,6
;;
;; NOTE THAT ALL NUMERIC VALUES ARE IN HEX, AND DECIMAL VALUES MUST END
;; WITH A DOT. THIS MACRO USES THE ACCUMULATOR AND Y REGISTER, BUT LEAVES
;; THE X REGISTER FREE.
;;
;; THE RESULTS OF THIS MACRO MUST BE INVOKED AT THE START OF THE NEXT LINE,
;; PROBABLY IMMEDIATELY AFTER AT STA WSYNC, OR AFTER STA WSYNC, STA HMOVE.
;; IF THE PLAYER GRAPHICS HAS BEEN STORED IN GP1, FOR INSTANCE, AND YOU
;; ARE ABOUT TO PUT UP THAT PLAYER AND THE BALL, AS IN THE SECOND EXAMPLE
;; ABOVE, YOU WOULD PUT IN CODE:
;; STY ENABL
;; LDY GP1
;; STY GRP1
;; AND THEN CONTINUE WITH REST OF CODE FOR THAT LINE. THERE SHOULD BE
;; ENOUGH TIME TO GET A PLAYFIELD STARTED, BUT DON'T DECREMENT LINE
;; COUNTS WHERE THERE WILL BE NEW PLAYFIELD. THERE ISN'T ENOUGH TIME.
;; PUT A 0 IN A1 FOR THOSE LINES, IN A TWO-LINE KERNEL, AND PUT A 2 IN
;; A1 ON THE NEXT LINE, WHERE THERE WILL BE MORE TIME.
;;
;; THE ROUTINE WALKS DOWN THROUGH THE PLAYER GRAPHICS TABLE AS IT MOVES
;; DOWN THE SCREEN, SO THE FIRST VALUE OF THE TABLE SHOULD BE 0, TO SET
;; THAT VALUE INTO THE GRAPHICS STORE LOCATION WHEN THE PLAYER ISN'T TO
;; APPEAR.
;;
;.MACRO LINE A1,A2,A3,A4,A5,A6,A7,?A8
;.IF NE,A2
;LDA A2
;SEC
;SBC LNCNT
;CMP #A3
;BCS A8
;TAY
;LDA A4(Y)
;STA A5
;.ENDC
;A8: LDY #0
;LDA LNCNT
;SEC
;.IF NE,A1
;SBC #A1
;STA LNCNT
;.ENDC
;SBC A6
;CMP #-A7
;BCC .+4
;LDY #2
;.ENDM
;;

; *
; **
;********** ******************
;*********** * INITIALIZATION *
;********** ******************
; **
; *


   SEG Bank0
   ORG $F000
START
   SEI;DISABLE INTERRUPTS
   CLD;BINARY ARITHMETIC
   LDX #0
   TXA
   STA SWACNT;SET PORTA FOR INPUT
10$: STA 0,X;CLEAR HARDWARE REGISTERS AND RAM
   INX
   BNE 10$
   DEX;FF
   STX GFLG1;SET SELECT MODE FLAG
   TXS;INIT STACK PTR
;
; PERFORM A GAME SELECT, GAME # 1
;
   JSR INITSL;SIMULATE SELECT LEVER PRESS
;
; END OF INITIALIZATION
;
   JMP OVERSC;GO START WITH OVERSCAN

; *
; **
;********** ****************
;*********** * VIDEO KERNEL *
;********** ****************
; **
; *


KERNEL: STA WSYNC;0
   LDA #$82;2 LOAD BACKGROUND COLOR
   EOR ATIM;5 COMP FOR ATTRACT MODE
   AND #$F7;7
   STA COLUBK;10
   LDX #180;12 LOAD NUMBER OF LINES
10$: STA WSYNC;0 FINISH THE LINE
   DEX;2 DONE?
   BNE 10$;4,5 NO, GO
   LDA GFLG1;7 ARE WE IN SELECT MODE?
   AND #$10;9
   BNE COPY;11,12 YES, GO DO COPYRIGHT NOTICE
   LDX #$11;13 LOAD NUMBER OF LINES
20$: STA WSYNC;0 END THE LINE
   DEX;2 DONE?
   BNE 20$;4,5 NO, GO
   JMP OVERSC;7 YES, EXIT
;
; DISPLAY COPYRIGHT NOTICE
;
COPY: STA WSYNC;0 SYNC UP
   STX PF0;3 CLEAR PLAYFIELD REGS
   STX PF1;6
   STX PF2;9
   NOP;11 WASTE SOME CYCLES
   STA T0;14 WASTE SOME MORE
   LDA BCOL;17 SET UP PLAYER COLOR
   EOR ATIM;20 ADJUST FOR ATTRACT COLORS
   AND ATMASK;23 ENSURE LOW LUM IF ATTRACT COLORS
   STA COLUP0;26
   STA COLUP1;29
   NOP;31 WASTE 2 CYCLES HERE
   LDA #$F0;33 SET UP FINE POSITIONING IN ADVANCE
   STA HMP0;36
   LDX #0;38
   STX HMP1;41
   STA RESP0;44 RESET PLAYER ZERO...
   STA RESP1;47 ...AND PLAYER ONE
   STA WSYNC;0
   STA HMOVE;3 EXECUTE FINE ADJUSTMENT
   LDA #$CB;5 SET NUSIZ FOR SMALL PLAYERS
   STA NUSIZ0;8 AND PROPER NUMBER OF COPIES
   LDX #1;10
   STX NUSIZ1;13
; DO DISPLAY
   LDX #$07;15 FOR 8 LINES OF THE SCREEN...
1$: STX T1;18,66 SAVE INDEX BECAUSE X IS USED LATER
   STA WSYNC;0
   LDY #2;2 TIME OUT TO CENTER OF SCREEN
   DEY;4;9
   BNE .-1;7;11
   STA T0;14 WASTE 3 CYCLES TO GET TIMING RIGHT
   LDA COL1-1,X;18 GET GRAPHICS FOR FIRST STORE
   STA GRP0;21 STORE IT
   LDA COL2-1,X;25 SAME FOR P1
   STA GRP1;28
   LDY COL3-1,X;32 NOW GET TRICKY TO SAVE TIME...
   LDA COL4-1,X;36 USE X AND Y AND A TO THEIR FULLEST
   STA T0;39 USE TEMP 0 ALSO FOR TIME SAVINGS
   LDA COL5-1,X;43 NOW LOAD UP ALL 3 REGS
   LDX T0;46
   STY GRP0;49 AND STORE 'EM AS FAST AS POSSIBLE
   STX GRP1;52 (TIMING IS VERY CRUCIAL HERE)
   STA GRP0;55
   LDX T1;58 NOW RESTORE INDEX
   DEX;60
   BNE 1$;62,63 AND BRANCH BACK TILL DONE
   STX GRP0;65 CLEAR PLAYER GRAPHICS FOR NEATNESS
   STX GRP1;68
   STA WSYNC;0 DISPLAY TWO BLANK LINES
   STA WSYNC;0 (BOTTOM MARGIN)
   JMP OVERSC
;
; END OF KERNEL
;

; *
; **
;********** ***************************
;*********** * OVERSCAN: 30 SCAN LINES *
;********** ***************************
; **
; *


;
; TIE UP SCREEN LOOSE ENDS
;
OVERSC: LDX #0
   STX COLUBK;TURN OFF BACKGROUND
   LDA #OVRCON;SET UP OVERSCAN TIMER
   STA TIM64T
   LDA #$82;TURN ON VBLANK, GROUND THE POTS
   STA VBLANK
;
; UPDATE FRAME COUNTER
;
   INC FRAME
   BNE 10$;GO IF NO OVERFLOW
   INC HFRAM
   LDA #$30;TIME TO GO INTO ATTRACT?
   CMP HFRAM
   BNE 10$;NO, GO
   LDA GFLG1;YES, SET THE FLAG
   ORA #$08
   STA GFLG1
10$:
;
; CHECK FOR RESET/GAME SELECT
;
   JSR GSRST;CHECK LEVERS...
   BCS 99$;IF LEVER WAS PRESSED...
   JMP INTST;SKIP GAME PLAY THIS FRAME
99$:
;
;
;********************************************
; PUT OVERSCAN CALCS HERE *
;********************************************
;
;
;
; END OF OVERSCAN
;
INTST:
   LDX INTIM;OVERSCAN DONE YET?
   BNE INTST;NO, GO BACK
VSNC: LDX #$02;YES, DO VSYNC
   STX VSYNC
   STA WSYNC;SEND 4 LINES OF VSYNC
   STA WSYNC
   STA WSYNC
   STA WSYNC
   LDA #0
   STA VSYNC;TURN OFF VSYNC (A=0)

; *
; **
;********** *************************
;*********** * VBLANK: 37 SCAN LINES *
;********** *************************
; **
; *


;
; START VBLANK TIMER
;
VBLNK: LDA #VBLCON;SET UP VBLANK TIMER
   STA TIM64T
;
;
;********************************************
; PUT VBLANK CALCS HERE *
;********************************************
;
;
; COLOR-SHIFT ATTRACT MODE
;
SHFT: LDY #$FF;ASSUME NO ATTRACT MASK
   LDA GFLG1;ARE WE IN COLOR ATTRACT?
   AND #$08
   BNE 5$;YES, GO
   STA ATIM;NO, RESET ATTRACT SHIFT KEY TO ZERO
   BEQ 99$;ALWAYS TAKEN
5$: LDY #$F7;LOAD ATTRACT MASK
   LDA FRAME;IS IT TIME TO SHIFT?
   BNE 99$;NO, GO
   INC ATIM;SET NEW COLOR-SHIFT MASK
99$: STY ATMASK;STORE CURRENT LUM MASK
;
; END OF VBLANK
;
INTST2:
   LDA INTIM;DONE WITH VBLANK YET?
   BNE INTST2;NO, GO BACK
   STA WSYNC;YES, GET READY FOR KERNEL
   STA VBLANK;TURN OFF VBLANK, AND START CHARGING POTS
   STA HMCLR;RESET HORIZ. MOTION REGS TO 0
   STA CXCLR;CLEAR COLLISIONS
   JMP KERNEL;GO FOR IT

; *
; **
;********** ******************************
;*********** * GAME SELECT AND GAME RESET *
;********** ******************************
; **
; *


; CHECK TO SEE IF GAME SELECT OR GAME RESET LEVERS ARE BEING
; PRESSED. IF YES, THEN CHECK TO SEE IF TIME-OUT HAS OCCURRED. IF
; YES, THEN EXECUTE THE FUNCTION. OTHERWISE RETURN WITH CARRY SET,
; INDICATING THAT NO ACTION WAS TAKEN. IF GAME SELECT OR RESET DID
; TAKE PLACE, RETURN WITH CARRY CLEAR, SO THAT THE OVERSCAN CALCS WILL
; BE SKIPPED (RESET OR SELECT USUALLY TAKES A LONG TIME TO DO).
GSRST: LDA SWCHB;READ CONSOLE SWITCHES
   ROR
   BCC GRS;GO IF RESET LEVER PRESSED
GS2: ROR
   BCC GSEL;GO IF GAME SELECT LEVER PRESSED
   LDX #1
   STX GSTIM
GSEX: SEC
   RTS;RTS WITH CARRY SET MEANS NO ACTION
;
; GAME SELECT
GSEL: DEC GSTIM;TIME TO EXECUTE?
   BNE GSEX;NO, GO
INITSL: LDA #$2D;RESET TIMER
   STA GSTIM
   LDA GFLG1;ARE WE IN SELECT MODE?
   AND #$10
   BEQ 12$;NO, DON'T INC GAME NUMBER
   SED;NEW GAME NUMBER
   LDA GAMNO
   CLC
   ADC #1;ADD 1 TO OLD NUMBER
   CMP #GMAX;TOO HIGH?
   BNE 10$;NO, SKIP RESET
   LDA #1;YES, RESET TO 1
10$: STA GAMNO
   CLD;RESTORE BINARY FUNCTIONING
;***************************************
; PUT GAME SELECT LOGIC HERE *
;***************************************
12$: LDX GAMNO;SET GFLG1 FROM TABLE
   LDA GF1SEL-1,X
   STA GFLG1
   BNE GSRS;ALWAYS TAKEN
;
; GAME RESET
GRS: DEC GSTIM;TIME TO EXECUTE?
   BNE GSEX;NO, EXIT
   LDX #$10;RESET TIMER
   STX GSTIM
   LDX GAMNO;SET GFLG1 FROM TABLE
   LDA GF1RST-1,X
   STA GFLG1
;**************************************
; PUT GAME RESET LOGIC HERE *
;**************************************
   LDX #0;RESET SCORES
   STX TSCR
   STX TSCR+1
   STX BSCR
   STX BSCR+1
;
; BOTH FUNCTIONS
GSRS: LDA #$05;SET UP HARDWARE
   STA NUSIZ0
   STA NUSIZ1
   LDA #$21
   STA CTRLPF
   LDA #4
   STA AUDC0
   STA CXCLR
   LDA #0
   STA HFRAM;TURN OFF COLOR ATTRACT
   LDX #1;SET UP SCREEN COLORS
20$: LDA MISC,X
   STA TCOL,X
   DEX
   BPL 20$
99$: CLC;RETURN WITH CLEAR CARRY
   RTS

; *
; **
;********** ************************
;*********** * ASSORTED SUBROUTINES *
;********** ************************
; **
; *


;
; "RANDOM" NUMBER ROUTINE
;
; RETURNS A "RANDOM" NUMBER IN THE ACCUMULATOR. IF IT DOESN'T
; SEEM VERY RANDOM TRY PLAYING AROUND WITH THE BASE ADDRESS OF THE FIRST
; TWO EXCLUSIVE OR'S... FIND VERY VARIED PIECES OF YOUR PROGRAM TO USE,
; AND IT SHOULD RETURN VERY UNPREDICTABLE RESULTS. ANOTHER TRICK IS TO
; SOMEHOW DO AN EOR WITH YOUR GAME CONTROLLERS... THIS IS ABOUT
; AS RANDOM AS DATA CAN GET, AND USUALLY MAKES A DIFFERENCE.
RNDNO: LDA RAND;GET SEED (LAST NUMBER)
   LDX RNDIND;AND INDEX
   EOR OVERSC,X;"RANDOMIZE"
   EOR KERNEL,X
   ASL;ROTATE TO AVOID SINGLE-BIT
   ADC #0;STATE PREFERENCES
   INX
   STX RNDIND;SAVE NEW INDEX
   EOR HFRAM;AND USE FRAME COUNTER FOR
   EOR FRAME;LONG REPEAT TIME
   STA RAND;SAVE NEW SEED
   RTS;EXIT
;
; SCORE ADDITION ROUTINE
;
; ADDS VALUE FOUND IN ACCUMULATOR TO THE PLAYER WHOSE OFFSET IS IN
; Y-REG. KEEP IN MIND THAT PLAYER ZERO SHOULD BE Y-REG = 0 AND PLAYER
; ONE SHOULD BE Y-REG = 2. ALSO, REMEMBER THE AMOUNT TO ADD (IN THE ACC.)
; SHOULD BE A DECIMAL NUMBER. THIS ROUTINE ALLOWS FOUR DECIMAL DIGITS
; OF SCORE FOR EACH PLAYER.
ADSCR: SED;ADD TO SCORE OF A PLAYER
   CLC
   ADC TSCR+1,Y
   STA TSCR+1,Y
   TXA
   ADC TSCR,Y
   STA TSCR,Y
   CLD
   RTS

; *
; **
;********** **********************
;*********** * RELOCATABLE TABLES *
;********** **********************
; **
; *


MISC: .BYTE $7C,$46;MISC INFORMATION FOR INITIALIZATION
;
; FRCMOV IS A TABLE USED FOR SMOOTH MOVEMENT OF OBJECTS AT
; FRACTIONAL SPEEDS. TO USE IT, ASSUME SPEED BYTE IS XXXX.XXXX
; (IN PIXELS PER FRAME) AND DO THE FOLLOWING:
; LDA #0;INIT NUMBER OF PIXELS TO MOVE TO 0
; STA T0
; LDA FRAME;GET FRAME NUMBER
; AND #$0F;USE ONLY LOW NYBBLE
; TAY;INDEX INTO FRCMOV
; LDA FRCMOV,Y;GET TABLE VALUE
; AND SPEED;TIME TO LET FRACTIONAL SPEED OVERFLOW
;;INTO A PIXEL MOVEMENT?
; BEQ 10$;NO, SKIP IT
; INC T0;YES, T0 IS NOW 1
;10$: LDA SPEED;GET SPEED AGAIN
; LSR;SHIFT OUT FRACTIONAL PORTION
; LSR
; LSR
; LSR
; CLC;ADD TO OVERFLOW FROM FRACTIONAL PART
; ADC T0
;
; ACCUMULATOR NOW CONTAINS THE NUMBER OF PIXELS TO MOVE THIS FRAME.
FRCMOV: .BYTE 1,8,4,8,2,8,4,8,0,8,4,8,2,8,4,8
GF1RST: .BYTE $A0,$80;GFLG1 VALUES AFTER GAME RESET
GF1SEL: .BYTE $30,$10;GFLG1 VALUES AFTER GAME SELECT
;
; COPYRIGHT NOTICE GRAPHICS TABLES
COL1: .BYTE $79,$85,$B5,$A5,$B5,$85,$79
COL2: .BYTE $17,$15,$15,$77,$55,$55,$77
COL3: .BYTE $71,$41,$41,$71,$11,$11,$70
COL4: .BYTE $49,$49,$49,$C9,$49,$49,$BE
COL5: .BYTE $55,$55,$55,$D9,$55,$55,$99

; *
; **
;********** *******************************
;*********** * FIXED (PAGE-ALIGNED) TABLES *
;********** *******************************
; **
; *

   ALIGN 256

;
; HMVTAB CONTAINS RESET COUNTS AND HMOVE VALUES FOR OBJECTS ON THE
; SCREEN. TO USE IT, DO THE FOLLOWING (THIS EXAMPLE POSITIONS THE BALL):
;
; LDA POSN;GET HORIZONTAL POSITION OF BALL
; STA WSYNC;0 SYNC UP FOR RESET LINE
; TAX;2 INDEX INTO HMVTAB
; LDA HMVTAB,X;6 GET TABLE VALUE
; STA HMBL;9 SET HMOVE VALUE FROM HIGH NYBBLE
; AND #$0F;11 KEEP LOW NYBBLE FOR TIME LOOP
; TAY;13 TFR TO Y FOR LOOP
; NOP;15 WASTE 2 CYCLES
; DEY;17;22 ETC. TIMING LOOP
; BPL .-1;20;25 ETC.
; STA RESBL;SET THE BALL'S POSITION RIGHT HERE
; STA WSYNC;FINISH THE LINE
; STA HMOVE;EXECUTE THE FINE POSITIONING HMOVE
;
; REMEMBER, HMVTAB MUST NOT CROSS A PAGE BOUNDARY, BECAUSE IF IT DOES
; IT COULD CAUSE THE INSTRUCTION "LDA HMVTAB,X" TO TAKE 5 CYCLES INSTEAD OF
; 4, AND THAT WOULD THROW OFF THE TIMING OF THE RESET LINE.
HMVTAB:
   .BYTE $60,$50,$40,$30,$20,$10,$00,$F0,$E0,$D0,$C0,$B0,$A0,$90
   .BYTE $71,$61,$51,$41,$31,$21,$11,$01,$F1,$E1,$D1,$C1,$B1,$A1,91
   .BYTE $72,$62,$52,$42,$32,$22,$12,$02,$F2,$E2,$D2,$C2,$B2,$A2,92
   .BYTE $73,$63,$53,$43,$33,$23,$13,$03,$F3,$E3,$D3,$C3,$B3,$A3,93
   .BYTE $74,$64,$54,$44,$34,$24,$14,$04,$F4,$E4,$D4,$C4,$B4,$A4,94
   .BYTE $75,$65,$55,$45,$35,$25,$15,$05,$F5,$E5,$D5,$C5,$B5,$A5,95
   .BYTE $76,$66,$56,$46,$36,$26,$16,$06,$F6,$E6,$D6,$C6,$B6,$A6,96
   .BYTE $77,$67,$57,$47,$37,$27,$17,$07,$F7,$E7,$D7,$C7,$B7,$A7,97
   .BYTE $78,$68,$58,$48,$38,$28,$18,$08,$F8,$E8,$D8,$C8,$B8,$A8,98
   .BYTE $79,$69,$59,$49,$39,$29,$19,$09,$F9,$E9,$D9,$C9

;
; END OF MEMORY
;
   ORG $FFFC
   .WORD START
   .WORD START
