;------------------------------------------------------------------------;
; SPINNER - Pope
;
;    This is a quick little program that spins the BASIC character set
;  using the interrupt.  It is included with CASM Version 1.3, available
;  on the World Wide Web at http://www.cs.wm.edu/~pbgonz/progc64.html,
;  or via Email to Lucas Pope <lupope@vt.edu>
;------------------------------------------------------------------------;


;------------------------------------------------------------------------;
LAYOUT
;------------------------------------------------------------------------;
;
; The BASIC SYS start runs sSetup at $0810, which hooks the user interrupt
; to jump to sSpinner.  Then control is returned to BASIC, and the
; interrupt takes over.

$0801:   dSysStart              ; BASIC start
$0810:   sSetup			; intialization code
	 sSpinner		; interrupt handler
	 dProgVars		; program variables

ENDL

ALIASB CharBackColor 	= $00     	; color of character back
ALIASB CharFrontColor 	= $0e      	; color of character front
ALIASB TurnPause 	= 05      	; pause while letters are turning
ALIASB FlatPause 	= 70      	; pause while letters are flat

ALIASB CountDown 	= $fd	   	; used as a timer

ALIASB Temp1 		= $fb      	; temporary variable 1
ALIASB Temp2 		= $fe      	; temporary variable 2

ALIASB Next 		= $fc      	; stores the turn sequence of
					; the chars

ALIASW kReturnFromInt	= $ea81		; some Kernel code that returns from
					; an interrupt

;------------------------------------------------------------------------;
DATA dProgVars
;------------------------------------------------------------------------;
OldInterrupt:
	0 0
ENDD

;------------------------------------------------------------------------;
DATA dSysStart
;------------------------------------------------------------------------;
;
; The BASIC program looks like this:
;
; 1995 SYS(2064)
;
	       EndOfLine  	; This will store the address of the label
	       1995		; This is a decimal word storing the line #
	       $9E		; Basic "SYS" instruction
	       "(2064)"		; hex address $0810
	       0		; end of BASIC line
EndOfLine:
	       0 0		; end of BASIC program
ENDD


;------------------------------------------------------------------------;
SUB sSetup
;------------------------------------------------------------------------;

Start:    sei
	  lda $0001
	  and #$fb
	  sta $0001
	  ldx #$00
	  ldy #$08
Copy1:    lda $d000,x             ; copying the ROM char mem to 3000 and 2800
	  sta $3000,x
	  sta $2800,x
	  lda $d100,x
	  sta $2900,x
	  sta $3100,x
	  dex
	  bne Copy1

	  lda $0001
	  ora #$04
	  sta $0001

	  ldx #$06
	  lda #$08
Cursor:   sta $2d00,x
	  dex
	  bpl Cursor


	  ldx #$00
Flip:     lda $3000,x             ; flipping chars at 3000 and putting them
	  lsr acc                 ; at 3800
	  rol Temp1
	  lsr acc
	  rol Temp1
	  lsr acc
	  rol Temp1
	  lsr acc
	  rol Temp1
	  lsr acc
	  rol Temp1
	  lsr acc
	  rol Temp1
	  lsr acc
	  rol Temp1
	  lsr acc
	  rol Temp1
	  lda Temp1
	  sta $3800,x
	  lda $3100,x
	  lsr acc
	  rol Temp1
	  lsr acc
	  rol Temp1
	  lsr acc
	  rol Temp1
	  lsr acc
	  rol Temp1
	  lsr acc
	  rol Temp1
	  lsr acc
	  rol Temp1
	  lsr acc
	  rol Temp1
	  lsr acc
	  rol Temp1
	  lda Temp1
	  sta $3900,x
	  dex
	  bne Flip

	  ; Make sure it's not already running:

	  lda dProgVars|OldInterrupt
	  cmp #$00
	  beq NotLoadedYet
	  lda dProgVars|OldInterrupt + 1
	  cmp #$00
	  beq NotLoadedYet

	  cli
	  rts                     ; return to basic


NotLoadedYet:

	  lda $0314			   	; Save the old interrupt:
	  sta dProgVars|OldInterrupt
	  lda $0315
	  sta dProgVars|OldInterrupt + 1

	  lda #<sSpinner|Start	; Set user interrupt to vector through
	  sta $0314		; the sSpinner subroutine:
	  lda #>sSpinner|Start
	  sta $0315

	  lda #$00
	  sta Next
	  lda #$1b
	  sta $d018
	  lda #FlatPause
	  sta CountDown

	  cli
	  rts                     ; return to basic

ENDS


;------------------------------------------------------------------------;
SUB sSpinner
;------------------------------------------------------------------------;
;
; This is just a lot of bit flipping.  I sacrificed some readability to
; have the demo program do something entertaining.
;

Start:    sei
	  dec CountDown
	  bne GoOn           ; jump to normal interrupt if CountDown <> 0
	  lda #TurnPause
	  sta CountDown

	  inc Next

	  lda Next           ; determines which part of the turn the
	  cmp #$04           ; characters are currently in
	  beq ToBlack
	  bcc Go5
	  cmp #$05
	  beq Go1
	  cmp #$06
	  beq Go2
	  cmp #$07
	  beq Flip
	  cmp #$0b
	  beq ToBlue
	  bcc Go5
	  cmp #$0c
	  beq Go3
	  cmp #$0d
	  beq Go4

	  lda #$00
	  sta Next
	  jmp norm
Go1:      jmp eflip1              ; jmp reaches for the branches above
Go2:      jmp eflip2
Go3:      jmp enorm1
Go4:      jmp enorm2
Go5:      jmp squish
GoOn:     jmp (dProgVars|OldInterrupt)

ToBlack:  ldx #$f9
	  lda #CharBackColor
	  sta $0286               ; changes the color to CharBackColor
Loop1:    sta $d800,x
	  sta $d8fa,x
	  sta $d9f4,x
	  sta $daee,x
	  dex
	  cpx #$ff
	  bne Loop1
	  jmp kReturnFromInt

ToBlue:   ldx #$f9
	  lda #CharFrontColor
	  sta $0286               ; changes the color to CharFrontColor
Loop2:    sta $d800,x
	  sta $d8fa,x
	  sta $d9f4,x
	  sta $daee,x
	  dex
	  cpx #$ff
	  bne Loop2
	  jmp kReturnFromInt



norm:     lda #FlatPause
	  sta CountDown
	  ldx #$00
dooper:   lda $3000,x             ; copies norm chars into visible
	  sta $2800,x
	  lda $3100,x
	  sta $2900,x
	  dex
	  bne dooper
	  jmp kReturnFromInt

Flip:     lda #FlatPause
	  sta CountDown
	  ldx #$00
dooper2:  lda $3800,x             ; copies flipped chars into visible
	  sta $2800,x
          lda $3900,x
	  sta $2900,x
          dex
	  bne dooper2
	  jmp kReturnFromInt

                                  ; squishes the visible characters
squish:   ldx #$00
sqshmore: lda $2800,x
          tay
          and #$08
	  sta Temp2
          tya
          asl acc
          and #$0f
	  sta Temp1
          tya
	  lsr acc
	  and #$f0
	  ora Temp1
	  ora Temp2
	  sta $2800,x
	  lda $2900,x
	  tay
	  and #$08
	  sta Temp2
	  tya
	  asl acc
	  and #$0f
	  sta Temp1
	  tya
	  lsr acc
	  and #$f0
	  ora Temp1
	  ora Temp2
	  sta $2900,x
	  dex
	  bne sqshmore
	  jmp kReturnFromInt

enorm1:   ldx #$00                ; copies normal chars into view, squishing
LoopA:    lda $3000,x             ;  them at the same time (squishes less
	  tay                     ;  every time) to make them appear to expand
	  and #$08
	  sta Temp2
	  tya
	  asl acc
	  asl acc
	  and #$0f
	  sta Temp1
	  tya
	  lsr acc
	  lsr acc
	  and #$f0
	  ora Temp1
	  ora Temp2
	  sta $2800,x
	  lda $3100,x
	  tay
	  and #$08
	  sta Temp2
	  tya
	  asl acc
	  asl acc
	  and #$0f
	  sta Temp1
	  tya
	  lsr acc
	  lsr acc
	  and #$f0
	  ora Temp1
	  ora Temp2
	  sta $2900,x
	  dex
	  bne LoopA
	  jmp kReturnFromInt

enorm2:   ldx #$00                 ; same as above only expands less
LoopB:    lda $3000,x
	  tay
	  and #$08
	  sta Temp2
	  tya
	  asl acc
	  and #$0f
	  sta Temp1
	  tya
	  lsr acc
	  and #$f0
	  ora Temp1
	  ora Temp2
	  sta $2800,x
	  lda $3100,x
	  tay
	  and #$08
	  sta Temp2
	  tya
	  asl acc
	  and #$0f
	  sta Temp1
	  tya
	  lsr acc
	  and #$f0
	  ora Temp1
	  ora Temp2
	  sta $2900,x
	  dex
	  bne LoopB
	  jmp kReturnFromInt


eflip1:   ldx #$00                 ; copies flipped characters into view
LoopC:    lda $3800,x              ;  "squishing" them at the same time
          tay
          and #$08
	  sta Temp2
          tya
          asl acc
          asl acc
          and #$0f
	  sta Temp1
          tya
	  lsr acc
          lsr acc
          and #$f0
	  ora Temp1
	  ora Temp2
          sta $2800,x
          lda $3900,x
          tay
          and #$08
	  sta Temp2
          tya
          asl acc
	  asl acc
          and #$0f
	  sta Temp1
          tya
	  lsr acc
	  lsr acc
	  and #$f0
	  ora Temp1
	  ora Temp2
	  sta $2900,x
	  dex
	  bne LoopC
	  jmp kReturnFromInt

eflip2:   ldx #$00                 ; same as above only less
LoopD:    lda $3800,x
          tay
          and #$08
	  sta Temp2
	  tya
          asl acc
	  and #$0f
	  sta Temp1
          tya
          lsr acc
          and #$f0
	  ora Temp1
	  ora Temp2
          sta $2800,x
          lda $3900,x
          tay
          and #$08
	  sta Temp2
	  tya
          asl acc
          and #$0f
	  sta Temp1
          tya
          lsr acc
          and #$f0
	  ora Temp1
	  ora Temp2
          sta $2900,x
          dex
	  bne LoopD
	  jmp kReturnFromInt

ENDS

