; File name:     COLOURS.S        Revised:       1990.12.13
; Revised by:    U.R. Andersson   ASSEMPRO'ed:   1990.12.09
; Created by:    Adam Greenwood   Created:       1989.xx.xx
;
; System variables for interrupts
;
EV_KEYHND = $118        ; Key handler vector
EV_HBLANK = $120        ; Hblank vector
VBLNO     = $454        ; No of Vblank routines
VBLQU     = $456        ; Vblank queue
;
DUMMYLONG = $00800000   ; Dummy to force long abs references
;
;
; MFP 68901 Addresses
;
IEA     =       $FFFA07      ; Interrupt Enable A
IEB     =       $FFFA09      ; Interrupt Enable B
ISRA    =       $FFFA0F      ; In Service A
IMA     =       $FFFA13      ; Interrupt Mask A
TBCR    =       $FFFA1B      ; Timer B Control
TBDR    =       $FFFA21      ; Timer B Data
;
;
; Start of program
;
START:
  BSR     INIT          ; Set everything up
  ST      FLASHFLG
WAITKEY:
  CLR.W   D0
  MOVE.W  #7,-(A7)      ; Raw input call
  TRAP    #1
  ADDQ    #2,A7
  CMP.B   #'Q',D0
  BEQ     FIN
  CMP.B   #'q',D0
  BEQ     FIN
  CMP.B   #$1B,D0
  BEQ     FIN
  CMP.B   #' ',D0
  BEQ     HALTFLASH
  CMP.B   #'0',D0
  BLO     NOTLOCKZ
  CMP.B   #'9',D0
  BLS     SETLOCKZ
  CMP.B   #'A',D0
  BLO     NOTLOCKZ
  CMP.B   #'F',D0
  BLS     SETLOCKU
  cmp     #'a',d0
  blo     notlockz
  cmp     #'f',d0
  bls     setlockl
NOTLOCKZ:
  cmp     #'x',d0
  beq     rot_on_x
  cmp     #'X',d0
  beq     rot_on_x
  cmp     #'y',d0
  beq     rot_on_y
  cmp     #'Y',d0
  beq     rot_on_y
  cmp     #'z',d0
  beq     rot_on_z
  cmp     #'Z',d0
  beq     rot_on_z
  BRA     WAITKEY
;
;
rot_on_z:
  move.l  x_palptr(pc),d0
  move    x_palmask(pc),d1
  move.l  y_palptr(pc),x_palptr
  move    y_palmask,x_palmask
  move.l  d0,y_palptr
  move    d1,y_palmask
  move.l  x_palptr(pc),a6    ; Load new initial palette
  BSR     RESTPAL
  bra     waitkey
;
;
rot_on_y:
  move.l  x_palptr(pc),d0
  move    x_palmask(pc),d1
  move.l  z_palptr(pc),x_palptr
  move    z_palmask,x_palmask
  move.l  d0,z_palptr
  move    d1,z_palmask
  move.l  x_palptr(pc),a6    ; Load new initial palette
  BSR     RESTPAL
  bra     waitkey
;
;
rot_on_x:
  move.l  y_palptr(pc),d0
  move    y_palmask(pc),d1
  move.l  z_palptr(pc),y_palptr
  move    z_palmask,y_palmask
  move.l  d0,z_palptr
  move    d1,z_palmask
  bra     waitkey
;
;
HALTFLASH:
  TST.B   FLASHFLG
  SEQ     FLASHFLG
  BRA     WAITKEY
;
;
setlockl:
  sub.b   #'a'-'A',d0
SETLOCKU:
  SUBQ.B  #'A'-'9'-1,D0
SETLOCKZ:
  SUB.B   #'0',D0
  EXT.W   D0
  LSL     #4,D0
  MOVE    D0,z_count
  CLR.B   FLASHFLG
  BRA     WAITKEY
;
;
; Subroutine to make any necessary calls to the OS
;
INIT:
  MOVE    #4,-(SP)      ; Get screen resolution
  TRAP    #14
  ADDQ    #2,SP
  MOVE    D0,ENTRYREZ
  BEQ.S   INIT_1
  CLR     -(SP)
  MOVE.L  #-1,-(SP)
  MOVE.L  #-1,-(SP)
  MOVE    #5,-(SP)
  TRAP    #14
  ADD     #12,SP
INIT_1:
  CLR.L   -(SP)        ; Set supervisor mode
  MOVE    #32,-(SP)
  TRAP    #1
  ADDQ    #6,SP
  MOVE.L  D0,OL_STK     ; Save value of old stack
;
  MOVE    #-1,-(SP)    ; Turn cursor off
  MOVE    #0,-(SP)
  MOVE    #21,-(SP)
  TRAP    #14
  ADDQ    #6,SP
;
  MOVE    #3,-(SP)
  TRAP    #14           ; Get screen Logbase address
  ADDQ    #2,SP         ; and save in SCRAD
  MOVE.L  D0,SCRAD
;
  LEA     OLDPAL(PC),A6     ;   Save old palette
  BSR     SAVEPAL
;
  move.l  #redpaltb,x_palptr
  move.l  #blupaltb,y_palptr
  move.l  #grnpaltb,z_palptr
  move    #$f0ff,x_palmask
  move    #$fff0,y_palmask
  move    #$ff0f,z_palmask
  clr     z_dir         ; Set z_pal step direction for increase
  clr     z_count       ; Set counter for z_pal to 0
  move.l  x_palptr(pc),a6    ; Load new initial palette
  BSR     RESTPAL
;
  MOVE.L  SCRAD(PC),A0       ; Copy to screen (LOGBASE)
  LEA     LINES(PC),A2       ; from predefined block
  add     #2*160,a0     ;skip top margin, 1 line, for alignment
  MOVE.L  #192-1,D0     ; Prep for 16 groups of 12 lines
SETSC:
  MOVE.L  A2,A1         ; Use same pattern on each line
  ADD     #32*8/16,A0   ; Pass left margin
  MOVE.L  #256/16-1,D1  ; Prep for 16 groups of 16 pix
SETLN:
  MOVE.L  (A1)+,(A0)+   ; 2 msb of 16 pix
  MOVE.L  (A1)+,(A0)+   ; 2 lsb of 16 pix
  DBRA    D1,SETLN      ; Loop to make visible line
  ADD     #32*8/16,A0   ; Pass right margin
  DBRA    D0,SETSC      ; Loop to make 192 lines
;
  MOVE.L  EV_KEYHND,OL_KEYHND          ;Save old key handler vector
  MOVE.L  EV_KEYHND,OLDKEYHND+2        ;Link new key handler to old
  MOVE.L  #NEWKEYHND,EV_KEYHND     ;Activate new key handler
;
  CLR.L   D0
  MOVE    VBLNO,D0      ; Get old number of Vblank routines
  MOVE    D0,D1
  MOVE    D0,OLDVBN     ; Save old number
  MOVE.L  VBLQU,A0      ; Get old Vblank Queue address
  MOVE.L  A0,OLDVBQ     ; Save old address
  LEA     NEWQU,A1
  SUBQ    #1,D0
  BMI.S   DONEQU
COPYQU:
  MOVE.L  (A0)+,(A1)+   ; Copy old queue into our new one
  DBRA    D0,COPYQU
DONEQU:
  MOVE.L  #NEWQU,VBLQU  ; Set our queue as new one
  MOVE.L  #VBL_RTN,(A1)+     ; Add new routine to queue
  ADDQ    #1,D1
  MOVE    D1,VBLNO      ; Add one to number of routines
;
  LEA     OLDMK(PC),A0
  MOVE.B  IEB,(A0)+     ; Save old Interrupt register values
  MOVE.B  IEA,(A0)+
  MOVE.B  IMA,(A0)+
;
  MOVE.L  EV_HBLANK,OL_HBLANK     ;Save old HBLANK vector
;
  AND.B   #$DF,IEB      ; Disable 200Hz Interrupt
  AND.B   #$FE,IEA      ; Disable Hblank Interrupt
;
  MOVE.L  #HBL_RTN,EV_HBLANK  ; Activate new HBLANK vector
;
  OR.B    #1,IEA        ; Re-enable Hblank interrupt
  OR.B    #1,IMA
  RTS
;
; New key handling routine to stop mouse disrupting display
;
NEWKEYHND:
  MOVE.W  #$2500,SR
OLDKEYHND:
  JMP     DUMMYLONG     ; Jump to old routine
;
;
; Vblank routine which is added to queue and called every Vblank
VBL_RTN:
  MOVE.B  #0,TBCR       ; Stop timer
  MOVE.B  #12,TBDR      ; Set lines per HBLANK interrupt
  MOVE.B  #8,TBCR       ; Start timer
  MOVE    z_count(PC),D0
  LSR     #4,D0         ; D0 = number (0..15) of next entry
  move.l  z_palptr(pc),a5
  LSL     #1,D0         ; D0 = offset to next z_pal palette entry
  MOVE    (A5,D0),D7
  move    z_palmask(pc),d0
  and     y_palmask(pc),d0
  move.l  palad(pc),a6
  add     #16*2,a6
  move    #16-1,d2
SETZPAL:
  MOVE    -(A6),D6      ; D6 = old RGB mix
  and     d0,d6         ;set y_pal & z_pal to zero
  or      d7,d6         ;then include new z_pal
  MOVE    D6,(A6)       ; store new RGB mix
  DBRA    D2,SETZPAL
  bsr     emurestpal
  TST.B   FLASHFLG
  BEQ.S   NOFLASH
  MOVE    z_count(PC),D1
  TST.B   z_dir         ; Check for direction
  BNE     GDWN
  ADDQ    #1,D1         ; If up add 1 to counter
  CMP     #240,D1       ; and check for end of list
  BNE.S   NEWZOK
  st      z_dir         ; If end change direction
  BRA     NEWZOK
;
GDWN:
  SUBQ    #1,D1         ; If down decrement counter
  BNE     NEWZOK
  sf      z_dir         ; If start change direction
NEWZOK:
  MOVE    D1,z_count    ; Save new value of counter
NOFLASH:
  MOVE    #1,y_count    ; Set y_pal counter to second palette
  RTS
;
;
; HBlank routine called every 12 lines
HBL_RTN:
  movem.l d0-d3/a6,-(sp)
  move    y_count(pc),d0
  addq    #1,y_count
  and     #$F,d0
  lsl     #1,d0
  move.l  y_palptr(pc),a6
  add     d0,a6
  move    (a6),d0
  move    d0,d1
  swap    d0
  move    d1,d0
  move    y_palmask,d1
  swap    d1
  move    y_palmask,d1
  move.l  palad(pc),a6
  add     #16*2,a6
  move    #16/2-1,d3
setpal_y:
  move.l  -(a6),d2
  and.l   d1,d2
  or.l    d0,d2
  move.l  d2,(a6)
  dbra    d3,setpal_y
  bsr     emurestpal
  BCLR    #0,ISRA       ; Re-enable lower level interupts
  movem.l (sp)+,d0-d3/a6
  rte
;
;
; Routine to make a controlled exit, restoring anything we have
; changed and returning to desktop
FIN:
  MOVE.L  OL_KEYHND(PC),EV_KEYHND
  MOVE.L  OL_HBLANK(PC),EV_HBLANK
  LEA     OLDMK(PC),A0      ; Restore MFP registers
  MOVE.B  (A0)+,IEB
  MOVE.B  (A0)+,IEA
  MOVE.B  (A0),IMA
  MOVE.W  OLDVBN(PC),VBLNO
  MOVE.L  OLDVBQ(PC),VBLQU
;
  LEA     OLDPAL(PC),A6
  BSR     RESTPAL       ; Restore original palette
;
  MOVE.L  OL_STK(PC),-(sp)     ; restore value of original SSP
  MOVE.W  #$20,-(sp)
  TRAP    #1            ; and return to user mode
  ADDQ    #6,sp
;
  MOVE    ENTRYREZ(PC),D0
  BEQ.S   FIN_X
  MOVE    D0,-(SP)
  MOVE.L  #-1,-(SP)
  MOVE.L  #-1,-(SP)
  MOVE    #5,-(SP)
  TRAP    #14
  ADD     #12,SP
FIN_X:
  MOVE    #0,-(SP)      ; Return to desktop
  TRAP    #1
;
;
; Subroutine to save palette to address in A6. Preserves all.
SAVEPAL:
  MOVEM.L D0-D2/A0-A1,-(SP)
  MOVEQ   #16-1,D2
  ADD     #16*2,A6
SAVEPALP:
  MOVE    #-1,-(SP)
  MOVE    D2,-(SP)
  MOVE    #7,-(SP)
  TRAP    #14
  ADDQ    #6,SP
  MOVE    D0,-(A6)
  DBRA    D2,SAVEPALP
  MOVE.L  A0,PALAD
  MOVEM.L (SP)+,D0-D2/A0-A1
  RTS
;
;
; Subroutine to Restore Palette from address in A6. Corrupts D0.
RESTPAL:
  move.l  a1,-(sp)
  move.l  palad(pc),a1
  moveq   #16*2,d0
  add     d0,a1
  add     d0,a6
  moveq   #16/2-1,d0
restpalp:
  move.l  -(a6),-(a1)
  dbra    d0,restpalp
  move.l  (sp)+,a1
;subroutine to refresh poked pallette, only if emulation pallette
emurestpal: ;Corrupts no regs, only CCR flags
  cmp     #$ff,palad         ;check high word of pal address
  bhs.s   no_emurest         ;no emu restoration if pallette is hardware
do_emurest:
  movem.l d0/a0/a1,-(sp)     ;save entry D0/A0/A1
  move.l  palad(pc),-(sp)    ;push A6 as palptr
  move    #6,-(sp)           ;push code XBIOS Setpallete(palptr)
  trap    #14                ;XBIOS
  addq    #6,sp
  movem.l (sp)+,d0/a0/a1     ;restore entry D0/A0/A1
no_emurest:
  rts
;
;
; Storage for:
;
OL_STK:   DS.L   1      ; Initial value of stack
ENTRYREZ: DS.L   1
OL_KEYHND:DS.L   1      ; Initial key handler vector
OLDVBN:   DS.W   1      ; Initial number of Vblank routines
OLDVBQ:   DS.L   1      ; Initial Vblank queue address
OL_HBLANK:DS.L   1      ; Initial Hblank vector
OLDPAL:   DS.W   16     ; Initial palette
NEWQU:    DS.L   20     ; New Vblank queue
SCRAD:    DS.L   1      ; Address of screen in memory
PALAD:    DS.L   1      ; Address of hardware pallette
x_palptr  ds.l   1
y_palptr  ds.l   1
z_palptr  ds.l   1
x_palmask:ds.w   1
y_palmask:ds.w   1
z_palmask:ds.w   1
y_count:  DS.W   1      ; Y_pal shift counter
z_count:  DS.W   1      ; Z_pal shift counter
z_dir:    DS.W   1      ; Direction of z_pal shift
;
OLDMK:    DS.B   3      ; Initial state of MFP
FLASHFLG: DS.B   1
;
  ALIGN.W
;
;
; Initial palette with RED set
;
REDPALTB:
  DC.W    $000,$800,$100,$900,$200,$A00,$300,$B00
  DC.W    $400,$C00,$500,$D00,$600,$E00,$700,$F00
;
; Blue settings for colours
;
BLUPALTB:
  DC.W    $000,$008,$001,$009,$002,$00A,$003,$00B
  DC.W    $004,$00C,$005,$00D,$006,$00E,$007,$00F
;
; Green settings for colours
;
GRNPALTB:
  DC.W    $000,$080,$010,$090,$020,$0A0,$030,$0B0
  DC.W    $040,$0C0,$050,$0D0,$060,$0E0,$070,$0F0
;
; Block to copy onto screen to get 16 colours
;
LINES:
  DC.W    $0000,$0000,$0000,$0000
  DC.W    $FFFF,$0000,$0000,$0000
  DC.W    $0000,$FFFF,$0000,$0000
  DC.W    $FFFF,$FFFF,$0000,$0000
  DC.W    $0000,$0000,$FFFF,$0000
  DC.W    $FFFF,$0000,$FFFF,$0000
  DC.W    $0000,$FFFF,$FFFF,$0000
  DC.W    $FFFF,$FFFF,$FFFF,$0000
  DC.W    $0000,$0000,$0000,$FFFF
  DC.W    $FFFF,$0000,$0000,$FFFF
  DC.W    $0000,$FFFF,$0000,$FFFF
  DC.W    $FFFF,$FFFF,$0000,$FFFF
  DC.W    $0000,$0000,$FFFF,$FFFF
  DC.W    $FFFF,$0000,$FFFF,$FFFF
  DC.W    $0000,$FFFF,$FFFF,$FFFF
  DC.W    $FFFF,$FFFF,$FFFF,$FFFF
;
; The end
;
  END     ;of file:     COLOURS.S
