-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_nesemulator.py
180 lines (166 loc) · 8.4 KB
/
test_nesemulator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# tests/test_nesemulator.py
# From Computer Science from Scratch
# Copyright 2021-2022 David Kopec
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# DESCRIPTION
# Tries running multiple different tests to verify the correctness of our emulator.
import unittest
from pathlib import Path
from NESEmulator.cpu import CPU
from NESEmulator.ppu import PPU
from NESEmulator.rom import ROM
class CPUTestCase(unittest.TestCase):
def setUp(self) -> None:
self.test_folder = (Path(__file__).resolve().parent.parent
/ 'NESEmulator' / 'Tests')
def test_nes_test(self):
# Create machinery that we are testing
rom = ROM(self.test_folder / "nestest" / "nestest.nes")
ppu = PPU(rom)
cpu = CPU(ppu, rom)
# Set up tests
cpu.PC = 0xC000 # special starting location for tests
with open(self.test_folder / "nestest" / "nestest.log") as f:
correct_lines = f.readlines()
log_line = 1
# Check every line of the log against our own produced logs
while log_line < 5260: # go until first unofficial opcode test
our_line = cpu.log()
correct_line = correct_lines[log_line - 1]
self.assertEqual(correct_line[0:14], our_line[0:14],
f"PC/Opcode doesn't match at line {log_line}")
self.assertEqual(correct_line[48:73], our_line[48:73],
f"Registers don't match at line {log_line}")
cpu.step()
log_line += 1
def test_blargg_instr_test_v5_basics(self):
# Create machinery that we are testing
rom = ROM(self.test_folder / "instr_test-v5" / "rom_singles" / "01-basics.nes")
ppu = PPU(rom)
cpu = CPU(ppu, rom)
# Tests run as long as 0x6000 is 80, and then 0x6000 is result code; 0 means success
rom.prg_ram[0] = 0x80
while rom.prg_ram[0] == 0x80: # go until first unofficial opcode test
cpu.step()
self.assertEqual(0, rom.prg_ram[0],
f"Result code of basics test is {rom.prg_ram[0]} not 0")
message = bytes(rom.prg_ram[4:]).decode("utf-8")
print(message[0:message.index("\0")]) # message ends with null terminator
def test_blargg_instr_test_v5_implied(self):
# Create machinery that we are testing
rom = ROM(self.test_folder / "instr_test-v5" / "rom_singles" / "02-implied.nes")
ppu = PPU(rom)
cpu = CPU(ppu, rom)
# Tests run as long as 0x6000 is 80, and then 0x6000 is result code; 0 means success
rom.prg_ram[0] = 0x80
while rom.prg_ram[0] == 0x80: # go until first unofficial opcode test
cpu.step()
self.assertEqual(0, rom.prg_ram[0],
f"Result code of implied test is {rom.prg_ram[0]} not 0")
message = bytes(rom.prg_ram[4:]).decode("utf-8")
print(message[0:message.index("\0")]) # message ends with null terminator
def test_blargg_instr_test_v5_branches(self):
# Create machinery that we are testing
rom = ROM(self.test_folder / "instr_test-v5" / "rom_singles" / "10-branches.nes")
ppu = PPU(rom)
cpu = CPU(ppu, rom)
# Tests run as long as 0x6000 is 80, and then 0x6000 is result code; 0 means success
rom.prg_ram[0] = 0x80
while rom.prg_ram[0] == 0x80: # go until first unofficial opcode test
cpu.step()
self.assertEqual(0, rom.prg_ram[0],
f"Result code of braches test is {rom.prg_ram[0]} not 0")
message = bytes(rom.prg_ram[4:]).decode("utf-8")
print(message[0:message.index("\0")]) # message ends with null terminator
def test_blargg_instr_test_v5_stack(self):
# Create machinery that we are testing
rom = ROM(self.test_folder / "instr_test-v5" / "rom_singles" / "11-stack.nes")
ppu = PPU(rom)
cpu = CPU(ppu, rom)
# Tests run as long as 0x6000 is 80, and then 0x6000 is result code; 0 means success
rom.prg_ram[0] = 0x80
while rom.prg_ram[0] == 0x80: # go until first unofficial opcode test
cpu.step()
self.assertEqual(0, rom.prg_ram[0],
f"Result code of stack test is {rom.prg_ram[0]} not 0")
message = bytes(rom.prg_ram[4:]).decode("utf-8")
print(message[0:message.index("\0")]) # message ends with null terminator
def test_blargg_instr_test_v5_jmp_jsr(self):
# Create machinery that we are testing
rom = ROM(self.test_folder / "instr_test-v5" / "rom_singles" / "12-jmp_jsr.nes")
ppu = PPU(rom)
cpu = CPU(ppu, rom)
# Tests run as long as 0x6000 is 80, and then 0x6000 is result code; 0 means success
rom.prg_ram[0] = 0x80
while rom.prg_ram[0] == 0x80: # go until first unofficial opcode test
cpu.step()
self.assertEqual(0, rom.prg_ram[0],
f"Result code of jmp_jsr test is {rom.prg_ram[0]} not 0")
message = bytes(rom.prg_ram[4:]).decode("utf-8")
print(message[0:message.index("\0")]) # message ends with null terminator
def test_blargg_instr_test_v5_rts(self):
# Create machinery that we are testing
rom = ROM(self.test_folder / "instr_test-v5" / "rom_singles" / "13-rts.nes")
ppu = PPU(rom)
cpu = CPU(ppu, rom)
# Tests run as long as 0x6000 is 80, and then 0x6000 is result code; 0 means success
rom.prg_ram[0] = 0x80
while rom.prg_ram[0] == 0x80: # go until first unofficial opcode test
cpu.step()
self.assertEqual(0, rom.prg_ram[0],
f"Result code of rts test is {rom.prg_ram[0]} not 0")
message = bytes(rom.prg_ram[4:]).decode("utf-8")
print(message[0:message.index("\0")]) # message ends with null terminator
def test_blargg_instr_test_v5_rti(self):
# Create machinery that we are testing
rom = ROM(self.test_folder / "instr_test-v5" / "rom_singles" / "14-rti.nes")
ppu = PPU(rom)
cpu = CPU(ppu, rom)
# Tests run as long as 0x6000 is 80, and then 0x6000 is result code; 0 means success
rom.prg_ram[0] = 0x80
while rom.prg_ram[0] == 0x80: # go until first unofficial opcode test
cpu.step()
self.assertEqual(0, rom.prg_ram[0],
f"Result code of rti test is {rom.prg_ram[0]} not 0")
message = bytes(rom.prg_ram[4:]).decode("utf-8")
print(message[0:message.index("\0")]) # message ends with null terminator
def test_blargg_instr_test_v5_brk(self):
# Create machinery that we are testing
rom = ROM(self.test_folder / "instr_test-v5" / "rom_singles" / "15-brk.nes")
ppu = PPU(rom)
cpu = CPU(ppu, rom)
# Tests run as long as 0x6000 is 80, and then 0x6000 is result code; 0 means success
rom.prg_ram[0] = 0x80
while rom.prg_ram[0] == 0x80: # go until first unofficial opcode test
cpu.step()
message = bytes(rom.prg_ram[4:]).decode("utf-8")
print(message[0:message.index("\0")]) # message ends with null terminator
self.assertEqual(0, rom.prg_ram[0],
f"Result code of brk test is {rom.prg_ram[0]} not 0")
def test_blargg_instr_test_v5_special(self):
# Create machinery that we are testing
rom = ROM(self.test_folder / "instr_test-v5" / "rom_singles" / "16-special.nes")
ppu = PPU(rom)
cpu = CPU(ppu, rom)
# Tests run as long as 0x6000 is 80, and then 0x6000 is result code; 0 means success
rom.prg_ram[0] = 0x80
while rom.prg_ram[0] == 0x80: # go until first unofficial opcode test
cpu.step()
message = bytes(rom.prg_ram[4:]).decode("utf-8")
print(message[0:message.index("\0")]) # message ends with null terminator
self.assertEqual(0, rom.prg_ram[0],
f"Result code of special test is {rom.prg_ram[0]} not 0")
if __name__ == "__main__":
unittest.main()