2020-11-03 02:09:32 +00:00
//
// k r o m 6 5 8 1 6 T e s t s . s w i f t
// C l o c k S i g n a l
//
// C r e a t e d b y T h o m a s H a r t e o n 0 2 / 1 1 / 2 0 2 0 .
// C o p y r i g h t 2 0 2 0 T h o m a s H a r t e . A l l r i g h t s r e s e r v e d .
//
import Foundation
import XCTest
// T h i s u t i l i s e s k r o m ' s S N E S - c e n t r i c 6 5 8 1 6 t e s t s , c o m p a r i n g s t e p - b y - s t e p t o
// t h e t r a c e s o f f e r e d b y L i l a Q a t e m u d e v . d e a s I d o n ' t w a n t t o i m p l e m e n t a
// S N E S j u s t f o r t h e s a k e o f r e s u l t i n s p e c t i o n .
//
// S o :
// h t t p s : / / g i t h u b . c o m / P e t e r L e m o n / S N E S / t r e e / m a s t e r / C P U T e s t / C P U f o r t h e t e s t s ;
// h t t p s : / / e m u d e v . d e / q 0 0 - s n e s / 6 5 8 1 6 - t h e - c p u / f o r t h e t r a c e s .
class Krom65816Tests : XCTestCase {
2020-11-04 01:59:07 +00:00
// MARK: - T e s t R u n n e r
2020-11-03 02:09:32 +00:00
2020-11-05 21:36:34 +00:00
func runTest ( _ name : String , pcLimit : UInt32 ? = nil ) {
2020-11-03 02:09:32 +00:00
var testData : Data ?
2020-11-05 21:42:39 +00:00
if let filename = Bundle ( for : type ( of : self ) ) . url ( forResource : name , withExtension : " sfc " ) {
testData = try ? Data ( contentsOf : filename )
2020-11-03 02:09:32 +00:00
}
var testOutput : String ?
2020-11-05 21:42:39 +00:00
if let filename = Bundle ( for : type ( of : self ) ) . url ( forResource : name + " -trace_compare " , withExtension : " log " ) {
testOutput = try ? String ( contentsOf : filename )
2020-11-03 02:09:32 +00:00
}
XCTAssertNotNil ( testData )
XCTAssertNotNil ( testOutput )
let outputLines = testOutput ! . components ( separatedBy : " \r \n " )
// A s s u m p t i o n s a b o u t t h e S F C f i l e f o r m a t f o l l o w ; I c o u l d n ' t f i n d a s p e c b u t t h o s e
// p r o d u c e d b y k r o m a p p e a r j u s t t o b e b i n a r y d u m p s . F i n g e r s c r o s s e d !
let machine = CSTestMachine6502 ( processor : . processor65816 )
machine . setData ( testData ! , atAddress : 0x8000 )
// T h i s r e p r o d u c e s t h e s t a t e s e e n a t t h e f i r s t l i n e o f a l l o f L i l a Q ' s t r a c e s ;
// TODO: d e t e r m i n e w h e t h e r ( i ) t h i s i s t h e S N E S s t a t e a t r e s e t , o r m e r e l y h o w
// s o m e s o r t o f B I O S l e a v e s i t ; a n d ( i i ) i f t h e f o r m e r , w h e t h e r I h a v e p o s t - r e s e t
// s t a t e i n c o r r e c t . I s t r o n g l y s u s p e c t i t ' s a S N E S - s p e c i f i c a r t e f a c t ?
machine . setValue ( 0x8000 , for : . programCounter )
machine . setValue ( 0x0000 , for : . A )
machine . setValue ( 0x0000 , for : . X )
machine . setValue ( 0x0000 , for : . Y )
machine . setValue ( 0x00ff , for : . stackPointer )
machine . setValue ( 0x34 , for : . flags )
2020-11-04 01:01:02 +00:00
// T h e r e s e e m s t o b e s o m e N i n t e n d o - s p e c i a l r e g i s t e r a t a d d r e s s 0 x 0 0 0 0 .
machine . setValue ( 0xb5 , forAddress : 0x0000 )
2020-11-03 19:18:40 +00:00
// P o k e s o m e f i x e d v a l u e s f o r S N E S r e g i s t e r s t o g e t p a s t i n i t i a l s e t u p .
machine . setValue ( 0x42 , forAddress : 0x4210 ) // " R D N M I " , a p p a r e n t l y ; t h i s s a y s : C P U v e r s i o n 2 , v b l a n k i n t e r r u p t r e q u e s t .
var allowNegativeError = false
2020-11-03 02:09:32 +00:00
var lineNumber = 1
2020-11-03 19:18:40 +00:00
var previousPC = 0
2020-11-03 02:09:32 +00:00
for line in outputLines {
2020-11-03 23:12:10 +00:00
// A t l e a s t o n e o f t h e t r a c e s e n d s w i t h a n e m p t y l i n e ; m y p r e f e r e n c e i s n o t t o
// m o d i f y t h e o r i g i n a l s i f p o s s i b l e .
if line = = " " {
break
}
2020-11-03 02:09:32 +00:00
machine . runForNumber ( ofInstructions : 1 )
2020-11-04 01:59:07 +00:00
let newPC = Int ( machine . value ( for : . lastOperationAddress ) )
// S t o p r i g h t n o w i f a P C l i m i t h a s b e e n s p e c i f i e d a n d t h i s i s i t .
if let pcLimit = pcLimit , pcLimit = = newPC {
break
}
2020-11-03 02:09:32 +00:00
2020-11-03 19:18:40 +00:00
func machineState ( ) -> String {
// F o r m u l a t e m y 6 5 8 1 6 s t a t e i n t h e s a m e f o r m a s t h e t e s t m a c h i n e
var cpuState = " "
let emulationFlag = machine . value ( for : . emulationFlag ) != 0
cpuState += String ( format : " %06x " , machine . value ( for : . lastOperationAddress ) )
cpuState += String ( format : " A:%04x " , machine . value ( for : . A ) )
cpuState += String ( format : " X:%04x " , machine . value ( for : . X ) )
cpuState += String ( format : " Y:%04x " , machine . value ( for : . Y ) )
if emulationFlag {
cpuState += String ( format : " S:01%02x " , machine . value ( for : . stackPointer ) )
} else {
cpuState += String ( format : " S:%04x " , machine . value ( for : . stackPointer ) )
}
cpuState += String ( format : " D:%04x " , machine . value ( for : . direct ) )
cpuState += String ( format : " DB:%02x " , machine . value ( for : . dataBank ) )
let flags = machine . value ( for : . flags )
cpuState += ( flags & 0x80 ) != 0 ? " N " : " n "
cpuState += ( flags & 0x40 ) != 0 ? " V " : " v "
if emulationFlag {
cpuState += " 1B "
} else {
cpuState += ( flags & 0x20 ) != 0 ? " M " : " m "
cpuState += ( flags & 0x10 ) != 0 ? " X " : " x "
}
cpuState += ( flags & 0x08 ) != 0 ? " D " : " d "
cpuState += ( flags & 0x04 ) != 0 ? " I " : " i "
cpuState += ( flags & 0x02 ) != 0 ? " Z " : " z "
cpuState += ( flags & 0x01 ) != 0 ? " C " : " c "
cpuState += " "
return cpuState
2020-11-03 02:09:32 +00:00
}
2020-11-03 19:18:40 +00:00
// P e r m i t a f i x - u p o f t h e n e g a t i v e f l a g o n l y i f t h i s l i n e f o l l o w e d a t e s t o f $ 4 2 1 0 .
var cpuState = machineState ( )
if cpuState != line && allowNegativeError {
machine . setValue ( machine . value ( for : . flags ) ^ 0x80 , for : . flags )
cpuState = machineState ( )
}
2020-11-03 02:09:32 +00:00
2020-11-03 19:18:40 +00:00
XCTAssertEqual ( cpuState , line , " Mismatch on line # \( lineNumber ) ; after instruction # \( String ( format : " %02x " , machine . value ( forAddress : UInt32 ( previousPC ) ) ) ) " )
2020-11-03 02:09:32 +00:00
if cpuState != line {
break
}
lineNumber += 1
2020-11-04 01:59:07 +00:00
previousPC = newPC
2020-11-03 19:18:40 +00:00
// C h e c k w h e t h e r a ' R D N M I ' t o g g l e n e e d s t o h a p p e n b y p e e k i n g a t t h e n e x t i n s t r u c t i o n ;
// i f i t ' s B I T $ 4 2 1 0 t h e n t o g g l e t h e t o p b i t a t a d d r e s s $ 4 2 1 0 .
//
// C o u p l i n g h e r e : a s s u m e t h a t b y t h e t i m e t h e t e s t 6 5 8 1 6 i s a w a r e i t ' s o n a n e w i n s t r u c t i o n
// i t ' s b e c a u s e t h e a c t u a l 6 5 8 1 6 h a s r e a d a n e w o p c o d e , a n d t h a t i f t h e 6 5 8 1 6 h a s j u s t r e a d
// a n e w o p c o d e t h e n i t h a s a l r e a d y a d v a n c e d t h e p r o g r a m c o u n t e r .
let programCounter = machine . value ( for : . programCounter )
let nextInstr = [
machine . value ( forAddress : UInt32 ( programCounter - 1 ) ) ,
machine . value ( forAddress : UInt32 ( programCounter + 0 ) ) ,
machine . value ( forAddress : UInt32 ( programCounter + 1 ) )
]
allowNegativeError = nextInstr [ 0 ] = = 0x2c && nextInstr [ 1 ] = = 0x10 && nextInstr [ 2 ] = = 0x42
2020-11-03 02:09:32 +00:00
}
}
// MARK: - T e s t s
2020-11-03 19:18:40 +00:00
func testADC ( ) { runTest ( " CPUADC " ) }
func testAND ( ) { runTest ( " CPUAND " ) }
func testASL ( ) { runTest ( " CPUASL " ) }
func testBIT ( ) { runTest ( " CPUBIT " ) }
func testBRA ( ) { runTest ( " CPUBRA " ) }
func testCMP ( ) { runTest ( " CPUCMP " ) }
func testDEC ( ) { runTest ( " CPUDEC " ) }
func testEOR ( ) { runTest ( " CPUEOR " ) }
func testINC ( ) { runTest ( " CPUINC " ) }
func testJMP ( ) { runTest ( " CPUJMP " ) }
func testLDR ( ) { runTest ( " CPULDR " ) }
func testLSR ( ) { runTest ( " CPULSR " ) }
func testMOV ( ) { runTest ( " CPUMOV " ) }
func testORA ( ) { runTest ( " CPUORA " ) }
func testPHL ( ) { runTest ( " CPUPHL " ) }
func testPSR ( ) { runTest ( " CPUPSR " ) }
func testROL ( ) { runTest ( " CPUROL " ) }
func testROR ( ) { runTest ( " CPUROR " ) }
func testSBC ( ) { runTest ( " CPUSBC " ) }
func testSTR ( ) { runTest ( " CPUSTR " ) }
func testTRN ( ) { runTest ( " CPUTRN " ) }
2020-11-03 02:09:32 +00:00
2020-11-04 01:59:07 +00:00
// E n s u r e t h e M S C t e s t s s t o p b e f o r e t h e y a t t e m p t t o t e s t S T P a n d W A I ;
// t h e t e s t r e l i e s o n S N E S m e a n s f o r s c h e d u l i n g a f u t u r e i n t e r r u p t .
func testMSC ( ) { runTest ( " CPUMSC " , pcLimit : 0x8523 ) }
2020-11-03 02:09:32 +00:00
}