REGION_FREE = 1
.include "shell.inc"
.include "crc_fast.s"

zp_byte in_p
zp_byte in_a
zp_byte in_x
zp_byte in_y
zp_byte in_s

.macro entry opcode,name,crc_0,crc_1,crc_2,crc_3
	jsr reset_crc
	lda #opcode
	sta opcode_byte - testcase_entry + testcase_instance
	jsr run_testcase
	; testcase_0  OPERANDS + 4,{testcase opcode}
	lda checksum
	cmp #crc_0
	jne fail
	lda checksum+1
	cmp #crc_1
	jne fail
	lda checksum+2
	cmp #crc_2
	jne fail
	lda checksum+3
	cmp #crc_3
	jne fail
.endmacro

testcase_entry:
	lda in_p
	pha
	lda in_a
	ldx in_x
	ldy in_y
	plp
opcode_byte: .byte 0
	.if OPERANDS > 0
	; .out .sprintf(" 1: %s", .string(op_1))
	.byte 0
	.endif
	.if OPERANDS > 1
	; .out .sprintf(" 2: %s", .string(op_2))
	.byte 0
	.endif
	php
	pha
	txa
	pha
	tya
	pha
	; Stack: <y, x, a, p>
	pla
	jsr update_crc_fast
	pla
	jsr update_crc_fast
	pla
	jsr update_crc_fast
	pla
	jsr update_crc_fast
	rts
testcase_entry_size = * - testcase_entry

; .macro testcase opcode, reg_p, reg_a, reg_x, reg_y, op_1, op_2
	; jsr crc_calc
	; .out .sprintf("OP: %s", .string(opcode))
	; .out .sprintf(" S: %s", .string(reg_p))
	; .out .sprintf(" A: %s", .string(reg_a))
	; .out .sprintf(" X: %s", .string(reg_x))
	; .out .sprintf(" Y: %s", .string(reg_y))
; .endmacro
; .macro testcase_6 opcode, ops
; 	testcase opcode, ops
; 	; .mid(0, 1, ops), .mid(1, 1, ops), .mid(2, 1, ops), .mid(3, 1, ops), .mid(4, 1, ops), .mid(5, 1, ops)
; .endmacro
; .macro testcase_0 count,ins
; 	.if count > 0
; 		testcase_0 count - 1, {ins,0}
; 		testcase_0 count - 1, {ins,1}
; 		testcase_0 count - 1, {ins,2}
; 		testcase_0 count - 1, {ins,$40}
; 		testcase_0 count - 1, {ins,$7F}
; 		testcase_0 count - 1, {ins,$80}
; 		testcase_0 count - 1, {ins,$81}
; 		testcase_0 count - 1, {ins,$FF}
; 		; .byte 0,1,2,$40,$7F,$80,$81,$FF
; 	.else
; 		ins
; 	.endif
; .endmacro
.pushseg
.segment "BSS"
testcase_instance: .res testcase_entry_size
.popseg

testcase_init:
	ldx #0
@loop:  lda testcase_entry,x
	sta testcase_instance,x
	inx
	cpx #testcase_entry_size
	bmi @loop
	rts

; values:
; 	.byte 0,1,2,$40,$7F,$80,$81,$FF
; values_size = * - values
	; .byte 0,1,2,$40,$7F,$80,$81,$FF
.macro increment pos, next, done
	lda pos
	cmp #0
	bne @a_1
	lda #1
	sta pos
	jmp done
@a_1:   cmp #1
	bne @a_2
	lda #2
	sta pos
	jmp done
@a_2:   cmp #2
	bne @a_40
	lda #40
	sta pos
	jmp done
@a_40:  cmp #$40
	bne @a_7F
	lda #$7F
	sta pos
	jmp done
@a_7F:  cmp #$7F
	bne @a_80
	lda #$80
	sta pos
	jmp done
@a_80:  cmp #$80
	bne @a_81
	lda #$81
	sta pos
	jmp done
@a_81:  cmp #$81
	bne @a_FF
	lda #$FF
	sta pos
	jmp done
@a_FF:  cmp #$FF
	lda #0
	sta pos
	jmp next
.endmacro
run_testcase:
	increment in_a, increment_x, done
increment_x:
	increment in_x, increment_y, done
increment_y:
	increment in_y, increment_p, done
increment_p:
	increment in_p, ret, done
done:
	jsr testcase_instance
	jmp run_testcase
ret:
	rts

; Defines instruction to test

; Values set_paxyso sets registers to. Set
; before calling test_values, which can then
; overwrite them if desired.

; Temporary space for check_paxyso
zp_byte out_a
zp_byte out_x
zp_byte out_s

; Values to cycle through for registers

; ; Sets bytes on stack around in_s
; .macro set_stack
; 	ldx in_s
; 	inx
; 	inx
; 	ldy #6
; :       txa
; 	asl
; 	eor #$A5
; 	sta $100,x
; 	dex
; 	dey
; 	bne :-
; .endmacro

; ; Checksums bytes on stack around in_s
; .macro check_stack
; 	ldx in_s
; 	inx
; 	inx
; 	ldy #6
; :       lda $100,x
; 	dex
; 	jsr update_crc
; 	dey
; 	bne :-
; .endmacro

; ; Sets P, A, X, Y, S, and operand
; .macro set_paxyso
; 	ldx in_s
; 	txs
; 	lda values,y
; 	sta operand
; 	lda in_p
; 	pha
; 	lda in_a
; 	ldx in_x
; 	ldy in_y
; 	plp
; .endmacro

; ; Checksums P, A, X, Y, S, and operand
; .macro check_paxyso
; 	php
; 	sta out_a
; 	pla
	
; 	stx out_x
; 	tsx
; 	stx out_s
; 	ldx saved_s
; 	txs
	
; 	cld
; 	jsr update_crc_fast
; 	lda out_a
; 	jsr update_crc_fast
; 	lda out_x
; 	jsr update_crc_fast
; 	tya
; 	jsr update_crc_fast
; 	lda out_s
; 	jsr update_crc_fast
; 	lda operand
; 	jsr update_crc_fast
; .endmacro
