ANESE/roms/tests/cpu/instr_timing/source/1-instr_timing.s
Daniel Prilik 2238090a05 *initial commit
Setting up the project. Also, iNES parsing
2017-10-13 20:18:31 -07:00

331 lines
7.6 KiB
ArmAsm

; Tests instruction timing for all except the 8 branches and 12 halts
;
; Times each instruction by putting it in a loop that counts iterations
; and waits for APU length counter to expire.
CUSTOM_IRQ=1
.include "shell.inc"
zp_byte nothing_failed
zp_byte test_index
zp_byte type_mask
zp_byte saved_sp
stack_copy = $600 ; stack is copied here during instruction test
test_opcode = $705 ; test loop is copied here
irq = test_opcode+2
main:
print_str "Instruction timing test",{newline,newline}
print_str "Takes about 25 seconds. "
print_str "Doesn't time the 8 branches "
print_str "and 12 illegal instructions.",{newline,newline}
set_test 5,"Timing of APU length period, INC zp, LDA abs, AND #imm, or BNE (taken) is wrong."
lda #$29
sta test_index
jsr time_instr
cmp #2
jne test_failed
set_test 0
print_str "Official instructions...",newline
lda #0
jsr test_instrs
bne :+
set_test 2,"Official instruction timing is wrong"
:
print_str {newline,"NOPs and alternate SBC...",newline}
lda #$80
jsr test_instrs
bne :+
set_test 3,"NOPs and alternate SBC timing is wrong"
:
print_str {newline,"Unofficial instructions...",newline}
lda #$40
jsr test_instrs
bne :+
set_test 4,"Unofficial instruction timing is wrong"
:
jmp tests_done
; A -> Type to test
test_instrs:
sta type_mask
setb nothing_failed,1
setb test_index,0
@loop: ldx test_index
lda instr_types,x
and #$F0
cmp type_mask
bne :+
jsr avoid_silent_nsf
jsr @test_instr
: inc test_index
bne @loop
lda nothing_failed
ora test_code
rts
; Tests current instruction in normal and page cross cases
@test_instr:
; No page crossing
lda #2
jsr time_instr
ldy test_index
eor instr_times,y
beq :+
jsr print_failed_instr
jsr print_newline
lda instr_times,y
cmp instr_times_cross,y
bne :+ ; test again only if page crossing time is different
rts
; Page crossing
: lda #3
jsr time_instr
ldy test_index
eor instr_times_cross,y
beq :+
jsr print_failed_instr
print_str " (cross)",newline
: rts
; Prints failed instruction times
; A -> Actual XOR correct
; X -> Actual
; Preserved: Y
print_failed_instr:
pha
lda test_index
jsr print_hex
jsr play_byte
print_str " was "
txa
jsr print_dec
pla
print_str ", should be "
stx temp
eor temp
jsr print_dec
setb nothing_failed,0
rts
; Times a single instruction
; test_index -> Opcode of instruction
; A -> Byte to load into X and Y before running instruction
; X, A <- Cycles instruction took
.align 256
time_instr:
sta temp
ldy test_index
sty test_opcode
; Copy test_opcode to RAM
lda instr_types,y
and #$07
asl a
tay
lda test_addrs-2,y
sta addr
lda test_addrs-1,y
sta addr+1
ldy #1
: lda (addr),y
sta test_opcode,y
iny
cpy #16
bne :-
; Save copy of stack
tsx
stx saved_sp
: lda $100,x
sta stack_copy,x
inx
bne :-
; Set zero-page values so the addressing modes use the following
; when X and Y = $02/$03
; zp $FD
; zp,x $FF/$00
; abs $03FD
; abs,x/y $03FF/$0400
; (ind,x) $02FD/$0302
; (ind),y $02FF/$0300
; JMP (ind) test_opcode+3
setb <$00,$02
setb <$01,$03
setb <$FD,$FD
setb <$FE,$02
setb <$FF,$FD
lda temp ; $A3 LAX (ab,X) will load X from these two
sta $02FD
sta $0302
setw $03FD,test_opcode+3 ; JMP ($03FD) will use this address
; Fill stack for RTS/RTI test
ldx #$FF
txs
inx
lda #>test_opcode
: pha
inx
bne :-
; Setup registers
lda temp
tay
tax
setb temp,0
; Synchronize with APU length counter
setb SNDMODE,$40
setb SNDCHN,$01
setb $4000,$10
setb $4001,$7F
setb $4002,$FF
setb $4003,$18
lda #$01
: and SNDCHN
bne :-
; Setup length counter
setb $4003,$18
; ~26323 delay, so length counter will be ~3500 cycles from expiring
setb temp3,-13
setb temp2,-207
: inc temp2
bne :-
inc temp3
bne :-
; Run instruction
jmp test_opcode
raw_to_cycles: ; entry i is lowest value that qualifies for i cycles
.byte 241, 226, 212, 200, 189, 179, 171, 163, 156, 149, 0
; Jumps here when instruction has been timed
instr_done:
; Restore things in case instruction affected them
sei
cld
; Convert iteration count to cycle count
lda temp
ldy #-1
: iny
cmp raw_to_cycles,y
blt :-
; Convert 10+ to 0
cpy #10
blt :+
ldy #0
:
; Restore stack
ldx saved_sp
txs
: lda stack_copy,x
sta $100,x
inx
bne :-
tya
tax
rts
.macro instr_template instr
: instr
inc temp
lda SNDCHN
and #$01
bne :-
jmp instr_done
.endmacro
test_1: instr_template nop
test_2: instr_template sta <$FD
test_3: instr_template sta $03FD
test_4: instr_template jmp test_opcode+3
test_addrs:
.word test_1, test_2, test_3, test_4
; $8n = unofficial NOPs and $EB equivalent of SBC #imm
; $4n = all other unofficial opcodes
; $0n = official opcodes
; -1 = not tested
; n = instruction length
instr_types:
; 0 1 2 3 4 5 6 7 8 9 A B C D E F
.byte 2, 2, -1,$42,$82, 2, 2,$42, 1, 2, 1,$42,$83, 3, 3,$43 ; 0
.byte -1, 2, -1,$42,$82, 2, 2,$42, 1, 3,$81,$43,$83, 3, 3,$43 ; 1
.byte 4, 2, -1,$42, 2, 2, 2,$42, 1, 2, 1,$42, 3, 3, 3,$43 ; 2
.byte -1, 2, -1,$42,$82, 2, 2,$42, 1, 3,$81,$43,$83, 3, 3,$43 ; 3
.byte 2, 2, -1,$42,$82, 2, 2,$42, 1, 2, 1,$42, 4, 3, 3,$43 ; 4
.byte -1, 2, -1,$42,$82, 2, 2,$42, 1, 3,$81,$43,$83, 3, 3,$43 ; 5
.byte 3, 2, -1,$42,$82, 2, 2,$42, 1, 2, 1,$42, 3, 3, 3,$43 ; 6
.byte -1, 2, -1,$42,$82, 2, 2,$42, 1, 3,$81,$43,$83, 3, 3,$43 ; 7
.byte $82, 2,$82,$42, 2, 2, 2,$42, 1,$82, 1,$42, 3, 3, 3,$43 ; 8
.byte -1, 2, -1,$42, 2, 2, 2,$42, 1, 3, 1,$43,$43, 3,$43,$43 ; 9
.byte 2, 2, 2,$42, 2, 2, 2,$42, 1, 2, 1,$42, 3, 3, 3,$43 ; A
.byte -1, 2, -1,$42, 2, 2, 2,$42, 1, 3, 1,$43, 3, 3, 3,$43 ; B
.byte 2, 2,$82,$42, 2, 2, 2,$42, 1, 2, 1,$42, 3, 3, 3,$43 ; C
.byte -1, 2, -1,$42,$82, 2, 2,$42, 1, 3,$81,$43,$83, 3, 3,$43 ; D
.byte 2, 2,$82,$42, 2, 2, 2,$42, 1, 2, 1,$82, 3, 3, 3,$43 ; E
.byte -1, 2, -1,$42,$82, 2, 2,$42, 1, 3,$81,$43,$83, 3, 3,$43 ; F
; Bxx HLT
; Clocks when no page crossing occurs
instr_times:
; 0 1 2 3 4 5 6 7 8 9 A B C D E F
.byte 7,6,0,8,3,3,5,5,3,2,2,2,4,4,6,6 ; 0
.byte 0,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7 ; 1
.byte 6,6,0,8,3,3,5,5,4,2,2,2,4,4,6,6 ; 2
.byte 0,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7 ; 3
.byte 6,6,0,8,3,3,5,5,3,2,2,2,3,4,6,6 ; 4
.byte 0,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7 ; 5
.byte 6,6,0,8,3,3,5,5,4,2,2,2,5,4,6,6 ; 6
.byte 0,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7 ; 7
.byte 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4 ; 8
.byte 0,6,0,6,4,4,4,4,2,5,2,5,5,5,5,5 ; 9
.byte 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4 ; A
.byte 0,5,0,5,4,4,4,4,2,4,2,4,4,4,4,4 ; B
.byte 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6 ; C
.byte 0,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7 ; D
.byte 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6 ; E
.byte 0,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7 ; F
; Clocks when page crossing occurs
instr_times_cross:
; 0 1 2 3 4 5 6 7 8 9 A B C D E F
.byte 7,6,0,8,3,3,5,5,3,2,2,2,4,4,6,6 ; 0
.byte 0,6,0,8,4,4,6,6,2,5,2,7,5,5,7,7 ; 1
.byte 6,6,0,8,3,3,5,5,4,2,2,2,4,4,6,6 ; 2
.byte 0,6,0,8,4,4,6,6,2,5,2,7,5,5,7,7 ; 3
.byte 6,6,0,8,3,3,5,5,3,2,2,2,3,4,6,6 ; 4
.byte 0,6,0,8,4,4,6,6,2,5,2,7,5,5,7,7 ; 5
.byte 6,6,0,8,3,3,5,5,4,2,2,2,5,4,6,6 ; 6
.byte 0,6,0,8,4,4,6,6,2,5,2,7,5,5,7,7 ; 7
.byte 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4 ; 8
.byte 0,6,0,6,4,4,4,4,2,5,2,5,5,5,5,5 ; 9
.byte 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4 ; A
.byte 0,6,0,6,4,4,4,4,2,5,2,5,5,5,5,5 ; B
.byte 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6 ; C
.byte 0,6,0,8,4,4,6,6,2,5,2,7,5,5,7,7 ; D
.byte 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6 ; E
.byte 0,6,0,8,4,4,6,6,2,5,2,7,5,5,7,7 ; F