***********************************************************************
*                                                                      *
*                    Apple //GS Utility Macros                         *
*                              by                                      *
*                          Lou Infeld                                  *
*                                                                      *
*                Copyright Apple Computer, Inc. 1986, 1987             *
*                       All Rights Reserved                            *
*                                                                      *
*        Revision History                                              *
*        ----------------                                              *
*        v1.0R1 (04/29/87) -- First Release                            *
*                             This file is a subset of the old         *
*                                "M16.Utility"                         *                  
*	v2.0R1 (01/22/88) --	First AsmIIGS release						*
*	v2.0R2 (02/11/88) --	"writelin" renamed "writeline"				*
*	v2.0R3 (03/29/88) --	"|" added to pea instrs to avoid Assembler	*
*								warning									*
*							"pushlong" was incorrect if &offset was "s"	*
*								or not specified						*
*	v2.0R4 (04/14/88) --	"writestr" and "writeline" didn't restore	*
*							STRING setting								*
*	v2.0R5 (08/22/88) --	"inc4" and "dec4" redefined to support only	*
*								positive 4 byte integers				*
*							"sub4" fixed so that there will not be any	*
*								truncation warnings generated			*
*							Pull macros now check for missing parameter *
*							  	or extra parameter						*
*	v2.0R6 (09/06/88) --	"dec4" fixed to support positive 4 byte		*
*								integers								*
*   v2.0R7 (4/4/89) -- changed "long" to "longmx", "short" to "shortmx" *
*                      and added stack based macros (rls3)              *
*************************************************************************

;............................................................
;
;        Pull long (4 bytes) from stack
;
;    pulllong address             - pull off stack to address
;    pulllong addr1,addr2         - pull off stack into 2 places
;    pulllong [zeropage],offset   - pull off stack and store indirectly             
;    pulllong                     - pull off stack and leave in A
;...............................................................
         MACRO
&lab     pulllong &addr1,&addr2
&lab     ANOP
         AIF   C:&addr1=0,.a
         AIF   C:&addr2=0,.b
         LCLC  &C
&C       AMID  &addr1,1,1
         AIF   "&C"="[",.zeropage
         pullword  &addr1
         sta   &addr2
         pullword  &addr1+2
         sta   &addr2+2
         MEXIT
.a
         pullword
         pullword
         MEXIT
.b
         pullword  &addr1
         pullword  &addr1+2
         MEXIT
.zeropage
         ldy   #&addr2
         pullword  &addr1,y
         ldy   #&addr2+2
         pullword  &addr1,y
         MEND
;...............................................................
;
;        Pull 3 bytes from stack
;
;    pull3 addr    -- pulls bytes off stack and stores in "loc"
;...............................................................
         MACRO
&lab     pull3 &addr   
&lab     ANOP
         pull1 &addr
         pullword  &addr+1
         MEND
;...............................................................
;
;        Pull 2 bytes from stack
;
;    pullword loc     -- pulls bytes off stack and stores in "loc"
;    pullword loc,x   -- pulls bytes off stack and stores in "loc,x"
;    pullword         -- pulls bytes off stack and leaves in A
;...............................................................
         MACRO
&lab     pullword &SYSOPR
&lab     ANOP
         pla
         AIF   C:&SYSOPR=0,.end
         sta   &SYSOPR
.end
         MEND
;...............................................................
;
;        Pull 1 byte from stack
;
;    pull1 loc     -- pulls byte off stack and stores in "loc"
;    pull1 loc,x   -- pulls byte off stack and stores in "loc,x"
;    pull1         -- pulls byte off stack and leaves in A
;...............................................................
         MACRO
&lab     pull1 &SYSOPR
&lab     ANOP
         shortm
         pla
         AIF   C:&SYSOPR=0,.end
         sta   &SYSOPR
.end
         longm
         MEND
;...............................................................
;
;        Push 1 byte onto stack
;
;    push1 loc     -- pushes byte onto stack from "loc"
;    push1 loc,x   -- pushes byte onto stack from "loc,x"
;    push1 #n      -- pushes constant #n onto stack
;    push1         -- pushes byte onto stack (from A)
;...............................................................
         MACRO
&lab     push1 &SYSOPR
&lab     ANOP
         shortm
         AIF   C:&SYSOPR=0,.a
         pushword  &SYSOPR
         AGO   .b
.a
         pushword
.b
         longm
         MEND
;............................................................
;
;        Push long (4 bytes) onto stack
;
;    pushlong address             - push contents of address
;    pushlong address,x           - push contents of address,x
;    pushlong const,s             - push contents of stack+const    
;    pushlong #address/const      - push address or constant
;    pushlong [zeropage],offset   - push using indirect address
;...............................................................
         MACRO
&lab     pushlong &addr,&offset
&lab     ANOP
         LCLC  &C
         LCLC  &REST
&C       AMID  &addr,1,1
         AIF   "&C"="#",.immediate
         AIF   "&C"="[",.zeropage
         AIF   C:&offset=0,.nooffset
         AIF   "&offset"="s",.stack
         pushword &addr+2,&offset
         pushword &addr,&offset
         MEXIT
.nooffset
         pushword  &addr+2
         pushword  &addr
         MEXIT
.immediate
&REST    AMID  &addr,2,L:&addr-1
         dc    I1'$F4',I2'(&REST)|-16'
         dc    I1'$F4',I2'&REST'
         MEXIT
.stack
         pushword &addr+2,s
         pushword &addr+2,s
         MEXIT
.zeropage
         ldy   #&offset+2
         pushword  &addr,y
         ldy   #&offset
         pushword  &addr,y
         MEND
;...............................................................
;
;        Push 3 bytes onto stack
;
;    push3 addr    -- pushes bytes onto stack from "loc"
;    push3 addr,x  -- pushes bytes onto stack from "loc,x"
;    push3 #n      -- pushes constant #n onto stack
;...............................................................
         MACRO
&lab     push3 &addr,&reg
&lab     ANOP
         LCLC  &C
         LCLC  &REST
&C       AMID  &addr,1,1
&REST    AMID  &addr,2,L:&addr
         AIF   C:&reg>0,.indexed
         AIF   "&C"="#",.immediate
         lda   &addr+1
         pha
         AGO   .a
.immediate
         lda   #(&REST)|-8
         pha
.a
         phb
         lda   &addr
         sta   1,s
         MEXIT
.indexed
         lda   &addr+1,&reg
         pha
         phb
         lda   &addr,&reg
         sta   1,s
         MEND
;...............................................................
;
;        Push 2 bytes onto stack
;
;    pushword loc     -- pushes bytes onto stack from "loc"
;    pushword loc,x   -- pushes bytes onto stack from "loc,x"
;    pushword #n      -- pushes constant #n onto stack
;    pushword         -- pushes bytes onto stack (from A)
;...............................................................
         MACRO
&lab     pushword  &SYSOPR
&lab     ANOP
         AIF   C:&SYSOPR=0,.b
         LCLC  &C
&C       AMID  "&SYSOPR",1,1
         AIF   ("&C"="#").AND.(S:LONGA),.immediate
         lda   &SYSOPR
         pha
         MEXIT
.b
         pha
         MEXIT
.immediate
         LCLC  &REST
         LCLA  &BL
&BL      ASEARCH "&SYSOPR"," ",1
         AIF   &BL>0,.a
&BL      SETA  L:&SYSOPR+1
.a
&REST    AMID  "&SYSOPR",2,&BL-2
         dc    I1'$F4',I2'&REST'
         MEND
;...............................................................
;
;        Add 2 byte integers
;
;    add loc1,loc2,loc3 - adds "loc1" to "loc2" and stores in "loc3"
;    add loc1,loc2      - adds "loc1" to "loc2" and leaves in A
;    add ,loc2,loc3     - adds A with "loc2" and stores in "loc3" 
;
;        "loc1" and "loc2" can be constants
;...............................................................
         MACRO
&lab     add   &a1,&a2,&a3
&lab     ANOP
         AIF   C:&a1=0,.a
         lda   &a1
.a
         clc
         adc   &a2
         AIF   C:&a3=0,.b
         sta   &a3
.b
         MEND
;...............................................................
;
;        Add 4 byte integers
;
;    add4 loc1,loc2,loc3 - adds "loc1" to "loc2" and stores in "loc3"
;    add4 ,loc2,loc3     - adds A to "loc2" and stores in "loc3"
;
;        "loc1" and "loc2" can be constants
;...............................................................
         MACRO
&lab     add4  &a1,&a2,&a3
&lab     ANOP
         LCLC  &C1
         LCLC  &C2
         LCLC  &REST1
         LCLC  &REST2
&C2      AMID  &a2,1,1
&REST2   AMID  &a2,2,L:&a2-1
         AIF   C:&a1=0,.a
&C1      AMID  &a1,1,1
&REST1   AMID  &a1,2,L:&a1-1
         lda   &a1
.a
         clc
         adc   &a2
         sta   &a3
         AIF   C:&a1>0,.b
         lda   #0
         AGO   .d
.b
         AIF   "&C1"="#",.c
         lda   &a1+2
         AGO   .d
.c
         lda   #^&REST1
.d
         AIF   "&C2"="#",.e
         adc   &a2+2
         AGO   .f
.e
         adc   #^&REST2
.f
         sta   &a3+2
         MEND
;...............................................................
;
;        Increment a positive 4 byte integer
;
;    inc4 loc - increments "loc"
;...............................................................
         MACRO
&lab     inc4  &a1
&lab     ANOP
         inc   &a1
         bne   ~a&SYSCNT
         inc   &a1+2
~a&SYSCNT ANOP
         MEND
;...............................................................
;
;        Subtract 2 byte integers
;
;    sub loc1,loc2,loc3 - subtracts "loc2" from "loc1" and stores in "loc3"
;    sub loc1,loc2      - subtracts "loc2" from "loc1" and leaves in A
;    sub ,loc2,lo3      - subtracts "loc2" from A and stores in "loc3" 
;
;        "loc1" and "loc2" can be constants
;...............................................................
         MACRO
&lab     sub   &a1,&a2,&a3
&lab     ANOP
         AIF   C:&a1=0,.a
         lda   &a1
.a
         sec
         sbc   &a2
         AIF   C:&a3=0,.b
         sta   &a3
.b
         MEND
;...............................................................
;
;        Subtract 4 byte integers
;
;    sub4 loc1,loc2,loc3 - subtracts "loc2" from "loc1" and stores in "loc3"
;    sub4 ,loc2,loc3     - subtracts "loc2" from A and stores in "loc3"
;...............................................................
         MACRO
&lab     sub4  &a1,&a2,&a3
&lab     ANOP
         LCLC  &C1
         LCLC  &C2
         LCLC  &REST1
         LCLC  &REST2
&C2      AMID  &a2,1,1
&REST2   AMID  &a2,2,L:&a2-1
         AIF   C:&a1=0,.a
&C1      AMID  &a1,1,1
&REST1   AMID  &a1,2,L:&a1-1
         lda   &a1
.a
         sec
         sbc   &a2
         sta   &a3
         AIF   C:&a1>0,.b
         lda   #0
         AGO   .d
.b
         AIF   "&C1"="#",.c
         lda   &a1+2
         AGO   .d
.c
         lda   #^&REST1
.d
         AIF   "&C2"="#",.e
         sbc   &a2+2
         AGO   .f
.e
         sbc   #^&REST2
.f
         sta   &a3+2
         MEND
;...............................................................
;
;        Decrement a positive 4 byte integer
;
;    dec4 loc - decrements "loc"
;...............................................................
         MACRO
&lab     dec4  &a1
&lab     ANOP
         pha
         sec
         lda   &a1
         sbc   #1
         bcs   ~a&SYSCNT
         dec   &a1+2
~a&SYSCNT sta   &a1
         pla
         MEND
;...............................................................
;
;        Define string
;
;        Generates a Pascal type of string
;...............................................................
         MACRO
&lab     str   &string
&lab     dc    i1'L:&string',C'&string'
         MEND
;...............................................................
;
;        Define pointer
;...............................................................
         MACRO
&lab     dp    &pointer
&lab     dc    i4'&pointer'
         MEND
;...............................................................
;
;        Left Shift 4 bytes
;
;        asl4  loc,#n                   ;n is shift count (pos)
;        asl4  loc,lnum                 ;lnum contains shift count (pos)
;        asl4  loc                      ;X contains shift count (pos)
;...............................................................
         MACRO
&lab     asl4  &loc,&num
&lab     ANOP
         lda   &loc+2
         AIF   C:&num=0,.a
         ldx   &num
.a
~a&SYSCNT asl  a
         asl   &loc
         adc   #0
         dex
         bne   ~a&SYSCNT
         sta   &loc+2
         MEND
;...............................................................
;
;        Right Shift 4 bytes
;
;        lsr4  loc,#n                   ;n is shift count (pos)
;        lsr4  loc,lnum                 ;lnum contains shift count (pos)
;        lsr4  loc                      ;X contains shift count (neg)
;...............................................................
         MACRO
&lab     lsr4  &loc,&num
&lab     ANOP
         AIF   C:&num=0,.a
         lda   &num
         eor   #$FFFF
         clc
         adc   #1
         tax
.a
         lda   &loc
~a&SYSCNT lsr  a
         lsr   &loc+2
         bcc   ~b&SYSCNT
         ora   #$8000
~b&SYSCNT inx
         bne   ~a&SYSCNT
         sta   &loc
         MEND
;...............................................................
;
;        Turn on native mode
;
;    The processor is put into "native" mode.  8 bit or 16 bit
;    mode can be specified by using "shortmx" or "longmx" as the
;    parameter.  If no parameter is specified, "long" is assumed
;...............................................................
         MACRO
&lab     native &mode
&lab     ANOP
         clc
         xce
         AIF C:&mode=0,.a
         &mode
         MEXIT
.a
         longmx
         MEND
;...............................................................
;
;        Turn on emulation mode
;
;    The processor is put into "emulation" mode.
;...............................................................
         MACRO
&lab     emulation
&lab     ANOP
         sec
         xce
         longa off
         longi off
         MEND
;...............................................................
;
;        Set Memory & registers to 16 bits
;...............................................................
         MACRO
&lab     longmx
&lab     ANOP
         rep   #%00110000
         longa on
         longi on
         MEND
;...............................................................
;
;        Set Memory & A register to 16 bits
;...............................................................
         MACRO
&lab     longm
&lab     ANOP
         rep   #%00100000
         longa on
         MEND
;...............................................................
;
;        Set X & Y registers to 16 bits
;...............................................................
         MACRO
&lab     longx
&lab     ANOP
         rep   #%00010000
         longi on
         MEND
;...............................................................
;
;        Set Memory & registers to 8 bits
;...............................................................
         MACRO
&lab     shortmx
&lab     ANOP
         sep   #%00110000
         longa off
         longi off
         MEND
;...............................................................
;
;        Set Memory & A register to 8 bits
;...............................................................
         MACRO
&lab     shortm
&lab     ANOP
         sep   #%00100000
         longa off
         MEND
;...............................................................
;
;        Set X & Y registers to 8 bits
;...............................................................
         MACRO
&lab     shortx
&lab     ANOP
         sep   #%00010000
         longi off
         MEND
;...............................................................
;
;        Write string
;
;        writestr loc     - string at loc "loc"
;        writestr #'ABC'  - string='ABC'
;        writestr         - A,Y has loc of string         
;...............................................................

         MACRO
&lab     writestr &addr
&lab     ANOP
         AIF   C:&addr=0,.c
         lclc  &char
&char    amid  &addr,1,1
         AIF   "&char"="#",.a
         pea   &addr|-16
         pea   &addr
         ago   .b
.a
         lclc  &str
&str     amid  &addr,3,L:&addr-3
         bra   ~b&SYSCNT
~a&SYSCNT dc   i1'L:&str',C'&str'
~b&SYSCNT pea  ~a&SYSCNT|-16
         pea   ~a&SYSCNT
.b
         ldx   #$1C0C
         jsl   $E10000
         MEXIT
.c
         phy
         pha
         AGO   .b
         MEND
;...............................................................
;
;        Write line (string+CR)
;
;        writeln loc     - string at loc "loc"
;        writeln #'ABC'  - string='ABC'
;        writeln         - CR only
;
;...............................................................

         MACRO
&lab     writeln &addr
&lab     ANOP
         AIF   C:&addr=0,.c
         lclc  &char
&char    amid  &addr,1,1
         AIF   "&char"="#",.a
         pea   &addr|-16
         pea   &addr
         ago   .b
.a
         lclc  &str
&str     amid  &addr,3,L:&addr-3
         bra   ~b&SYSCNT
~a&SYSCNT dc   I1'L:&str',C'&str'
~b&SYSCNT pea  ~a&SYSCNT|-16
         pea   ~a&SYSCNT
.b
         ldx   #$1A0C
~c&SYSCNT jsl  $E10000
         MEXIT
.c
         pea   +(~c&SYSCNT+1)|-16
         pea   ~c&SYSCNT+1
         AGO   .b
         MEND
;...............................................................
;
;        Write character
;
;        writech          - char in A register
;        writech #'A'     - char='A'
;        writech ch,x     - char in loc "ch,x"
;...............................................................

         MACRO
&lab     writech &SYSOPR
&lab     ANOP
         AIF   C:&SYSOPR=0,.a
         lda   &SYSOPR
.a
         pha
         ldx   #$180C
         jsl   $E10000
         MEND
;...............................................................
;
;              Read a char from keyboard
;
;        readch addr     - char stored in "addr"
;        readch          - char left in A register
;
;...............................................................

         MACRO
&lab     readch &SYSOPR
&lab     ANOP
         pea   0
         pea   1
         ldx   #$220C
         jsl   $E10000
         pla
         AIF   C:&SYSOPR=0,.a
         sta   &SYSOPR
.a
         MEND

;
; DSect &Value
;
; Begin local data section.  This defines a dummy PC
; register which can be used in equates to avoid error-
; prone linked equates for setting up direct page or
; stack offsets.  The dummy PC begins at &Value and
; is updated by the appropriate amount by the BYTE,
; WORD, LONG, and BLOCK macros.
;
 MACRO
 DSect &Value
 GBLA &DummyPC
&DummyPC SETA &Value
 MEND


;
; DefineStack
;
; This is a specialized data section which defines
; a dummy PC starting at 1 in order to define a
; series of stack offsets using the BYTE, WORD,
; LONG, and BLOCK macros.
;
 MACRO
 DefineStack
 GBLA &DummyPC
&DummyPC SETA 1
 MEND

;
; &lab byte
;
; Equate the given label with the current dummy
; PC (defined by DSect, GlobalDSect, or
; DefineStack), and update the dummy PC by the
; appropriate amount.
;
 MACRO
&lab BYTE
&lab equ &DummyPC
&DummyPC SETA &DummyPC+1
 MEND

;
; &lab word
;
; Equate the given label with the current dummy
; PC (defined by DSect, GlobalDSect, or
; DefineStack), and update the dummy PC by the
; appropriate amount.
;
 MACRO
&lab WORD
&lab equ &DummyPC
&DummyPC SETA &DummyPC+2
 MEXIT
 MEND

;
; &lab long
;
; Equate the given label with the current dummy
; PC (defined by DSect, GlobalDSect, or
; DefineStack), and update the dummy PC by the
; appropriate amount.
;
 MACRO
&lab LONG
&lab equ &DummyPC
&DummyPC SETA &DummyPC+4
 MEND

;
; &lab block &size
;
; Equate the given label with the current dummy
; PC (defined by DSect, GlobalDSect, or
; DefineStack), and update the dummy PC by the
; appropriate amount (&size bytes).
;
 MACRO
&lab BLOCK &Value
 AIF C:&lab=0,.skiplab
&lab equ &DummyPC
.skiplab
&DummyPC SETA &DummyPC+&Value
 MEND

;
; &lab DSectSize
;
; This macro equates the given label with the
; current dummy PC defined by the DSect,
; GlobalDSect, or DefineStack macros.  This is
; useful for determing the size of data sections
; or parts of data sections.
;
 MACRO
&lab DSectSize
&lab equ &DummyPC
 MEND

;
; &lab EndLocals
;
; This macro equates the given label with the
; current DummyPC-1 defined by the DSect,
; GlobalDSect, or DefineStack macros.  This is
; useful for determing the stack usage of locals.
;
 MACRO
&lab EndLocals
&lab equ &DummyPC-1
 MEND
