NEW AUTO 3,1 .LIST OFF .OP 65C02 .OR $2000 .TF bin/xmastree */------------------------------------- * # XMASTREE * Displays a Christmas Tree of user defined height. Ho Ho Ho. * * ## Arguments * **** * Height of the tree. A positive number up to about 41 is realistic, beyond that you're on your own... * * ## Return Value * N/A * * ### Author * Original algorithm Jan 2012, Brian J. Bernstein. * Updated for A2osx 2021-07-02. *\------------------------------------- .INB inc/macros.i .INB inc/a2osx.i *-------------------------------------- STAR .EQ '*' BLANK .EQ '_' MAX .EQ 30 *-------------------------------------- * Zero Page Segment, up to 32 bytes *-------------------------------------- .DUMMY .OR ZPBIN ZS.START ZPPtr1 .BS 2 ; address pointer (used in arg parsing) ArgIndex .BS 1 ; index offset for argument parsing bSize .BS 2 ; arg variable - size of the tree, though we only use first byte ROW .BS 1 ; current row MARGIN .BS 1 ; number of blanks to chop from margin ZS.END .ED *-------------------------------------- * File Header (16 Bytes) *-------------------------------------- CS.START cld jmp (.1,x) .DA #$61 ; 6502,Level 1 (65c02) .DA #1 ; BIN Layout Version 1 .DA #0 ; Events disabled (enable with S.PS.F.EVENT) .DA #0 .DA CS.END-CS.START ; Code Size (without Constants) .DA DS.END-DS.START ; Data SegmentSize .DA #32 ; Stack Size .DA #ZS.END-ZS.START ; Zero Page Size .DA 0 *-------------------------------------- * Relocation Table *-------------------------------------- .1 .DA CS.INIT .DA CS.RUN .DA CS.DOEVENT .DA CS.QUIT L.MSG.USAGE .DA MSG.USAGE ; msg for usage / help text L.MSG.NEWLINE .DA MSG.MSG.NEWLINE .DA 0 *-------------------------------------- * Called once at process creation * Put code for loading LIB here *-------------------------------------- CS.INIT clc ; nothing to init, so just clc and return rts *-------------------------------------- * Called until exit with CS * if RUN exits with CC, RUN entered again *-------------------------------------- CS.RUN .1 inc ArgIndex ; Check next argument lda ArgIndex >SYSCALL ArgV ; check for an arg at index in A bcs .9 ; If doesn't exist, we're done with args >SYSCALL AToI >STYA bSize .2 jsr CS.RUN.Tree ; build the tree jmp .99 *--- Display usage and error out ------ .9 >PUSHW L.MSG.USAGE ; push address for usage text >PUSHBI 0 >SYSCALL PrintF ; print usage message lda #E.SYN ; set OS return code as Syntax Error sec ; indicate we don't want CS.RUN called again rts ; return to OS *--- Successful exit ------------------ .99 lda #0 ; set OS return code to success sec ; indicate we don't want CS.RUN called again rts ; return to OS *-------------------------------------- * Called if option S.PS.F.EVENT enabled in Header * Timer Event : every 10th seconds *-------------------------------------- CS.DOEVENT sec ; we don't use this since we don't have timer events rts *-------------------------------------- * Called once, when RUN exited with CS * Put code for unloading LIB here *-------------------------------------- CS.QUIT clc ; nothing to do on exit except clear carry and return rts *-------------------------------------- CS.RUN.Tree lda bSize cmp #3 ; did they specify a size of 2? bcs CS.RUN.Start ; if not, go normal tree drawing cmp #2 ; did they specify a size of 2? bcc CS.RUN.Sapling lda #'Y' >SYSCALL PutChar jsr CS.RUN.Newline rts CS.RUN.Sapling lda #'|' >SYSCALL PutChar jsr CS.RUN.Newline rts CS.RUN.Start lda #2 ; start from row 2 sta ROW lda #MAX ; calculate margin chop sec ; SEC before SBC !!! sbc bSize sta MARGIN jsr CS.RUN.Stump ; display a stump first since same as top of tree CS.RUN.Blanks lda #MAX ; calculate number of blanks to tab sec sbc ROW sbc MARGIN tax ; put into x register lda #BLANK ; load blank character jsr CS.RUN.Disp ; display ́x ́ blanks CS.RUN.Stars lda ROW ; calculate number of stars to display asl ; ASL not ROL !!! tax ; put into x register and -2 dex dex lda #STAR ; load star character jsr CS.RUN.Disp ; display ́x ́ stars CS.RUN.Next jsr CS.RUN.Newline ldx ROW ; increment row inx stx ROW cpx bSize ; are we done? bne CS.RUN.Blanks jsr CS.RUN.Stump ; display a stump... rts ; ...and we ́re done CS.RUN.Stump lda #MAX-2 ; calculate number of blanks to place stump sec sbc MARGIN tax lda #BLANK jsr CS.RUN.Disp ; display ́x ́ blanks lda #STAR ; display star as a stump ldy ROW ; unless the tree is only 3 rows tall, cpy #3 ; then give it a much skinnier stump bne .2 lda #'|' ; <-- skinny stump .2 >SYSCALL PutChar jsr CS.RUN.Newline rts CS.RUN.Disp cpx #0 beq .9 .1 pha phx >SYSCALL PutChar plx pla dex ; loop until we decrement X to 0 bne .1 .9 rts CS.RUN.Newline >PUSHW L.MSG.NEWLINE >PUSHBI 0 >SYSCALL PrintF rts *-------------------------------------- CS.END *-------------------------------------- MSG.USAGE .CS "Usage : XMASTREE \r\n" .CZ " size : height of the tree to generate\r\n" MSG.MSG.NEWLINE .CZ "\r\n" *-------------------------------------- * Per Process DATA segment (0 filled before INIT) *-------------------------------------- .DUMMY .OR 0 DS.START DS.END .ED *-------------------------------------- MAN SAVE usr/src/bin/xmastree.s ASM