mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			322 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			322 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
BLARGG_MACROS_INCLUDED = 1
 | 
						|
 | 
						|
; Allows extra error checking with modified version
 | 
						|
; of ca65. Otherwise acts like a constant of 0.
 | 
						|
ADDR = 0
 | 
						|
 | 
						|
; Switches to Segment and places Line there.
 | 
						|
; Line can be an .align directive, .res, .byte, etc.
 | 
						|
; Examples:
 | 
						|
; seg_data BSS, .align 256
 | 
						|
; seg_data RODATA, {message: .byte "Test",0}
 | 
						|
.macro seg_data Segment, Line
 | 
						|
	.pushseg
 | 
						|
	.segment .string(Segment)
 | 
						|
		Line
 | 
						|
	.popseg
 | 
						|
.endmacro
 | 
						|
 | 
						|
; Reserves Size bytes in Segment for Name.
 | 
						|
; If Size is omitted, reserves one byte.
 | 
						|
.macro seg_res Segment, Name, Size
 | 
						|
	.ifblank Size
 | 
						|
		seg_data Segment, Name: .res 1
 | 
						|
	.else
 | 
						|
		seg_data Segment, Name: .res Size
 | 
						|
	.endif
 | 
						|
.endmacro
 | 
						|
 | 
						|
; Shortcuts for zeropage, bss, and stack
 | 
						|
.define zp_res  seg_res ZEROPAGE,
 | 
						|
.define nv_res  seg_res NVRAM,
 | 
						|
.define bss_res seg_res BSS,
 | 
						|
.define sp_res  seg_res STACK,
 | 
						|
.define zp_byte zp_res
 | 
						|
 | 
						|
; Copies byte from Src to Addr. If Src begins with #,
 | 
						|
; it sets Addr to the immediate value.
 | 
						|
; Out: A = byte copied
 | 
						|
; Preserved: X, Y
 | 
						|
.macro mov Addr, Src
 | 
						|
	lda Src
 | 
						|
	sta Addr
 | 
						|
.endmacro
 | 
						|
 | 
						|
; Copies word from Src to Addr. If Src begins with #,
 | 
						|
; it sets Addr the immediate value.
 | 
						|
; Out: A = high byte of word
 | 
						|
; Preserved: X, Y
 | 
						|
.macro movw Addr, Src
 | 
						|
	.if .match( .left( 1, {Src} ), # )
 | 
						|
		lda #<(.right( .tcount( {Src} )-1, {Src} ))
 | 
						|
		sta Addr
 | 
						|
		lda #>(.right( .tcount( {Src} )-1, {Src} ))
 | 
						|
		sta 1+(Addr)
 | 
						|
	.else
 | 
						|
		lda Src
 | 
						|
		sta Addr
 | 
						|
		lda 1+(Src)
 | 
						|
		sta 1+(Addr)
 | 
						|
	.endif
 | 
						|
.endmacro
 | 
						|
 | 
						|
; Increments 16-bit value at Addr.
 | 
						|
; Out: EQ/NE based on resulting 16-bit value
 | 
						|
; Preserved: A, X, Y
 | 
						|
.macro incw Addr
 | 
						|
	.local @Skip
 | 
						|
	inc Addr
 | 
						|
	bne @Skip
 | 
						|
	inc 1+(Addr)
 | 
						|
@Skip:
 | 
						|
.endmacro
 | 
						|
 | 
						|
; Adds Src to word at Addr.
 | 
						|
; Out: A = high byte of result, carry set appropriately
 | 
						|
; Preserved: X, Y
 | 
						|
.macro addw Addr, Src
 | 
						|
	.if .match( .left( 1, {Src} ), # )
 | 
						|
		addw_ Addr,(.right( .tcount( {Src} )-1, {Src} ))
 | 
						|
	.else
 | 
						|
		lda Addr
 | 
						|
		clc
 | 
						|
		adc Src
 | 
						|
		sta Addr
 | 
						|
		
 | 
						|
		lda 1+(Addr)
 | 
						|
		adc 1+(Src)
 | 
						|
		sta 1+(Addr)
 | 
						|
	.endif
 | 
						|
.endmacro
 | 
						|
.macro addw_ Addr, Imm
 | 
						|
	lda Addr
 | 
						|
	clc
 | 
						|
	adc #<Imm
 | 
						|
	sta Addr
 | 
						|
	
 | 
						|
	;.if (Imm >> 8) <> 0
 | 
						|
		lda 1+(Addr)
 | 
						|
		adc #>Imm
 | 
						|
		sta 1+(Addr)
 | 
						|
	;.else
 | 
						|
	;   .local @Skip
 | 
						|
	;   bcc @Skip
 | 
						|
	;   inc 1+(Addr)
 | 
						|
	;@Skip:
 | 
						|
	;.endif
 | 
						|
.endmacro
 | 
						|
 | 
						|
; Splits list of words into tables of low and high bytes
 | 
						|
; Example: split_words foo, {$1234, $5678}
 | 
						|
; expands to:
 | 
						|
; foo_l: $34, $78
 | 
						|
; foo_h: $12, $56
 | 
						|
; foo_count = 2
 | 
						|
.macro split_words Label, Words
 | 
						|
	.ident (.concat (.string(Label), "_l")): .lobytes Words
 | 
						|
	.ident (.concat (.string(Label), "_h")): .hibytes Words
 | 
						|
	.ident (.concat (.string(Label), "_count")) = * - .ident (.concat (.string(Label), "_h"))
 | 
						|
.endmacro
 | 
						|
 | 
						|
.macro SELECT Bool, True, False, Extra
 | 
						|
	.ifndef Bool
 | 
						|
		False Extra
 | 
						|
	.elseif Bool <> 0
 | 
						|
		True Extra
 | 
						|
	.else
 | 
						|
		False Extra
 | 
						|
	.endif
 | 
						|
.endmacro
 | 
						|
 | 
						|
.macro DEFAULT Name, Value
 | 
						|
	.ifndef Name
 | 
						|
		Name = Value
 | 
						|
	.endif
 | 
						|
.endmacro
 | 
						|
 | 
						|
.ifp02
 | 
						|
	; 6502 doesn't define these alternate names
 | 
						|
	.define blt bcc
 | 
						|
	.define bge bcs
 | 
						|
.endif
 | 
						|
.define jlt jcc
 | 
						|
.define jge jcs
 | 
						|
 | 
						|
; Jxx Target = Bxx Target, except it can go farther than
 | 
						|
; 128 bytes. Implemented via branch around a JMP.
 | 
						|
 | 
						|
; Don't use ca65's longbranch, because they fail for @labels
 | 
						|
;.macpack longbranch
 | 
						|
 | 
						|
.macro jeq Target
 | 
						|
	bne *+5
 | 
						|
	jmp Target
 | 
						|
.endmacro
 | 
						|
 | 
						|
.macro jne Target
 | 
						|
	beq *+5
 | 
						|
	jmp Target
 | 
						|
.endmacro
 | 
						|
 | 
						|
.macro jmi Target
 | 
						|
	bpl *+5
 | 
						|
	jmp Target
 | 
						|
.endmacro
 | 
						|
 | 
						|
.macro jpl Target
 | 
						|
	bmi *+5
 | 
						|
	jmp Target
 | 
						|
.endmacro
 | 
						|
 | 
						|
.macro jcs Target
 | 
						|
	bcc *+5
 | 
						|
	jmp Target
 | 
						|
.endmacro
 | 
						|
 | 
						|
.macro jcc Target
 | 
						|
	bcs *+5
 | 
						|
	jmp Target
 | 
						|
.endmacro
 | 
						|
 | 
						|
.macro jvs Target
 | 
						|
	bvc *+5
 | 
						|
	jmp Target
 | 
						|
.endmacro
 | 
						|
 | 
						|
.macro jvc Target
 | 
						|
	bvs *+5
 | 
						|
	jmp Target
 | 
						|
.endmacro
 | 
						|
 | 
						|
 | 
						|
; Passes constant data to routine in addr
 | 
						|
; Preserved: A, X, Y
 | 
						|
.macro jsr_with_addr routine,data
 | 
						|
	.local Addr
 | 
						|
	pha
 | 
						|
	lda #<Addr
 | 
						|
	sta addr
 | 
						|
	lda #>Addr
 | 
						|
	sta addr+1
 | 
						|
	pla
 | 
						|
	jsr routine
 | 
						|
	seg_data RODATA,{Addr: data}
 | 
						|
.endmacro
 | 
						|
 | 
						|
; Calls routine multiple times, with A having the
 | 
						|
; value 'start' the first time, 'start+step' the
 | 
						|
; second time, up to 'end' for the last time.
 | 
						|
.macro for_loop routine,start,end,step
 | 
						|
	.local @for_loop
 | 
						|
	lda #start
 | 
						|
@for_loop:
 | 
						|
	pha
 | 
						|
	jsr routine
 | 
						|
	pla
 | 
						|
	clc
 | 
						|
	adc #step
 | 
						|
	cmp #<((end)+(step))
 | 
						|
	bne @for_loop
 | 
						|
.endmacro
 | 
						|
 | 
						|
; Calls routine n times. The value of A in the routine
 | 
						|
; counts from 0 to n-1.
 | 
						|
.macro loop_n_times routine,n
 | 
						|
	for_loop routine,0,n-1,+1
 | 
						|
.endmacro
 | 
						|
 | 
						|
; Same as for_loop, except uses 16-bit value in YX.
 | 
						|
; -256 <= step <= 255
 | 
						|
.macro for_loop16 routine,start,end,step
 | 
						|
.if (step) < -256 || (step) > 255
 | 
						|
	.error "Step must be within -256 to 255"
 | 
						|
.endif
 | 
						|
	.local @for_loop_skip
 | 
						|
	.local @for_loop
 | 
						|
	ldy #>(start)
 | 
						|
	lda #<(start)
 | 
						|
@for_loop:
 | 
						|
	tax
 | 
						|
	pha
 | 
						|
	tya
 | 
						|
	pha
 | 
						|
	jsr routine
 | 
						|
	pla
 | 
						|
	tay
 | 
						|
	pla
 | 
						|
	clc
 | 
						|
	adc #step
 | 
						|
.if (step) > 0
 | 
						|
	bcc @for_loop_skip
 | 
						|
	iny
 | 
						|
.else
 | 
						|
	bcs @for_loop_skip
 | 
						|
	dey
 | 
						|
.endif
 | 
						|
@for_loop_skip:
 | 
						|
	cmp #<((end)+(step))
 | 
						|
	bne @for_loop
 | 
						|
	cpy #>((end)+(step))
 | 
						|
	bne @for_loop
 | 
						|
.endmacro
 | 
						|
 | 
						|
; Stores byte at addr
 | 
						|
; Preserved: X, Y
 | 
						|
.macro setb addr, byte
 | 
						|
	lda #byte
 | 
						|
	sta addr
 | 
						|
.endmacro
 | 
						|
 | 
						|
; Stores word at addr
 | 
						|
; Preserved: X, Y
 | 
						|
.macro setw addr, word
 | 
						|
	lda #<(word)
 | 
						|
	sta addr
 | 
						|
	lda #>(word)
 | 
						|
	sta addr+1
 | 
						|
.endmacro
 | 
						|
 | 
						|
; Loads XY with 16-bit immediate or value at address
 | 
						|
.macro ldxy Arg
 | 
						|
	.if .match( .left( 1, {Arg} ), # )
 | 
						|
		ldy #<(.right( .tcount( {Arg} )-1, {Arg} ))
 | 
						|
		ldx #>(.right( .tcount( {Arg} )-1, {Arg} ))
 | 
						|
	.else
 | 
						|
		ldy (Arg)
 | 
						|
		ldx (Arg)+1
 | 
						|
	.endif
 | 
						|
.endmacro
 | 
						|
 | 
						|
; Increments XY as 16-bit register, in CONSTANT time.
 | 
						|
; Z flag set based on entire result.
 | 
						|
; Preserved: A
 | 
						|
; Time: 7 clocks
 | 
						|
.macro inxy
 | 
						|
	iny ; 2
 | 
						|
	beq *+4 ; 3
 | 
						|
		; -1
 | 
						|
	bne *+3 ; 3
 | 
						|
		; -1
 | 
						|
	inx ; 2
 | 
						|
.endmacro
 | 
						|
 | 
						|
; Negates A and adds it to operand
 | 
						|
.macro subaf Operand
 | 
						|
	eor #$FF
 | 
						|
	sec
 | 
						|
	adc Operand
 | 
						|
.endmacro
 | 
						|
 | 
						|
; Initializes CPU registers to reasonable values
 | 
						|
; Preserved: A, Y
 | 
						|
.macro init_cpu_regs
 | 
						|
	sei
 | 
						|
	cld     ; unnecessary on NES, but might help on clone
 | 
						|
	ldx #$FF
 | 
						|
	txs
 | 
						|
	.ifndef BUILD_NSF
 | 
						|
		inx
 | 
						|
		stx PPUCTRL
 | 
						|
	.endif
 | 
						|
.endmacro
 |