	.Xlist
	Page	58,132
	Subttl	MACROS.INC	Apple Emulator (65C02 Processor)
;******************************************************************************
;
;   Name:	MACROS		Apple Emulator (65C02 Processor)
;
;   Group:	Emulator
;
;   Revision:	1.00
;
;   Date:	January 30, 1988
;
;   Author:	Randy W. Spurlock
;
;******************************************************************************
;
;  Module Functional Description:
;
;		This module contains all the macros needed by the
;	Apple emulator. This module can be included with any needed
;	source files to define the Apple emulator macros.
;
;******************************************************************************
;
;  Changes:
;
;    DATE     REVISION				DESCRIPTION
;  --------   --------	-------------------------------------------------------
;   1/30/88	1.00	Original
;
;******************************************************************************

_count	=	00h
_current=	00h
_number =	00h

Atari_Interrupt Macro vector
	lodsb
	mov	di,vector
	mov	di,ds:[di]			; get address pointed to by nmivector
	mov	ax,si			; Get the current program counter
	dec	ax			; Point to last instruction byte
	Push_16 			; Save the return address on the stack
	mov	si,di			; Update the program counter
	mov	al,dh			; get flags
	xor	ah,ah			; ax = flags
	mov	bx,ax			; used to encode flags
	mov	al,cs:[bx + Flag_Encode]
	Push_8				; flags saved on atari stack
	Endm

Ticks	Macro	tickcount
	local 	_No_Update
	sub	bp,tickcount
	ja	_No_Update
	call	Hardware_Update
_No_Update:
	endm

LineUp	Macro	divide,filler
_value	=	$ - _current
	If	_number Gt 00h
		Check	%_number, %_value
	Endif
	.Xlist
	Ifb	<filler>
_fill	=	00h
	Else
_fill	=	filler
	Endif
_addr	=	$ - Emulate
_amt	=	_addr MOD divide
	If	_amt NE 0
_amt	=	divide - _amt
	Db	_amt dup (filler)	; Reserved required space to line up
	Endif
	.List
_current=	$
_number =	_number + 1
	Endm

Check	Macro	Number, Value
	If2
		If	&Value Gt OP_SIZE
			%out	*** Error - Opcode &Number length is &Value ***
		Endif
	Endif
	Endm

String	Macro	Str
_cnt	=	0
	Irpc	x,<Str>
_cnt	=	_cnt + 1
	Endm
	Db	_cnt,Str,0Dh,0Ah	; Define the requested string
	Endm

Err_Str Macro	Name, Str
	Def_Err %_Err_Cnt,Name,<Str>
_Err_Cnt=	_Err_Cnt + 1
	Endm

Def_Err Macro	Number,Name,Str
ERR_&Name	Equ	&Number 	; Define the error name
	public	ERR_&Name
Error_&Number	Equ	This Word	; Define the error string
	String	<Str>
	Endm

Err_Tbl Macro
Error_Table	Equ	This Word	; Declare start of error table
_Err_Num=	0
	Rept	_Err_Cnt
		Def_Tbl %_Err_Num
_Err_Num=	_Err_Num + 1
	Endm
	Endm

Def_Tbl Macro	Number
	Dw	Error_&Number		; Define the error table entry
	Endm

Encode	Macro	Value
_base	=	Value And 10110101b
_flag_Z =	(Value And 01000000b) Shr 6
_flag_V =	(Value And 00001000b) Shr 3
_flag_M =	(Value And 00000010b) Shr 1
_value	=	_base + (_flag_V Shl 6) + (_flag_M Shl 3) + (_flag_Z Shl 1)
	Db	_value			; Define the encoded byte value
	Endm

Decode	Macro	Value
_base	=	Value And 10110101b
_flag_V =	(Value And 01000000b) Shr 6
_flag_M =	(Value And 00001000b) Shr 3
_flag_Z =	(Value And 00000010b) Shr 1
_value	=	_base + (_flag_Z Shl 6) + (_flag_V Shl 3) + (_flag_M Shl 1)
	Db	_value			; Define the decoded byte value
	Endm

Save	Macro	a,b,c,d,e,f,g,h,i,j
	.Xlist
	Irp	x,<a,b,c,d,e,f,g,h,i,j>
		Ifnb	<x>
			push	x	; Save the requested register
		Endif
	Endm
	.List
	Endm

Restore Macro	a,b,c,d,e,f,g,h,i,j
	.Xlist
	Irp	x,<j,i,h,g,f,e,d,c,b,a>
		Ifnb	<x>
			pop	x	; Restore the requested register
		Endif
	Endm
	.List
	Endm

Fault	Macro
	or	cs:[Emulate_Flag],SYS_DEBUG
	or	dh,CPU_R		; Set emulator interrupt request
	Endm

Fetch	Macro
	lodsb
	xor	ah,ah
	shl	ax,1			; Convert opcode to address
	mov	di,ax			; Move routine address to DI
	jmp	cs:[di]			; Jump to correct opcode routine
	Endm

Flgnz	Macro
	lahf				; Load flags into AH register
	and	ah,CPU_N + CPU_Z	; Mask off all but sign/zero flags
	and	dh,Not (CPU_N + CPU_Z)	; Clear the n and z flags
	or	dh,ah			; Update the 65C02 status flags
	Endm

Flgnzc	Macro reg
	lahf				; Load flags into AH register (2)
	and	ah,CPU_N + CPU_Z + CPU_C ; Mask off all but sign/carry/zero flags
	and	dh,Not (CPU_N + CPU_Z + CPU_C) ; (4) (4)
	or	dh,ah			; Update the 65C02 status flags
	Endm

Flgnvzc Macro
	pushf				; Push the processor flags
	pop	ax			; Pop flags into AX register
	and	ax,0000100011000001b	; Mask all but overflow/sign/zero/carry
	or	al,ah			; Logically OR in overflow flag
	and	dh,Not (CPU_N + CPU_V + CPU_Z + CPU_C)
	or	dh,al			; Update the 65C02 status flags
	Endm

Push_16 Macro
	sub	cs:Astack,2		;
	mov	bl,cs:Astack
	mov	bh,1
	mov	ds:[bx+1],ax		; Push the 16-bit value
	Endm

Push_8	Macro
	mov	bl,cs:Astack
	mov	bh,1        		; get stack pointer
	mov	ds:[bx],al		; Push the 8-bit value
	dec	cs:Astack		; Decrement the stack pointer
	Endm

Pop_16	Macro
	add	cs:Astack,2
	mov	bl,cs:Astack
	mov	bh,1
	mov	ax,ds:[bx-1]		; Pop the 16-bit value
	Endm

Pop_8	Macro
	inc	cs:Astack
	mov	bl,cs:Astack
	mov	bh,1
	mov	al,ds:[bx]		; Pop the 8-bit value
	Endm

DoImm	Macro
_type	=	000h
	mov	di,si			; Setup the effective address
	inc	si			; Update the program counter
	Endm

DoAbs	Macro
_type	=	0FFh
	lodsw				; Get the absolute address
	mov	di,ax			; Setup the effective address
	Endm

DoDP	Macro
_type	=	000h
	lodsb				; Get the direct page offset
	xor	ah,ah			; Convert to direct page address
	mov	di,ax			; Setup the effective address
	Endm

DoDIX	Macro
_type	=	000h
	lodsb				; Get the direct page offset
	add	al,ch			; Add in the X index value
	xor	ah,ah			; Convert to direct page address
	mov	di,ax			; Setup the effective address
	Endm

DoDIY	Macro
_type	=	000h
	lodsb				; Get the direct page offset
	add	al,cl			; Add in the Y index value
	xor	ah,ah			; Convert to direct page address
	mov	di,ax			; Setup the effective address
	Endm

DoAIX	Macro
_type	=	0FFh
	lodsw				; Get the absolute address
	add	al,ch			; Add in the X index value
	adc	ah,0			; Do 16-bit arithmetic
	mov	di,ax			; Setup the effective address
	Endm

DoAIY	Macro
_type	=	0FFh
	lodsw				; Get the absolute address
	add	al,cl			; Add in the Y index value
	adc	ah,0			; Do 16-bit arithmetic
	mov	di,ax			; Setup the effective address
	Endm

DoAI	Macro
_type	=	0FFh
	lodsw				; Get the absolute address
	mov	di,ax			; Setup to do the indirection
	mov	di,ds:[di]		; Setup the effective address
	Endm

DoDI	Macro
_type	=	0FFh
	lodsb				; Get the direct page offset
	xor	ah,ah			; Convert to direct page address
	mov	di,ax			; Setup to do the indirection
	mov	di,ds:[di]		; Setup the effective address
	Endm

DoAIIX	Macro
_type	=	0FFh
	lodsw				; Get the absolute address
	add	al,ch			; Add in the X index value
	adc	ah,0			; Do 16-bit arithmetic
	mov	di,ax			; Setup to do the indirection
	mov	di,ds:[di]		; Setup the effective address
	Endm

DoDIIX	Macro
_type	=	0FFh
	lodsb				; Get the direct page offset
	add	al,ch			; Add in the X index value
	xor	ah,ah			; Convert to direct page address
	mov	di,ax			; Setup to do the indirection
	mov	di,ds:[di]		; Setup the effective address
	Endm

DoDIIY	Macro
_type	=	0FFh
	lodsb				; Get the direct page offset
	xor	ah,ah			; Convert to direct page address
	mov	di,ax			; Setup to do the indirection
	mov	di,ds:[di]		; Do the indirection
	mov	al,cl			; Get the Y index value
	add	di,ax			; Setup the effective address
	Endm

DoPCR	Macro
_type	=	000h
	mov	di,si			; Get the current program counter
	lodsb				; Get the program counter offset
	cbw				; Convert offset into a full word
	add	di,ax			; Setup the effective address
	Endm

OpADC	Macro
	local	_addr, _update
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	mov	ah,dh			; Copy 65C02 flags into AH register
	test	dh,CPU_M		; Check for in decimal mode (BCD)
	jz	_addr			; Jump if in binary mode
	shr	ah,1			; Shift 65C02 carry into real carry
	adc	al,dl			; Add with carry to accumulator
	daa				; Do the adjust for decimal mode
	mov	dl,al			; Update the accumulator value
	jmp	Short _update		; Go update the 65C02 flags
_addr:
	shr	ah,1			; Shift 65C02 carry into real carry
	adc	dl,al			; Add with carry to accumulator
_update:
	Flgnvzc 			; Update the 65C02 processor flags
	Endm

OpAND	Macro
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	and	dl,al			; AND accumulator with memory
	Flgnz				; Update the 65C02 processor flags
	Endm

OpASL	Macro
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	shl	al,1			; Shift the memory location left
	mov	bx,ax			; Save the memory location value
	Flgnzc				; Update the 65C02 processor flags
	mov	ax,bx			; Restore the memory location value
	If	_type
		call	Write_Memory	; call routine to write 65C02 memory
	Else
		mov	ds:[di],al	; Write the 65C02 memory value
	Endif
	Endm

OpBIT	Macro
	Local	_addr
	and	dh,Not (CPU_N + CPU_V + CPU_Z)
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	test	dl,al			; AND accumulator with memory value
	jnz	_addr			; Jump if the value is non-zero
	or	dh,CPU_Z		; Zero result, set the zero flag
_addr:
	and	al,11000000b		; Mask off all but upper two bits
	xor	ah,ah			; Convert flag bits to full word
	mov	bx,ax			; Setup to decode the flag value
	or	dh,cs:[bx + Flag_Decode]; Set correct bits in 65C02 status
	Endm

OpBITz	Macro
	Local	_addr
	and	dh,Not CPU_Z		; Clear the z flag
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	test	dl,al			; AND accumulator with memory value
	jnz	_addr			; Jump if the value is non-zero
	or	dh,CPU_Z		; Zero result, set the zero flag
_addr:
	Endm

OpCMP	Macro
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	cmp	dl,al			; Compare accumulator with memory
	cmc				; Toggle carry to the correct state
	Flgnzc				; Update the 65C02 processor flags
	Endm

OpCPX	Macro
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	cmp	ch,al			; Compare X index register with memory
	cmc				; Toggle carry to the correct state
	Flgnzc				; Update the 65C02 processor flags
	Endm

OpCPY	Macro
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	cmp	cl,al			; Compare Y index register with memory
	cmc				; Toggle carry to the correct state
	Flgnzc				; Update the 65C02 processor flags
	Endm

OpDEC	Macro
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	dec	al			; Decrement the memory location
	mov	bx,ax			; Save the memory location value
	Flgnz				; Update the 65C02 processor flags
	mov	ax,bx			; Restore the memory location value
	If	_type
		call	Write_Memory	; call routine to write 65C02 memory
	Else
		mov	ds:[di],al	; Write the 65C02 memory value
	Endif
	Endm

OpEOR	Macro
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	xor	dl,al			; Exclusive-OR accumulator with memory
	Flgnz				; Update the 65C02 processor flags
	Endm

OpINC	Macro
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	inc	al			; Increment the memory location
	mov	bx,ax			; Save the memory location value
	Flgnz				; Update the 65C02 processor flags
	mov	ax,bx			; Restore the memory location value
	If	_type
		call	Write_Memory	; call routine to write 65C02 memory
	Else
		mov	ds:[di],al	; Write the 65C02 memory value
	Endif
	Endm

OpJMP	Macro
	mov	si,di			; Update the program counter
	Endm

OpJSR	Macro
	mov	ax,si			; Get the current program counter
	dec	ax			; Point to last instruction byte
	Push_16 			; Save the return address on the stack
	mov	si,di			; Update the program counter
	call	Jsr_Steal		; override atari code
	Endm

OpLDA	Macro
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	mov	dl,al			; Load accumulator from memory
	or	dl,dl			; Set the status flags correctly
	Flgnz				; Update the 65C02 processor flags
	Endm

OpLDX	Macro
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	mov	ch,al			; Load X index register from memory
	or	ch,ch			; Set the status flags correctly
	Flgnz				; Update the 65C02 processor flags
	Endm

OpLDY	Macro
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	mov	cl,al			; Load Y index register from memory
	or	cl,cl			; Set the status flags correctly
	Flgnz				; Update the 65C02 processor flags
	Endm

OpLSR	Macro
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	shr	al,1			; Shift the memory location right
	mov	bx,ax			; Save the memory location value
	Flgnzc				; Update the 65C02 processor flags
	mov	ax,bx			; Restore the memory location value
	If	_type
		call	Write_Memory	; call routine to write 65C02 memory
	Else
		mov	ds:[di],al	; Write the 65C02 memory value
	Endif
	Endm

OpORA	Macro
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	or	dl,al			; OR accumulator with memory
	Flgnz				; Update the 65C02 processor flags
	Endm

OpROL	Macro
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	mov	ah,dh			; Copy 65C02 flags into AH register
	shr	ah,1			; Shift 65C02 carry into real carry
	rcl	al,1			; Rotate the memory location left
	rcr	ah,1			; Save carry result in AH register
	If	_type
		call	Write_Memory	; call routine to write 65C02 memory
	Else
		mov	ds:[di],al	; Write the 65C02 memory value
	Endif
	or	al,al			; Set the n and z flags correctly
	rcl	ah,1			; Restore the carry result
	Flgnzc				; Update the 65C02 processor flags
	Endm

OpROR	Macro
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	mov	ah,dh			; Copy 65C02 flags into AH register
	shr	ah,1			; Shift 65C02 carry into real carry
	rcr	al,1			; Rotate the memory location right
	rcr	ah,1			; Save carry result in AH register
	If	_type
		call	Write_Memory	; call routine to write 65C02 memory
	Else
		mov	ds:[di],al	; Write the 65C02 memory value
	Endif
	or	al,al			; Set the n and z flags correctly
	rcl	ah,1			; Restore the carry result
	Flgnzc				; Update the 65C02 processor flags
	Endm

OpSBC	Macro
	local	_addr
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	mov	ah,dh			; Copy 65C02 flags into AH register
	shr	ah,1			; Shift 65C02 carry into real carry
	cmc				; Invert carry to correct state
	xchg	al,dl			; Get the current accumulator value
	sbb	al,dl			; Subtract from accumulator with borrow
	lahf				; Save the actual flags value
	test	dh,CPU_M		; Check for decimal mode
	jz	_addr			; Jump if in binary mode
	sahf				; Restore the actual flags value
	das				; Do the adjust for decimal mode
	lahf				; Save the actual flags value
_addr:
	sahf				; Restore the actual flags value
	mov	dl,al			; Update the accumulator value
	cmc				; Invert carry back to correct state
	Flgnvzc 			; Update the 65C02 processor flags
	Endm

OpSTA	Macro
	mov	al,dl			; Store the accumulator in memory
	If	_type
		call	Write_Memory	; call routine to write 65C02 memory
	Else
		mov	ds:[di],al	; Write the 65C02 memory value
	Endif
	Endm

OpSTX	Macro
	mov	al,ch			; Store X index register in memory
	If	_type
		call	Write_Memory	; call routine to write 65C02 memory
	Else
		mov	ds:[di],al	; Write the 65C02 memory value
	Endif
	Endm

OpSTY	Macro
	mov	al,cl			; Store Y index register in memory
	If	_type
		call	Write_Memory	; call routine to write 65C02 memory
	Else
		mov	ds:[di],al	; Write the 65C02 memory value
	Endif
	Endm

OpSTZ	Macro
	xor	al,al			; Store zero in memory
	If	_type
		call	Write_Memory	; call routine to write 65C02 memory
	Else
		mov	ds:[di],al	; Write the 65C02 memory value
	Endif
	Endm

OpTRB	Macro
	Local	_addr
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	and	dh,Not CPU_Z		; Clear the z flag
	mov	ah,dl			; Get a copy of the accumulator
	not	ah			; Invert the accumulator value
	and	al,ah			; Mask off the desired memory bits
	If	_type
		call	Write_Memory	; call routine to write 65C02 memory
	Else
		mov	ds:[di],al	; Write the 65C02 memory value
	Endif
	not	ah			; Restore the accumulator value
	and	ah,al			; AND accumulator with memory
	jnz	_addr			; Jump if the result is non-zero
	or	dh,CPU_Z		; Zero result, set the z flag
_addr:
	Endm

OpTSB	macro
	Local	_addr
;	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
;	Else
		mov	al,ds:[di]	; Read the 65C02 memory value
;	Endif
	and	dh,Not CPU_Z		; Clear the z flag
	mov	ah,dl			; Get a copy of the accumulator
	or	al,ah			; Set the desired memory bits
	If	_type
		call	Write_Memory	; call routine to write 65C02 memory
	Else
		mov	ds:[di],al	; Write the 65C02 memory value
	Endif
	and	ah,al			; AND accumulator with memory
	jnz	_addr			; Jump if the result is non-zero
	or	dh,CPU_Z		; Zero result, set the z flag
_addr:
	Endm

OpRMB	Macro	Value
	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
	mov	al,ds:[di]		; Read the memory location
		and	al,Not Value	; Reset the requested bit
		call	Write_Memory	; call routine to write 65C02 memory
	Else
		and	Byte Ptr ds:[di],Not Value
	Endif
	Endm

OpSMB	Macro	Value
	If	_type
;		call	Read_Memory	; call routine to read 65C02 memory
	mov	al,ds:[di]		; Read the memory location
		or	al,Value	; Set the requested bit
		call	Write_Memory	; call routine to write 65C02 memory
	Else
		or	Byte Ptr ds:[di],Value
	Endif
	Endm

Private Macro	Name,Size
Name	Equ	This Byte
	Private_Stack	<Size>		; Define private stack header
	Db	Size Dup (?)		; Define the actual stack data area
	Endm

Row	Macro	String
	Calc	String,%_count
_count	=	_count + 1
	Endm

Calc	Macro	String,Cnt
_x&Cnt	=	0
	Irpc	c,<String>
		_x&Cnt	=	_x&Cnt Shl 1
		Ifidn <c>,<*>
			_x&Cnt	=	_x&Cnt + 1
		Endif
	Endm
	Endm

Define	Macro
_number =	0
	Rept	_count
		Data	%_number
_number =	_number + 1
	Endm
_count	=	0
	Endm

Data	Macro	Cnt
	Db	_x&Cnt
	Endm

	.List
