; MACRO.S
* * * macro file,  created 12/5/83       ks/pg * * *

; The following stuff gets used to handle nested conditionals and loops.
;         This macro is called inside the MACRODEF macro, at the top
;         of every source file.

$SETUP    MACRO
STK       DEFG    'STK'                  needed for concatenation syntax
PTR       DEFG    0                      stack pointer

INDEX     DEFL    0
          DO 10                          change this for more nesting levels
STK&INDEX DEFG    1                      create each entry in the stack-INDEX     DEFL    &INDEX+1               labels "STK0000n"
INDEX     DEFL    &INDEX+1
          ENDDO

; Used to derive the proper opcode for branching to ENDIF
;   The possible arguments to IF and UNTIL and WHILE are all here:

LT        DEFG    'BCS'
CC        DEFG    'BCS'

GE        DEFG    'BCC'
CS        DEFG    'BCC'

NOTZERO   DEFG    'BEQ'
NOTEQUAL  DEFG    'BEQ'

ZERO      DEFG    'BNE'
EQUAL     DEFG    'BNE'
EQUALS    DEFG    'BNE'
EQU       DEFG    'BNE'

PLUS      DEFG    'BMI'
MINUS     DEFG    'BPL'

          ENDM

RAMDEF    MACRO

          $SETUP                         needed for conditionals and iteration

CTRLOFF   EQU     $60

* * VCS holdovers * *
INPTCTRL  EQU     $01                    Input Port Control ???
INPT4     EQU     $0C                    player 0 button, player 1 is next
INPT5     EQU     $0D
AUDC0     EQU     $15      ;BITS     3210 AUDIO CONTROL 0
AUDC1     EQU     $16      ;BITS     3210 AUDIO CONTROL 1
AUDF0     EQU     $17      ;BITS     3210 AUDIO FREQUENCY 0
AUDF1     EQU     $18      ;BITS     3210 AUDIO FREQUENCY 1
AUDV0     EQU     $19      ;BITS     3210 AUDIO VOLUME 0
AUDV1     EQU     $1A      ;BITS     3210 AUDIO VOLUME 1
* * Maria, you doll * *
BACKGRND  EQU     $20                    ; background color
P0C1      EQU     $21
P0C2      EQU     $22
P0C3      EQU     $23
WSYNC     EQU     $24                    ; fast Maria wsync strobe
P1C1      EQU     $25
P1C2      EQU     $26
P1C3      EQU     $27
MSTAT     EQU     $28                    ; bit 7 in vblank, bit 6 in display
P2C1      EQU     $29
P2C2      EQU     $2A
P2C3      EQU     $2B
DPPH      EQU     $2C                    ; display list pointer high
P3C1      EQU     $2D
P3C2      EQU     $2E
P3C3      EQU     $2F
DPPL      EQU     $30                    ; display list pointer low
P4C1      EQU     $31
P4C2      EQU     $32
P4C3      EQU     $33
CHARBASE  EQU     $34                    ; character mode high pointer
P5C1      EQU     $35
P5C2      EQU     $36
P5C3      EQU     $37
OFFSET    EQU     $38                    ; future expansion, ignore
P6C1      EQU     $39
P6C2      EQU     $3A
P6C3      EQU     $3B
CTRL      EQU     $3C                    ; bit 7 character width, bit 6 BCNT
P7C1      EQU     $3D
P7C2      EQU     $3E
P7C3      EQU     $3F

* 6532  TIMERS AND PORTS
SWCHA     EQU     $280  ;PO, P1 JOYSTICKS
;         BIT 7 PLAYER 0 EAST IF CLEAR
;         BIT 6          WEST
;         BIT 5          SOUTH
;         BIT 4          NORTH
;         BIT 3 PLAYER 1 EAST IF CLEAR
;         BIT 2          WEST
;         BIT 1          SOUTH
;         BIT 0          NORTH

SWCHB     EQU     $282  ;CONSOLE SWITCHES
;         BIT 7   PLAYER 1 DIFFICULTY A IF SET B IF CLEAR
;         BIT 6   PLAYER 0 DIFFICULTY A IF SET B IF CLEAR
;         BIT 3   BLACK & WHITE/COLOR  COLOR WHEN SET
;         BIT 1   GAME SELECT  CLEAR WHEN PRESSED
;         BIT 0   GAME RESET   CLEAR WHEN PRESSED

CTLSWA    EQU     $281
CTLSWB    EQU     $283

********************************************************************************
*                 ZERO PAGE RAM  40-FF                                         *
*         93 BYTES CURRENTLY STORED HERE !                                     *
********************************************************************************

NUMZONES  EQU     11

          ORG     $40

DLIADR    EQU     $40                    ; JMP INDIRECT FROM NMI VECTOR

LISTPTR   EQU     $42                    ; USED IN LOADER AS A DLIST POINTER
LISTPTRA  EQU     $44

LISTSIZE  EQU     $46                    ; MUST BE IN ZERO PAGE, SO THAT
                                         ; "STY   LISTSIZE,X" WORKS
LISTSTRT  EQU     LISTSIZE+NUMZONES      ; BEGINNING OF MOVING CHAR INFO

TEMP0     EQU     $5C
TEMP1     EQU     TEMP0+1
TEMP2     EQU     TEMP0+2
TEMP3     EQU     TEMP0+3
TEMP4     EQU     TEMP0+4
TEMP5     EQU     TEMP0+5
TEMP6     EQU     TEMP0+6
KTEMP0    EQU     TEMP0+7                ; USED FOR SOUND DRIVER
KTEMP1    EQU     TEMP0+8

RANDOM0   EQU     $65                    ; THESE ARE USED BY RANDOM ROUTINES
RANDOM1   EQU     RANDOM0+1
RANDOM2   EQU     RANDOM0+2

TEMPX     EQU     $68                    ; USED FOR INDEX REGISTERS
TEMPY     EQU     TEMPX+1

LTEMPY    EQU     $6A                    ; FOR THE LOADER
LSECOND   EQU     LTEMPY+1               ; USED FOR OVERLAP TEST
TEMPYPOS  EQU     LTEMPY+2               ; ALSO FOR THE LOADER
HIGHPOS   EQU     LTEMPY+3               ; USED BY THE LOADER FOR HIGH BYTE

RTEMPX    EQU     $6E
RTEMPY    EQU     RTEMPX+1               ; FOR RANDOM ROUTINES

RTEMP0    EQU     HIGHPOS+3
RTEMP1    EQU     HIGHPOS+4

HEADER0   EQU     $72                    ; LOADER : TEMP STORAGE FOR HEADER
HEADER1   EQU     HEADER0+1              ;   BYTES
HEADER2   EQU     HEADER0+2
HEADER3   EQU     HEADER0+3

FRAMECNT  EQU     $76                    ; ONE PER VBLANK
OLDFCNT   EQU     FRAMECNT+1
CYCLECNT  EQU     FRAMECNT+2             ; ONE PER GAMEPLAY CYCLE
NUMCYCLE  EQU     FRAMECNT+3
MAXCYCLE  EQU     FRAMECNT+4

SYSCOUNT  EQU     FRAMECNT+5

STATUS    EQU     FRAMECNT+7
MODE      EQU     FRAMECNT+8

; 63 BYTES UP TO THIS POINT.

TOTALCH   EQU     $20                    ; 32 MOVING OBJECTS AT ONE TIME
TOTALFX   EQU     $1B                    ; 27 FIXED OBJECTS PER SCREEN

CSTATE    EQU     $7F                    ; 32 BYTES EACH
CYPOS     EQU     CSTATE+TOTALCH
CXPOS     EQU     CYPOS+TOTALCH

; 159 BYTES UP TO THIS POINT

PLAYNUM   EQU     $DF                    ; TRUE IF TWO-PLAYER
CURRENT   EQU     $E0                    ; TELLS WHICH PLAYER

RUNLOAD   EQU     $E1                    ; WHETHER TO RUN LOADER OR NOT

GODPTR    EQU     $E2                    two bytes

; added late-- Jan. 30, 1984

GAMECNT   EQU     $E4
WAITCNT   EQU     $E5
OTHER     EQU     $E6
HOWHARD   EQU     $E7
HIGHEST   EQU     $E8

PLRACK    EQU     $EA
PLCARRY   EQU     $EB
PLLIVES   EQU     $EC
PLBCD     EQU     $ED                    two bytes

PSREADY   EQU     $EF
RESREADY  EQU     $F0
SELREADY  EQU     $F1
THREADY   EQU     $F2                    ; USED BY "SELECT"

GOALX     EQU     $F3
GOALY     EQU     $F4

CYCLEIDX  EQU     $F5                     ; AT RACK START, EQUALS 0
THROWIDX  EQU     $F7

THROWBUT  EQU     $F8                     ; FOR PURPOSE OF GAMEPLAY
JOYDIR    EQU     $F9

HJOYDIR   EQU     $FA                     ; CONTROLLER STATUS
HTHROW    EQU     $FB

DOITOVER  EQU     $FC

FPRESET   EQU     $FD
FPSELECT  EQU     $FE
FPPAUSE   EQU     $FF

          ENDM

MOVE      MACRO   A,B,C,D,E,F,G,H        universal moving

; First test to see if this is a multiple move.

  IF      '&C'<>''.AND.'&D'<>'X'.AND.'&D'<>'Y'
   IF   '&C'<>'X'.AND.'&C'<>'Y'.AND.'&B'<>'X'.AND.'&B'<>'Y'

                  LDA   &A
                  STA   &B
                  STA   &C
                  IF '&D'<>''
                     STA   &D
                  ENDIF
                  IF '&E'<>''
                     STA   &E
                  ENDIF
                  IF '&F'<>''
                     STA   &F
                  ENDIF
                  IF '&G'<>''
                     STA   &G
                  ENDIF
                  IF '&H'<>''
                     STA   &H
                  ENDIF

                  EXITM
             ENDIF
          ENDIF

          IF      '&D'<>''               handles indirect addressing mode
A         DEFL    '&A!,&B'
B         DEFL    '&C!,&D'
          ELSEIF  '&C'<>''
          IF      '&B'='X'.OR.'&B'='Y'
A         DEFL    '&A!,&B'
B         DEFL    '&C'
          ELSE
B         DEFL    '&B!,&C'
          ENDIF
          ENDIF

          IF      '&A'='A'                 store accumulator somewhere
          IF      '&B'='X'
          TAX
          ELSEIF  '&B'='Y'
          TAY
          ELSEIF  '&B'='S'
          TAX
          TXS
          ELSE
          STA     &B
          ENDIF

          ELSEIF  '&A'='Y'                 store y somewhere
          IF      '&B'='A'
          TYA
          ELSEIF  '&B'='X'
          TYA
          TAX
          ELSE
          STY     &B
          ENDIF

          ELSEIF  '&A'='X'                 store x somewhere
          IF      '&B'='A'
          TXA
          ELSEIF  '&B'='Y'
          TXA
          TAY
          ELSE
          STX     &B
          ENDIF

          ELSEIF  '&B'='A'                 load a with memory
          LDA     &A
          ELSEIF  '&B'='X'                 load x with memory
          LDX     &A
          ELSEIF  '&B'='Y'                 load y with memory
          LDY     &A
          ELSEIF  '&B'='S'
          LDX     &A
          TXS
          ELSE
          LDA     &A
          STA     &B
          ENDIF
          ENDM

DELTA     MACRO   A,B,C,D

          IF      '&B'='X'.OR.'&B'='Y'
A         DEFL    '&A!,&B'
B         DEFL    C
C         DEFL    D
          ENDIF

          IF      '&C'='X'.OR.'&C'='Y'
B         DEFL    '&B!,&C'
          ENDIF

          IF '&A'<>'A'                   get correct value in A
          IF '&A'='X'
          TXA
          ELSEIF '&A'='Y'
          TYA
          ELSE
          LDA     &A
          ENDIF
          ENDIF

          SEC
          SBC     &B
          BPL     Z&INDX
          EOR     #$FF
          CLC
          ADC     #1
Z&INDX
          ENDM

ADD       MACRO   A,B,C,D,E,F            source1,source2,destination

          IF '&B'='X'.OR.'&B'='Y'
A         DEFL    '&A!,&B'
B         DEFL    '&C'
C         DEFL    '&D'
D         DEFL    '&E'
E         DEFL    '&F'
          ENDIF

          IF '&C'='X'.OR.'&C'='Y'
B         DEFL    '&B!,&C'
C         DEFL    '&D'
D         DEFL    '&E'
          ENDIF

          IF '&D'<>''
C         DEFL    '&C!,&D'
          ELSEIF '&C'=''
C         DEFL    '&A'
          ENDIF

          IF '&A'<>'A'
          LDA     &A
          ENDIF

          CLC                            hackable byte, if not needed
          ADC     &B

          IF '&C'<>'A'
          STA     &C
          ENDIF

          ENDM

MOVEWORD  MACRO   A,B
          MOVE    &A,&B
          MOVE    &A+1,&B+1
          ENDM

CLRB      MACRO   A
          MOVE    #0,&A
          ENDM

CLRW      MACRO   A
          MOVE    #0,&A,&A+1
          ENDM

INCWORD   MACRO   A,B,C,D

          IF      '&B'='X'.OR.'&B'='Y'
A         DEFL    '&A!,&B'
B         DEFL    C
C         DEFL    D
          ENDIF

          IF      '&C'='X'.OR.'&C'='Y'
B         DEFL    '&B!,&C'
          ENDIF

          INC     &A
          BNE     Z&INDX

          IF  '&B'=''
          INC     &A!+1
          ELSE
          INC     &B
          ENDIF

Z&INDX
          ENDM

DECWORD   MACRO   A,B,C,D

          IF      '&B'='X'.OR.'&B'='Y'
A         DEFL    '&A!,&B'
B         DEFL    C
C         DEFL    D
          ENDIF

          IF      '&C'='X'.OR.'&C'='Y'
B         DEFL    '&B!,&C'
          ENDIF

          SEC
          LDA     &A
          SBC     #1
          STA     &A
          LDA     &B
          SBC     #0
          STA     &B
          ENDM

ADDWORD   MACRO   A,B,C,D,E,F,G,H

          IF '&B'='X'.OR.'&B'='Y'
A         DEFL    '&A!,&B'
B         DEFL    '&C'
C         DEFL    '&D'
D         DEFL    '&E'
E         DEFL    '&F'
F         DEFL    '&G'
G         DEFL    '&H'
          ENDIF

          IF '&C'='X'.OR.'&C'='Y'
B         DEFL    '&B!,&C'
C         DEFL    '&D'
D         DEFL    '&E'
E         DEFL    '&F'
F         DEFL    '&G'
          ENDIF

          IF '&D'='X'.OR.'&D'='Y'
C         DEFL    '&C!,&D'
D         DEFL    '&E'
E         DEFL    '&F'
          ENDIF

          IF '&E'='X'.OR.'&E'='Y'
D         DEFL    '&D!,&E'
          ENDIF

          CLC
          LDA     &A
          ADC     &C
          STA     &A
          LDA     &B
          ADC     &D
          STA     &B

          ENDM

INCTIME   MACRO   R
          INCWORD &R,&R!+1
          ENDM

SUBWORD   MACRO   A,B,C,D,E,F,G,H

          IF '&B'='X'.OR.'&B'='Y'
A         DEFL    '&A!,&B'
B         DEFL    '&C'
C         DEFL    '&D'
D         DEFL    '&E'
E         DEFL    '&F'
F         DEFL    '&G'
G         DEFL    '&H'
          ENDIF

          IF '&C'='X'.OR.'&C'='Y'
B         DEFL    '&B!,&C'
C         DEFL    '&D'
D         DEFL    '&E'
E         DEFL    '&F'
F         DEFL    '&G'
          ENDIF

          IF '&D'='X'.OR.'&D'='Y'
C         DEFL    '&C!,&D'
D         DEFL    '&E'
E         DEFL    '&F'
          ENDIF

          IF '&E'='X'.OR.'&E'='Y'
D         DEFL    '&D!,&E'
          ENDIF

          SEC
          LDA     &A
          SBC     &C
          STA     &A
          LDA     &B
          SBC     &D
          STA     &B

          ENDM

SUB       MACRO   A,B,C,D,E,F            source1,source2,destination

          IF '&B'='X'.OR.'&B'='Y'
A         DEFL    '&A!,&B'
B         DEFL    '&C'
C         DEFL    '&D'
D         DEFL    '&E'
E         DEFL    '&F'
          ENDIF

          IF '&C'='X'.OR.'&C'='Y'
B         DEFL    '&B!,&C'
C         DEFL    '&D'
D         DEFL    '&E'
          ENDIF

          IF '&D'<>''
C         DEFL    '&C!,&D'
          ELSEIF '&C'=''
C         DEFL    '&A'
          ENDIF

          IF '&A'<>'A'
          LDA     &A
          ENDIF

          SEC                            hackable byte
          SBC     &B

          IF '&C'<>'A'
          STA     &C
          ENDIF

          ENDM

BLT       MACRO   A,B,C
          IF      '&B'='X'.OR.'&B'='Y'.AND.'&C'<>''   ; handles label='X'
A         DEFL    '&A!,&B'
B         DEFL    C
          ENDIF

          IF      '&B'<>''
          LDA     &A
          BMI     &B
          ELSE
          BCC     &A
          ENDIF
          ENDM

BGE       MACRO   A,B,C
          IF      '&B'='X'.OR.'&B'='Y'.AND.'&C'<>''
A         DEFL    '&A!,&B'
B         DEFL    C
          ENDIF

          IF      '&B'<>''
          LDA     &A
          BPL     &B
          ELSE
          BCS     &A
          ENDIF
          ENDM

BGT       MACRO   A,B,C
          IF      '&B'='X'.OR.'&B'='Y'.AND.'&C'<>''
A         DEFL    '&A!,&B'
B         DEFL    C
          ENDIF

          IF      '&B'<>''
          LDA     &A
          BEQ     ZZ&INDX                who knows if conflict ?
          BPL     &B                     (with this assembler !?!)
ZZ&INDX
          ELSE
          BEQ     Z&INDX
          BCS     &A
Z&INDX
          ENDIF
          ENDM


PHX       MACRO
          TXA
          PHA
          ENDM

PHY       MACRO
          TYA
          PHA
          ENDM

PLX       MACRO
          PLA
          TAX
          ENDM

PLY       MACRO
          PLA
          TAY
          ENDM

PUSH      MACRO   A

          IF '&A'='X'
          PHX

          ELSEIF  '&A'='Y'
          PHY

          ELSEIF  '&A'='A'.OR.'&A'='ACC'
          PHA

          ELSEIF  '&A'='XY'.OR.'&A'='INDEX'.OR.'&A'='YX'
          PHX
          PHY

          ELSE                           otherwise, you got'em all
          PHX
          PHY
          PHA
          ENDIF
          ENDM

PULL      MACRO   A

          IF '&A'='X'
          PLX

          ELSEIF  '&A'='Y'
          PLY

          ELSEIF  '&A'='A'.OR.'&A'='ACC'
          PLA

          ELSEIF  '&A'='XY'.OR.'&A'='INDEX'.OR.'&A'='YX'
          PLY
          PLX

          ELSEIF  '&A'='YX'
          PLX
          PLY

          ELSE                           otherwise, you got'em all
          PLY
          PLX
          PLA
          ENDIF
          ENDM

SAVE      MACRO   A
          LDA     &A
          PHA
          ENDM

RESTORE   MACRO   A
          PLA
          STA     &A
          ENDM

; Note that MSTAT must read the same value TWICE to be assured the value is
;         correct.

ONSCREEN  MACRO
Z&INDX    BIT     $28                    mstat
          BMI     Z&INDX
          ENDM

OFFSCRN   MACRO
Z&INDX    BIT     $28                    mstat
          BPL     Z&INDX
          ENDM

INVBLANK  MACRO
          OFFSCRN
          ENDM


FILL      MACRO   ADDR,COUNT,VALUE
          IF '&VALUE'=''
VALUE     DEFL    0
          ENDIF

          IF &COUNT<5                    5 is changeable

          LDA     #&VALUE
          DO      &COUNT                 for really short fills
COUNT     DEFL    &COUNT-1
          STA     &ADDR+&COUNT
          ENDDO

          ELSEIF &COUNT<$100

          LDA     #&VALUE                short form, less than a page
          LDX     #&COUNT
Z&INDX    STA     &ADDR-1,X
          DEX
          BNE     Z&INDX

          ELSE
          LDA     #L(&ADDR)
          STA     TEMP0
          LDA     #H(&ADDR+&COUNT-1)     change
          STA     TEMP1
          LDA     #&VALUE

          IF      &COUNT.MOD.$100<>0     special case
          STA     &ADDR+((&COUNT/$100)*$100)   missing byte
          LDY     #&COUNT.MOD.$100-1
          LDX     #&COUNT/$100+1
          ELSE
          LDY     #0
          LDX     #&COUNT/$100
          ENDIF

          JSR     ZZZZFILL
          ENDIF
          ENDM

COPY      MACRO   FROM,TO,COUNT
          IF &COUNT<5                    5 is changeable

          DO      &COUNT                 for really short fills
COUNT     DEFL    &COUNT-1
          LDA     &FROM+&COUNT
          STA     &TO+&COUNT
          ENDDO

          ELSEIF &COUNT<$100

          LDX     #&COUNT                short form, less than a page
Z&INDX    LDA     &FROM-1,X
          STA     &TO-1,X
          DEX
          BNE     Z&INDX

          ELSE                           greater than one page

          IF      &COUNT.MOD.$100<>0     special case
          LDA     &FROM+((&COUNT/$100)*$100)     special case-- missing byte
          STA     &TO+((&COUNT/$100)*$100)
          LDY     #&COUNT.MOD.$100-1
          LDX     #&COUNT/$100+1
          ELSE
          LDY     #0
          LDX     #&COUNT/$100
          ENDIF

          LDA     #L(&FROM)
          STA     TEMP0
          LDA     #H(&FROM+&COUNT.AND.$FF00)
          STA     TEMP1
          LDA     #L(&TO)
          STA     TEMP2
          LDA     #H(&TO+&COUNT.AND.$FF00)
          STA     TEMP3
          JSR     ZZZZCOPY               If this is used, change "library.s"
          ENDIF
          ENDM

MOVEPTR   MACRO   PTR,WHERE
          LDA     #L(&PTR)
          STA     &WHERE
          LDA     #H(&PTR)
          STA     &WHERE+1
          ENDM


CLEAR     MACRO   A
          IF '&A'='ALL'.OR.'&A'='TOP'
* * expand this for optimality ! * *
          LDA     #0
          LDX     #$10                   [$40,$4F]
Z&INDX    STA     $3F,X
          DEX
          BNE     Z&INDX

          LDX     #$10                   [$140,$14F]
Y&INDX    STA     $13F,X
          DEX
          BNE     Y&INDX
          ENDIF

          IF '&A'<>'TOP'
          DMAOFF                         off when wiping out display list(s)
          JSR     CLRMARIA
          ENDIF
          ENDM


DMAOFF    MACRO
          JSR     XDMAOFF
          ENDM

DMAON     MACRO
          JSR     XDMAON
          ENDM

NEWSTATE  MACRO   STATE                  ; advance to a new state
          MOVEPTR &STATE,GODPTR          ; GOD is zero page address
          ENDM

ENDCYCLE  MACRO
          JMP     GOD
          ENDM

; conditional and iteration macros; with nesting up to 10 levels
;         Note: the maximum number of levels can be increased
;         indefinitly if anyone needs more (!).

; The conditional macros:

$IF        MACRO  A,B,C

          IF '&B'<>''                    If three arguments, do the compare
             LDA  &A
             CMP  &C
A         DEFL    '&B'
          ENDIF

          &&&A    LS&INDX
STK&PTR   DEFG    'LS&INDX'              pop off in ENDIF
PTR       DEFG    &PTR+1

          ENDM

$ELSE     MACRO
          JMP     END&INDX             ;if was satisfied; skip to ENDIF
PTR       DEFG    &PTR-1
&&STK&PTR

STK&PTR   DEFG    'END&INDX'
PTR       DEFG    &PTR+1
          ENDM

$ENDIF    MACRO                          ;if not, it comes here
PTR       DEFG    &PTR-1
&&STK&PTR
          ENDM

; Iteration macros: DO ... WHILE condition
;         and       REPEAT ... UNTIL condition
;   Note that since DO==REPEAT and WHILE==UNTIL, any combination
;         will have the desired effect: DO... UNTIL; REPEAT...WHILE

$DO       MACRO
DO&INDX
STK&PTR   DEFG    'DO&INDX'
PTR       DEFG    &PTR+1
          ENDM

$WHILE    MACRO   A,B,C

          IF '&B'<>''                    If three arguments, do the compare
             LDA  &A
             CMP  &C
A         DEFL    '&B'
          ENDIF

          &&&A    WH&INDX              branch around jump if not satisfied

PTR       DEFG    &PTR-1
          JMP     &&STK&PTR              jump back to label on stack

WH&INDX
          ENDM

; repeat-until macro-- identical to do--while

$REPEAT   MACRO
DO&INDX
STK&PTR   DEFG    'DO&INDX'
PTR       DEFG    &PTR+1
          ENDM

$UNTIL    MACRO   A,B,C

          IF '&B'<>''                    If three arguments, do the compare
             LDA  &A
             CMP  &C
A         DEFL    '&B'
          ENDIF

          &&&A    WH&INDX              branch around jump if not satisfied

PTR       DEFG    &PTR-1
          JMP     &&STK&PTR

WH&INDX

          ENDM

