; POLARIS
; by 'Diminished'
; Vintage Computing Christmas Challenge 2022
; Christmas Star Challenge
; December 2022
; for BBC Micro Model B, with OS 1.2.
; version 1B (return-to-BASIC edition)

; -------------

; assemble using beebasm 1.1: https://github.com/stardot/beebasm/
; this will produce a disc image "polaris.ssd":

; beebasm -v -i polaris_return_to_basic_source.txt -do polaris.ssd

; -------------

; assemble into zero page, and just hope nothing breaks:
ORG &20

; OS "write character" system call entry point:
OSWRCH=&FFEE

; -------------



; How the variables should update:
; -----inc----->   ------dec---->
;  9 10 11 12 13   17 16 15 14 13  Q (t_vdu_buf+4): self-modify INC to DEC, reset to 17 at half-way
; ------------dec--------------->
; 21 20 19 18 17   21 20 19 18 17  M (t_vdu_buf+3): reset at half-way
; ------------inc--------------->
;  5  6  7  8  9    5  6  7  8  9  (26-M) (Y register): reset at half-way



.start

; OS CLS poke, to make CLS (VDU 12) fill a rectangle rather than just clearing it.
; we do this on every ".start" (i.e. on both halves of the star),
; so that we always have 42 in A going into the next step.

LDA #'*'
STA 856

; init M with 21

; note that we can't just start with 21 pre-initialised in t_vdu_buf[4],
; as it must be re-initialised before the second half of the star
; is drawn.

; as luck would have it, 21 is '*' (i.e. 42) >> 1,
; so using LSR saves one byte over the naive LDA #21.

LSR A
STA t_vdu_buf + 4      ; M, master copy

; init 26-M
; this is kept in the Y register, so we can CPY it for the inner loop condition.

LDY #5


; each iteration of P_loop draws a pair of rectangles.
.P_loop

; first VDU sequence.
; draw the vertical rectangle.

LDA #28                ; VDU 28
STA t_vdu_buf + 6

; [5] already contains Q; [4] already contains M.
; we must duplicate Q into [3] as well.

LDA t_vdu_buf + 5      ; t_vdu_buf[3] = t_vdu_buf[5] (Q)
STA t_vdu_buf + 3

STY t_vdu_buf + 2      ; (26-M)

; [1] already contains 12 (CLS) -- it is constant data.

; start reading VDU bytes from t_vdu_buf[6] and working backwards:

LDX #6
JSR S_vdu              ; execute VDU sequence


; second VDU sequence.
; draw the horizontal rectangle.

; [7], [5], [4], [3], [1] are already correctly populated.
; [2] contains junk (prior 26-M value), but we don't care.
; which just leaves [6]:

STY t_vdu_buf + 6      ; (26-M)

; start reading VDU bytes from t_vdu_buf[7] this time:

LDX #7
JSR S_vdu              ; execute VDU sequence


; increment Q.
; after the half way point, this is self-modified from INC to DEC:

.selfmod_inc_to_dec
INC t_vdu_buf + 5

; decrement M.

DEC t_vdu_buf + 4

; increment (26-M).

INY


; have we drawn half a star yet? if not, loop for next two rectangles

CPY #10
BNE P_loop


; reach this point after drawing half a star
; (either first half or second half)

; selfmod Q increment to decrement:

LDA #&C6               ; INC -> DEC
STA selfmod_inc_to_dec

; reset Q to 17
.selfmod_quit
LDA #17                ; the 1B (terminating) version will selfmod this to ORA (17), Y
STA selfmod_quit       ; the selfmod occurs here; next time around, the ORA will be executed instead
STA t_vdu_buf + 5      ; in the second half, this resets Q to gibberish, but it doesn't matter

; begin second half.
; in order to re-initialise M and 26-M,
; we go right back to .start, and run the
; entire thing again from the top.
; (the ORA selfmod happens to give us the flags
;  to terminate after the second iteration):

BPL start

RTS


; -------------


; VDU subroutine
; on entry: X must contain 6 or 7
; on exit: A scribbled, Y untouched, X=&FF

.S_vdu
LDA t_vdu_buf, X
JSR OSWRCH
DEX
BPL S_vdu
RTS



; -------------


; VDU byte buffer
; certain values are pre-initialised:

; - [0]: (constant) undefine text window
; - [1]: (constant) VDU 12 (CLS)
; - [5]: (variable) Q (for first half of star)
; - [7]: (constant) VDU 28 (define text window for horizontal rectangles)

;              <--- bytes sent to OS this way <---

;               [0]  [1]  [2] [3] [4]  [5] [6]   [7]
;                26  12  26-M  q   M    Q   28       ; (for horizontal rectangles)
;           or   26  12  JUNK  q   M    Q   26-M  28 ; (for vertical rectangles)


.t_vdu_buf equb  26, 12,   0,  0,  0,   9,  0,    28

; -------------

.end

print "length:", end-start
SAVE "DEMO2",start,end