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>**
* 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        ; CC if < 3 !!! if not, go normal tree drawing

                cmp #2                  ; did they specify a size of 2?
                bcc CS.RUN.Sapling		; CC if < 2 !!!

                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
                clc
				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					; -1 !!! not -2
                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 <size>\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
