Curt Vendel #1 Posted September 11, 2005 .title VCS Skeleton Program .enable ama .asect ;absolute addressing .radix 16 ;default base .LIST MEB ;DISPLAY ALL OF ANY MACROS ; romstr = 0f000 ;rom start addr ; SKLTON.MAC ; copyright Atari, 1982 .nlist .sbttl Stella Hardware Regs .list .page ; * ; ** ;********** ********************************** ;*********** * TIA and PIA Register Addresses * ;********** ********************************** ; ** ; * ; ; TIA Addresses vsync = 00 ;bit 1 vertical sync set-clr 1=>start vblank = 01 ;bit 76 1 vblank set-clr, port ctl (inpt0-5) wsync = 02 ;strobe wait for horiz blank rsync = 03 ;strobe reset horiz sync counter nusiz0 = 04 ;bits 54 210 number-size player/missile 0 nusiz1 = 05 ;bits 54 210 number-size player/missile 1 colup0 = 06 ;bits 7654321 color(4)-lum(3) player 0 colup1 = 07 ;bits 7654321 color(4)-lum(3) player 1 colupf = 08 ;bits 7654321 color(4)-lum(3) playfield colubk = 09 ;bits 7654321 color(4)-lum(3) background ctrlpf = 0a ;bits 54 210 playfield control & ball refp0 = 0b ;bit 3 reflect player 0. 1=>reflect refp1 = 0c ;bit 3 reflect player 1 pf0 = 0d ;bits 7654 playfield reg byte 0 (reversed) pf1 = 0e ;bits all playfield reg byte 1 pf2 = 0f ;bits all playfield reg byte 2 (reversed) resp0 = 10 ;strobe reset player 0 resp1 = 11 ;strobe reset player 1 resm0 = 12 ;strobe reset missile 0 resm1 = 13 ;strobe reset missile 1 resbl = 14 ;strobe reset ball audc0 = 15 ;bits 3210 audio control 0 audc1 = 16 ;bits 3210 audio control 1 audf0 = 17 ;bits 3210 audio frequency 0 audf1 = 18 ;bits 3210 audio frequency 1 audv0 = 19 ;bits 3210 audio volume 0 audv1 = 1a ;bits 3210 audio volume 1 grp0 = 1b ;bits all graphics for player 0 grp1 = 1c ;bits all graphics for player 1 enam0 = 1d ;bit 1 enable missile 0. 1=> enable enam1 = 1e ;bit 1 enable missile 1 enabl = 1f ;bit 1 enable ball hmp0 = 20 ;bits 7654 horiz motion player 0. 0-7 => left hmp1 = 21 ;bits 7654 horiz motion player 1. f-8 => right hmm0 = 22 ;bits 7654 horiz motion missile 0 hmm1 = 23 ;bits 7654 horiz motion missile 1 hmbl = 24 ;bits 7654 horiz motion ball vdelp0 = 25 ;bit 0 vertical delay player 0. 1=> vdel on vdelp1 = 26 ;bit 0 vertical delay player 1 vdelbl = 27 ;bit 0 vertical delay ball resmp0 = 28 ;bit 1 reset missile to player 0 resmp1 = 29 ;bit 1 reset missile to player 1 hmove = 2a ;strobe act on horiz motion hmclr = 2b ;strobe clear all hm registers cxclr = 2c ;strobe clear collision latches ; ; Read Addresses - bits 7 & 6 only cxm0p = 30 ;m0*p1 m0*p0 cxm1p = 31 ;m1*p0 m1*p1 cxp0fb = 32 ;p0*pf p0*bl cxp1fb = 33 ;p1*pf p1*bl cxm0fb = 34 ;m0*pf m0*bl cxm1fb = 35 ;m1*pf m1*bl cxblpf = 36 ;bl*pf cxppmm = 37 ;p0*p1 m0*m1 inpt0 = 38 ;pot 0. bit7=1 => pot cap is charged inpt1 = 39 ;pot 1 inpt2 = 3a ;pot 2 inpt3 = 3b ;pot 3 inpt4 = 3c ;joystick 0 button. b7=0 => button pressed inpt5 = 3d ;joystick 1 button ; ; PIA and Timer (6532) Locations swcha = 280 ;p0,p1 sticks (rldu), pot triggers, kbd, driving ctl ctlswa = 281 ;swcha i/o control 1=output swchb = 282 ;console switches (read only) p1b,p0b,x,x,b/w,x,select, reset ctlswb = 283 ;unused intim = 284 ;interval timer input =>timer up tim1t = 294 ;timer output: 1 mc/tick (.838 microsec) tim8t = 295 ;8 machine cycles/tick tim64t = 296 ;64 mc's/tick t1024t = 297 ;1024 machine cycles/tick (858.2 microseconds) .nlist .sbttl Equates .list .page ; * ; ** ;********** ******************** ;*********** * 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 .nlist .sbttl Ram Variables .list .page ; * ; ** ;********** ***************************** ;*********** * Variables (ram page zero) * ;********** ***************************** ; ** ; * .=80 tcol: .=.+1 ;top score color bcol: .=.+1 ;bottom score color gflg1: .=.+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: .=.+1 ;game number (decimal) gstim: .=.+1 ;game select timer tscr: .=.+2 ;top player's score bscr: .=.+2 ;bottom player's score rand: .=.+1 ;"random" number seed/last number rndind: .=.+1 ;"random" number index frame: .=.+1 ;frame counter hfram: .=.+1 ;hi byte of frame counter atim: .=.+1 ;attract timer atmask: .=.+1 ;attract lum mask t0: .=.+1 ;temporary variables t1: .=.+1 .NLIST .SBTTL MACROS .LIST .PAGE ; * ; ** ;********** ****************** ;*********** * 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 ; ; .nlist .sbttl Initialization .list .page ; * ; ** ;********** ****************** ;*********** * Initialization * ;********** ****************** ; ** ; * .=romstr init: sei ;disable interrupts cld ;binary arithmetic ldx #0 txa sta ctlswa ;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 .nlist .sbttl video kernel .list .page ; * ; ** ;********** **************** ;*********** * Video Kernel * ;********** **************** ; ** ; * kernel: sta wsync ;0 lda #82 ;2 load background color eor atim ;5 comp for attract mode and #0f7 ;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 #0f0 ;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 #0cb ;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 ; .nlist .sbttl Overscan .list .page ; * ; ** ;********** *************************** ;*********** * 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) .nlist .sbttl Vblank Calculations .list .page ; * ; ** ;********** ************************* ;*********** * 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 #0ff ;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 #0f7 ;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 .nlist .sbttl Game Reset/Select .list .page ; * ; ** ;********** ****************************** ;*********** * 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 .nlist .sbttl Assorted Subroutines .list .page ; * ; ** ;********** ************************ ;*********** * 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 .nlist .sbttl Tables .list .page ; * ; ** ;********** ********************** ;*********** * 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 0a0,80 ;gflg1 values after game reset gf1sel: .byte 30,10 ;gflg1 values after game select ; ; copyright notice graphics tables col1: .byte 79,85,0b5,0a5,0b5,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,0c9,49,49,0be col5: .byte 55,55,55,0d9,55,55,99 .page ; * ; ** ;********** ******************************* ;*********** * Fixed (Page-aligned) Tables * ;********** ******************************* ; ** ; * PALIGN ; ; 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,0f0,0e0,0d0,0c0,0b0,0a0,90 .byte 71,61,51,41,31,21,11,01,0f1,0e1,0d1,0c1,0b1,0a1,91 .byte 72,62,52,42,32,22,12,02,0f2,0e2,0d2,0c2,0b2,0a2,92 .byte 73,63,53,43,33,23,13,03,0f3,0e3,0d3,0c3,0b3,0a3,93 .byte 74,64,54,44,34,24,14,04,0f4,0e4,0d4,0c4,0b4,0a4,94 .byte 75,65,55,45,35,25,15,05,0f5,0e5,0d5,0c5,0b5,0a5,95 .byte 76,66,56,46,36,26,16,06,0f6,0e6,0d6,0c6,0b6,0a6,96 .byte 77,67,57,47,37,27,17,07,0f7,0e7,0d7,0c7,0b7,0a7,97 .byte 78,68,58,48,38,28,18,08,0f8,0e8,0d8,0c8,0b8,0a8,98 .byte 79,69,59,49,39,29,19,09,0f9,0e9,0d9,0c9 ; ; End of Memory ; .=0fffc .word init ;start vector .word init .end Quote Share this post Link to post Share on other sites
Cybergoth #2 Posted September 11, 2005 Hi there! ; .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. :-o Greetings, Manuel Quote Share this post Link to post Share on other sites
Cybergoth #3 Posted September 11, 2005 Hi there! Uihjah... Skeleton = 4K-Template Phew... and I thought this were some parts of an unfinished game... Anyway, DASM'd: ; 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 Quote Share this post Link to post Share on other sites