Fix HL+, add cpu instr testsuite
This commit is contained in:
parent
e3fce0bcc5
commit
d91fa7d75b
@ -85,9 +85,9 @@ impl Cartridge {
|
|||||||
match addr {
|
match addr {
|
||||||
0x0000 ... 0x3FFF => self.rom[addr as usize],
|
0x0000 ... 0x3FFF => self.rom[addr as usize],
|
||||||
0x4000 ... 0x7FFF => {
|
0x4000 ... 0x7FFF => {
|
||||||
|
let addr = addr - 0x4000;
|
||||||
let abs_addr: usize = addr as usize + self.bank_no as usize * 0x4000;
|
let abs_addr: usize = addr as usize + self.bank_no as usize * 0x4000;
|
||||||
let val: u8 = self.rom[abs_addr];
|
let val: u8 = self.rom[abs_addr];
|
||||||
// println!("Access {:04X}{:04X} = {:02X}", self.bank_no, addr, val);
|
|
||||||
val
|
val
|
||||||
},
|
},
|
||||||
0xA000 ... 0xBFFF => {
|
0xA000 ... 0xBFFF => {
|
||||||
@ -143,7 +143,7 @@ impl Cartridge {
|
|||||||
|
|
||||||
pub fn write_byte(&mut self, addr: u16, val: u8) {
|
pub fn write_byte(&mut self, addr: u16, val: u8) {
|
||||||
match self.mbc_type {
|
match self.mbc_type {
|
||||||
MemoryBankControllerType::None => panic!("Cartridge: No MBC found, can not write to ROM"),
|
MemoryBankControllerType::None => println!("Cartridge: No MBC found, can not write to ROM ({:02X} to {:04X})", val, addr),
|
||||||
MemoryBankControllerType::MBC3 => self.write_byte_mbc3(addr, val),
|
MemoryBankControllerType::MBC3 => self.write_byte_mbc3(addr, val),
|
||||||
_ => panic!("MBC not supported.")
|
_ => panic!("MBC not supported.")
|
||||||
}
|
}
|
||||||
|
|||||||
1406
src/cpu.rs
1406
src/cpu.rs
File diff suppressed because it is too large
Load Diff
@ -135,7 +135,7 @@ impl Display {
|
|||||||
self.vram[(addr - 0x8000) as usize] = val;
|
self.vram[(addr - 0x8000) as usize] = val;
|
||||||
}
|
}
|
||||||
0xFE00 ... 0xFE9F => {
|
0xFE00 ... 0xFE9F => {
|
||||||
println!("OAM: Write {:02X} to {:04X}", val, addr);
|
// println!("OAM: Write {:02X} to {:04X}", val, addr);
|
||||||
self.oam[(addr - 0xFE00) as usize] = val;
|
self.oam[(addr - 0xFE00) as usize] = val;
|
||||||
}
|
}
|
||||||
0xFF40 => self.control = val,
|
0xFF40 => self.control = val,
|
||||||
|
|||||||
@ -63,18 +63,6 @@ impl Interconnect {
|
|||||||
self.disable_bootrom == 0
|
self.disable_bootrom == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn vblank_interrupt(&mut self) -> bool {
|
|
||||||
// This should set 0xFF0F accordingly and the CPU should
|
|
||||||
// handle the interrupt generation. So this is WRONG!
|
|
||||||
// the interrupt WAITS
|
|
||||||
if self.display.vblank_interrupt() && self.interrupt & INTERRUPT_DISPLAY_VBLANK > 0 {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_byte(&self, addr: u16) -> u8 {
|
pub fn read_byte(&self, addr: u16) -> u8 {
|
||||||
// TODO: Make this more beautiful.
|
// TODO: Make this more beautiful.
|
||||||
// TODO: if some flag set, use bios, otherwise only use rom
|
// TODO: if some flag set, use bios, otherwise only use rom
|
||||||
|
|||||||
BIN
tests/cpu_instrs/cpu_instrs.gb
Normal file
BIN
tests/cpu_instrs/cpu_instrs.gb
Normal file
Binary file not shown.
BIN
tests/cpu_instrs/individual/01-special.gb
Normal file
BIN
tests/cpu_instrs/individual/01-special.gb
Normal file
Binary file not shown.
BIN
tests/cpu_instrs/individual/02-interrupts.gb
Normal file
BIN
tests/cpu_instrs/individual/02-interrupts.gb
Normal file
Binary file not shown.
BIN
tests/cpu_instrs/individual/03-op sp,hl.gb
Normal file
BIN
tests/cpu_instrs/individual/03-op sp,hl.gb
Normal file
Binary file not shown.
BIN
tests/cpu_instrs/individual/04-op r,imm.gb
Normal file
BIN
tests/cpu_instrs/individual/04-op r,imm.gb
Normal file
Binary file not shown.
BIN
tests/cpu_instrs/individual/05-op rp.gb
Normal file
BIN
tests/cpu_instrs/individual/05-op rp.gb
Normal file
Binary file not shown.
BIN
tests/cpu_instrs/individual/06-ld r,r.gb
Normal file
BIN
tests/cpu_instrs/individual/06-ld r,r.gb
Normal file
Binary file not shown.
BIN
tests/cpu_instrs/individual/07-jr,jp,call,ret,rst.gb
Normal file
BIN
tests/cpu_instrs/individual/07-jr,jp,call,ret,rst.gb
Normal file
Binary file not shown.
BIN
tests/cpu_instrs/individual/08-misc instrs.gb
Normal file
BIN
tests/cpu_instrs/individual/08-misc instrs.gb
Normal file
Binary file not shown.
BIN
tests/cpu_instrs/individual/09-op r,r.gb
Normal file
BIN
tests/cpu_instrs/individual/09-op r,r.gb
Normal file
Binary file not shown.
BIN
tests/cpu_instrs/individual/10-bit ops.gb
Normal file
BIN
tests/cpu_instrs/individual/10-bit ops.gb
Normal file
Binary file not shown.
BIN
tests/cpu_instrs/individual/11-op a,(hl).gb
Normal file
BIN
tests/cpu_instrs/individual/11-op a,(hl).gb
Normal file
Binary file not shown.
119
tests/cpu_instrs/readme.txt
Normal file
119
tests/cpu_instrs/readme.txt
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
Game Boy CPU Instruction Behavior Test
|
||||||
|
--------------------------------------
|
||||||
|
This ROM tests the behavior of all CPU instructions except STOP and the
|
||||||
|
11 illegal opcodes. The tests are fairly thorough, running instructions
|
||||||
|
with boundary data and verifying both the result and that other
|
||||||
|
registers are not modified. Instructions which perform the same
|
||||||
|
operation on different registers are each tested just as thoroughly, in
|
||||||
|
case an emulator implements each independently. Some sub-tests take half
|
||||||
|
minute to complete.
|
||||||
|
|
||||||
|
Failed instructions are listed as
|
||||||
|
|
||||||
|
[CB] opcode
|
||||||
|
|
||||||
|
Some errors cannot of course be diagnosed properly, since the test
|
||||||
|
framework itself relies on basic instruction behavior being correct.
|
||||||
|
|
||||||
|
|
||||||
|
Internal operation
|
||||||
|
------------------
|
||||||
|
The main tests use a framework that runs each instruction in a loop,
|
||||||
|
varying the register values on input and examining them on output.
|
||||||
|
Rather than keep a table of correct values, it simply calculates a
|
||||||
|
CRC-32 checksum of all the output, then compares this with the correct
|
||||||
|
value. Instructions are divided into several groups, each with a
|
||||||
|
different set of input values suited for their behavior; for example,
|
||||||
|
the bit test instructions are fed $01, $02, $04 ... $40, $80, to ensure
|
||||||
|
each bit is handled properly, while the arithmetic instructions are fed
|
||||||
|
$01, $0F, $10, $7F, $FF, to exercise carry and half-carry. A few
|
||||||
|
instructions require a custom test due to their uniqueness.
|
||||||
|
|
||||||
|
|
||||||
|
Multi-ROM
|
||||||
|
---------
|
||||||
|
In the main directory is a single ROM which runs all the tests. It
|
||||||
|
prints a test's number, runs the test, then "ok" if it passes, otherwise
|
||||||
|
a failure code. Once all tests have completed it either reports that all
|
||||||
|
tests passed, or prints the number of failed tests. Finally, it makes
|
||||||
|
several beeps. If a test fails, it can be run on its own by finding the
|
||||||
|
corresponding ROM in individual/.
|
||||||
|
|
||||||
|
Ths compact format on screen is to avoid having the results scroll off
|
||||||
|
the top, so the test can be started and allowed to run without having to
|
||||||
|
constantly monitor the display.
|
||||||
|
|
||||||
|
Currently there is no well-defined way for an emulator test rig to
|
||||||
|
programatically find the result of the test; contact me if you're trying
|
||||||
|
to do completely automated testing of your emulator. One simple approach
|
||||||
|
is to take a screenshot after all tests have run, or even just a
|
||||||
|
checksum of one, and compare this with a previous run.
|
||||||
|
|
||||||
|
|
||||||
|
Failure codes
|
||||||
|
-------------
|
||||||
|
Failed tests may print a failure code, and also short description of the
|
||||||
|
problem. For more information about a failure code, look in the
|
||||||
|
corresponding source file in source/; the point in the code where
|
||||||
|
"set_test n" occurs is where that failure code will be generated.
|
||||||
|
Failure code 1 is a general failure of the test; any further information
|
||||||
|
will be printed.
|
||||||
|
|
||||||
|
Note that once a sub-test fails, no further tests for that file are run.
|
||||||
|
|
||||||
|
|
||||||
|
Console output
|
||||||
|
--------------
|
||||||
|
Information is printed on screen in a way that needs only minimum LCD
|
||||||
|
support, and won't hang if LCD output isn't supported at all.
|
||||||
|
Specifically, while polling LY to wait for vblank, it will time out if
|
||||||
|
it takes too long, so LY always reading back as the same value won't
|
||||||
|
hang the test. It's also OK if scrolling isn't supported; in this case,
|
||||||
|
text will appear starting at the top of the screen.
|
||||||
|
|
||||||
|
Everything printed on screen is also sent to the game link port by
|
||||||
|
writing the character to SB, then writing $81 to SC. This is useful for
|
||||||
|
tests which print lots of information that scrolls off screen.
|
||||||
|
|
||||||
|
|
||||||
|
Source code
|
||||||
|
-----------
|
||||||
|
Source code is included for all tests, in source/. It can be used to
|
||||||
|
build the individual test ROMs. Code for the multi test isn't included
|
||||||
|
due to the complexity of putting everything together.
|
||||||
|
|
||||||
|
Code is written for the wla-dx assembler. To assemble a particular test,
|
||||||
|
execute
|
||||||
|
|
||||||
|
wla -o "source_filename.s" test.o
|
||||||
|
wlalink linkfile test.gb
|
||||||
|
|
||||||
|
Test code uses a common shell framework contained in common/.
|
||||||
|
|
||||||
|
|
||||||
|
Internal framework operation
|
||||||
|
----------------------------
|
||||||
|
Tests use a common framework for setting things up, reporting results,
|
||||||
|
and ending. All files first include "shell.inc", which sets up the ROM
|
||||||
|
header and shell code, and includes other commonly-used modules.
|
||||||
|
|
||||||
|
One oddity is that test code is first copied to internal RAM at $D000,
|
||||||
|
then executed there. This allows self-modification, and ensures the code
|
||||||
|
is executed the same way it is on my devcart, which doesn't have a
|
||||||
|
rewritable ROM as most do.
|
||||||
|
|
||||||
|
Some macros are used to simplify common tasks:
|
||||||
|
|
||||||
|
Macro Behavior
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
wreg addr,data Writes data to addr using LDH
|
||||||
|
lda addr Loads byte from addr into A using LDH
|
||||||
|
sta addr Stores A at addr using LDH
|
||||||
|
delay n Delays n cycles, where NOP = 1 cycle
|
||||||
|
delay_msec n Delays n milliseconds
|
||||||
|
set_test n,"Cause" Sets failure code and optional string
|
||||||
|
|
||||||
|
Routines and macros are documented where they are defined.
|
||||||
|
|
||||||
|
--
|
||||||
|
Shay Green <gblargg@gmail.com>
|
||||||
Loading…
Reference in New Issue
Block a user