copied over cryboy tests and made them run again

This commit is contained in:
Matthew Berry 2021-05-08 22:25:21 -07:00
parent f6fdd071d1
commit bdda6b0509
77 changed files with 1313 additions and 0 deletions

772
spec/gb/cpu_spec.cr Normal file
View file

@ -0,0 +1,772 @@
require "./spec_helper"
describe CPU do
describe "registers" do
it "do computations correctly across registers" do
cpu = new_cpu [] of UInt8
cpu.b = 0x00
cpu.c = 0x00
cpu.bc.should eq 0x0000
cpu.c += 0x01
cpu.b.should eq 0x00
cpu.c.should eq 0x01
cpu.bc.should eq 0x0001
cpu.bc += 0x4320
cpu.b.should eq 0x43
cpu.c.should eq 0x21
cpu.bc.should eq 0x4321
end
end
describe "unprefixed opcode" do
describe "0x00" do
it "does nothing" do
cpu = new_cpu [0x00]
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
end
end
describe "0x01" do
it "loads bc with d16" do
d16 = 0x1234
cpu = new_cpu [0x01, d16 & 0xFF, d16 >> 8]
cpu.tick
cpu.pc.should eq 3
cpu.sp.should eq 0xFFFE
cpu.bc.should eq d16
end
end
describe "0x02" do
it "loads (bc) with a" do
cpu = new_cpu [0x02]
cpu.a = 0x34
cpu.bc = 0xA000
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.memory[0xA000].should eq 0x34
end
end
describe "0x03" do
it "increments bc" do
cpu = new_cpu [0x03]
cpu.bc = 0x1234
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.bc.should eq 0x1235
end
end
describe "0x04" do
it "increments b" do
cpu = new_cpu [0x04]
cpu.b = 0x12
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.b.should eq 0x13
end
end
describe "0x05" do
it "decrements b" do
cpu = new_cpu [0x05]
cpu.b = 0x12
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.b.should eq 0x11
end
end
describe "0x06" do
it "loads b with d8" do
d8 = 0x12
cpu = new_cpu [0x06, d8]
cpu.tick
cpu.pc.should eq 2
cpu.sp.should eq 0xFFFE
cpu.b.should eq d8
end
end
describe "0x07" do
it "rotates accumulator left w/o carry" do
cpu = new_cpu [0x07]
cpu.a = 0b01011010
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.a.should eq 0b10110100
cpu.f_c.should eq false
end
it "rotates accumulator left w/ carry" do
cpu = new_cpu [0x07]
cpu.a = 0b10100101
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.a.should eq 0b01001011
cpu.f_c.should eq true
end
end
describe "0x08" do
it "loads (d16) with sp" do
d16 = 0xA000
cpu = new_cpu [0x08, d16 & 0xFF, d16 >> 8]
cpu.tick
cpu.pc.should eq 3
cpu.sp.should eq 0xFFFE
cpu.memory[0xA000] = 0xFFFE
end
end
describe "0x09" do
it "adds bc to hl" do
cpu = new_cpu [0x09]
cpu.hl = 0x1010
cpu.bc = 0x1111
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.hl.should eq 0x2121
cpu.bc.should eq 0x1111
end
end
describe "0x0A" do
it "loads a with (bc)" do
cpu = new_cpu [0x0A, 0x12]
cpu.bc = 0x0001_u8
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.bc.should eq 0x0001
cpu.memory[0x01].should eq 0x12
end
end
describe "0x0B" do
it "decrememnts bc" do
cpu = new_cpu [0x0B]
cpu.bc = 0x1234
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.bc.should eq 0x1233
end
end
describe "0x0C" do
it "increments c" do
cpu = new_cpu [0x0C]
cpu.c = 0x12
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.c.should eq 0x13
end
end
describe "0x0D" do
it "decrements c" do
cpu = new_cpu [0x0D]
cpu.c = 0x12
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.c.should eq 0x11
end
end
describe "0x0E" do
it "loads c with d8" do
cpu = new_cpu [0x0E, 0x12]
cpu.tick
cpu.pc.should eq 2
cpu.sp.should eq 0xFFFE
cpu.c.should eq 0x12
end
end
describe "0x0F" do
it "rotates accumulator right w/o carry" do
cpu = new_cpu [0x0F]
cpu.a = 0b01011010
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.a.should eq 0b00101101
cpu.f_c.should eq false
end
it "rotates accumulator right w/ carry" do
cpu = new_cpu [0x0F]
cpu.a = 0b10100101
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.a.should eq 0b11010010
cpu.f_c.should eq true
end
end
describe "0x10" do
it "stops execution" do
# todo: implement and test
end
end
describe "0x11" do
it "loads de with d16" do
d16 = 0x1234
cpu = new_cpu [0x11, d16 & 0xFF, d16 >> 8]
cpu.tick
cpu.pc.should eq 3
cpu.sp.should eq 0xFFFE
cpu.de.should eq d16
end
end
describe "0x12" do
it "loads (de) with a" do
cpu = new_cpu [0x12]
cpu.a = 0x34
cpu.de = 0xA000
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.memory[0xA000].should eq 0x34
end
end
describe "0x13" do
it "increments de" do
cpu = new_cpu [0x13]
cpu.de = 0x1234
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.de.should eq 0x1235
end
end
describe "0x14" do
it "increments d" do
cpu = new_cpu [0x14]
cpu.d = 0x12
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.d.should eq 0x13
end
end
describe "0x15" do
it "decrements d" do
cpu = new_cpu [0x15]
cpu.d = 0x12
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.d.should eq 0x11
end
end
describe "0x16" do
it "loads d with d8" do
d8 = 0x12
cpu = new_cpu [0x16, d8]
cpu.tick
cpu.pc.should eq 2
cpu.sp.should eq 0xFFFE
cpu.d.should eq d8
end
end
describe "0x17" do
it "rotates accumulator left through carry w/o carry" do
cpu = new_cpu [0x17]
cpu.a = 0b01011010
cpu.f_c = true
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.a.should eq 0b10110101
cpu.f_c.should eq false
end
it "rotates accumulator left through carry w/ carry" do
cpu = new_cpu [0x17]
cpu.a = 0b10100101
cpu.f_c = false
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.a.should eq 0b01001010
cpu.f_c.should eq true
end
end
# todo codes here
describe "0x21" do
it "loads hl with d16" do
d16 = 0x1234
cpu = new_cpu [0x21, d16 & 0xFF, d16 >> 8]
cpu.tick
cpu.pc.should eq 3
cpu.sp.should eq 0xFFFE
cpu.hl.should eq d16
end
end
describe "0x22" do
it "loads (hl+) with a" do
cpu = new_cpu [0x22]
cpu.a = 0x34
cpu.hl = 0xA000
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.memory[0xA000].should eq 0x34
cpu.hl.should eq 0xA001
end
end
describe "0x23" do
it "increments hl" do
cpu = new_cpu [0x23]
cpu.hl = 0x1234
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.hl.should eq 0x1235
end
end
describe "0x24" do
it "increments h" do
cpu = new_cpu [0x24]
cpu.h = 0x12
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.h.should eq 0x13
end
end
describe "0x25" do
it "decrements h" do
cpu = new_cpu [0x25]
cpu.h = 0x12
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.h.should eq 0x11
end
end
describe "0x26" do
it "loads h with d8" do
d8 = 0x12
cpu = new_cpu [0x26, d8]
cpu.tick
cpu.pc.should eq 2
cpu.sp.should eq 0xFFFE
cpu.h.should eq d8
end
end
# todo codes here
describe "0x31" do
it "loads sp with d16" do
d16 = 0x1234
cpu = new_cpu [0x31, d16 & 0xFF, d16 >> 8]
cpu.tick
cpu.pc.should eq 3
cpu.sp.should eq d16
end
end
describe "0x32" do
it "loads (hl-) with a" do
cpu = new_cpu [0x32]
cpu.a = 0x34
cpu.hl = 0xA000
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.memory[0xA000].should eq 0x34
cpu.hl.should eq 0x9FFF
end
end
describe "0x33" do
it "increments sp" do
cpu = new_cpu [0x33]
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFF
end
end
describe "0x34" do
it "increments (hl)" do
cpu = new_cpu [0x34]
cpu.memory[0xA000] = 0x12_u8
cpu.hl = 0xA000
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.memory[0xA000].should eq 0x13
end
end
describe "0x35" do
it "decrements (hl)" do
cpu = new_cpu [0x35]
cpu.memory[0xA000] = 0x12_u8
cpu.hl = 0xA000
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
cpu.memory[0xA000].should eq 0x11
end
end
describe "0x36" do
it "loads (hl) with d8" do
d8 = 0x12
cpu = new_cpu [0x36, d8]
cpu.hl = 0xA000
cpu.tick
cpu.pc.should eq 2
cpu.sp.should eq 0xFFFE
cpu.memory[0xA000].should eq d8
end
end
# todo codes here
describe "0xC0" do
it "returns if nz" do
cpu = new_cpu [0xC0]
cpu.sp = 0xFFF0_u16
cpu.memory[0xFFF0] = 0x1234_u16
cpu.f_z = false
cpu.tick
cpu.pc.should eq 0x1234
cpu.sp.should eq 0xFFF2
end
it "doesn't return if not nz" do
cpu = new_cpu [0xC0]
cpu.f_z = true
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
end
end
describe "0xC1" do
it "pops bc" do
cpu = new_cpu [0xC1]
cpu.sp = 0xFFF0_u16
cpu.memory[0xFFF0_u16] = 0x1234
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFF2
cpu.bc.should eq 0x1234
end
end
describe "0xC2" do
it "jumps to a16 if nz" do
a16 = 0xA000
cpu = new_cpu [0xC2, a16 & 0xFF, a16 >> 8]
cpu.f_z = false
cpu.tick
cpu.pc.should eq a16
cpu.sp.should eq 0xFFFE
end
it "doesn't jump to a16 if not nz" do
a16 = 0xA000
cpu = new_cpu [0xC2, a16 & 0xFF, a16 >> 8]
cpu.f_z = true
cpu.tick
cpu.pc.should eq 3
cpu.sp.should eq 0xFFFE
end
end
describe "0xC3" do
it "jumps to a16" do
a16 = 0xA000
cpu = new_cpu [0xC3, a16 & 0xFF, a16 >> 8]
cpu.tick
cpu.pc.should eq 0xA000
cpu.sp.should eq 0xFFFE
end
it "jumps to a16 regardless of nz" do
a16 = 0xAC00
cpu = new_cpu [0xC3, a16 & 0xFF, a16 >> 8]
cpu.f_z = false
cpu.tick
cpu.pc.should eq a16
cpu = new_cpu [0xC3, a16 & 0xFF, a16 >> 8]
cpu.f_z = true
cpu.tick
cpu.pc.should eq a16
end
end
describe "0xC4" do
it "calls a16 if nz" do
a16 = 0xAC00
cpu = new_cpu [0xC4, a16 & 0xFF, a16 >> 8]
cpu.f_z = false
cpu.tick
cpu.pc.should eq 0xAC00
cpu.sp.should eq 0xFFFC
cpu.memory[0xFFFD].should eq 0x00
cpu.memory[0xFFFC].should eq 0x03
end
it "doesn't call a16 if not nz" do
a16 = 0xAC00
cpu = new_cpu [0xC4, a16 & 0xFF, a16 >> 8]
cpu.f_z = true
cpu.tick
cpu.pc.should eq 3
cpu.sp.should eq 0xFFFE
end
end
describe "0xC5" do
it "pushes bc" do
cpu = new_cpu [0xC5]
cpu.bc = 0x1234_u16
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFC
cpu.memory[0xFFFD].should eq 0x12
cpu.memory[0xFFFC].should eq 0x34
end
end
describe "0xC6" do
it "adds d8 to a" do
d8 = 0x01
cpu = new_cpu [0xC6, d8]
cpu.a = 0xFF
cpu.tick
cpu.pc.should eq 2
cpu.sp.should eq 0xFFFE
cpu.a.should eq 0x00
cpu.f_z.should eq true
cpu.f_n.should eq false
cpu.f_h.should eq true
cpu.f_c.should eq true
end
end
# todo codes here
describe "0xD0" do
it "returns if nc" do
cpu = new_cpu [0xD0]
cpu.sp = 0xFFF0_u16
cpu.memory[0xFFF0] = 0x1234_u16
cpu.f_c = false
cpu.tick
cpu.pc.should eq 0x1234
cpu.sp.should eq 0xFFF2
end
it "doesn't return if not nc" do
cpu = new_cpu [0xD0]
cpu.f_c = true
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFE
end
end
describe "0xD1" do
it "pops de" do
cpu = new_cpu [0xD1]
cpu.sp = 0xFFF0_u16
cpu.memory[0xFFF0_u16] = 0x1234
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFF2
cpu.de.should eq 0x1234
end
end
describe "0xD2" do
it "jumps to a16 if nc" do
a16 = 0xA000
cpu = new_cpu [0xD2, a16 & 0xFF, a16 >> 8]
cpu.f_c = false
cpu.tick
cpu.pc.should eq a16
cpu.sp.should eq 0xFFFE
end
it "doesn't jump to a16 if not nc" do
a16 = 0xA000
cpu = new_cpu [0xD2, a16 & 0xFF, a16 >> 8]
cpu.f_c = true
cpu.tick
cpu.pc.should eq 3
cpu.sp.should eq 0xFFFE
end
end
describe "0xD3" do
# unused opcode
end
describe "0xD4" do
it "calls a16 if nc" do
a16 = 0xAC00
cpu = new_cpu [0xD4, a16 & 0xFF, a16 >> 8]
cpu.f_c = false
cpu.tick
cpu.pc.should eq 0xAC00
cpu.sp.should eq 0xFFFC
cpu.memory[0xFFFD].should eq 0x00
cpu.memory[0xFFFC].should eq 0x03
end
it "doesn't call a16 if not nc" do
a16 = 0xAC00
cpu = new_cpu [0xD4, a16 & 0xFF, a16 >> 8]
cpu.f_c = true
cpu.tick
cpu.pc.should eq 3
cpu.sp.should eq 0xFFFE
end
end
describe "0xD5" do
it "pushes de" do
cpu = new_cpu [0xD5]
cpu.de = 0x1234_u16
cpu.tick
cpu.pc.should eq 1
cpu.sp.should eq 0xFFFC
cpu.memory[0xFFFD].should eq 0x12
cpu.memory[0xFFFC].should eq 0x34
end
end
describe "0xD6" do
it "subs d8 from a" do
d8 = 0x01
cpu = new_cpu [0xD6, d8]
cpu.a = 0x10
cpu.tick
cpu.pc.should eq 2
cpu.sp.should eq 0xFFFE
cpu.a.should eq 0x0F
cpu.f_z.should eq false
cpu.f_n.should eq true
cpu.f_h.should eq true
cpu.f_c.should eq false
end
end
# todo codes here
end
describe "prefixed opcode" do
# todo codes here
describe "0x40" do
it "tests bit 0 of b" do
cpu = new_cpu [0xCB, 0x40]
cpu.b = 0b01010101
cpu.tick
cpu.pc.should eq 2
cpu.sp.should eq 0xFFFE
cpu.b.should eq 0b01010101
cpu.f_z.should eq false
cpu.f_c.should eq false
cpu.f_h.should eq true
end
end
# todo codes here
end
end

4
spec/gb/cryboy_spec.cr Normal file
View file

@ -0,0 +1,4 @@
require "./spec_helper"
describe Crab do
end

54
spec/gb/joypad_spec.cr Normal file
View file

@ -0,0 +1,54 @@
describe Joypad do
it "defaults to buttons not pressed" do
joypad = Joypad.new
joypad.read.should eq 0b00111111
end
it "toggles button select" do
joypad = Joypad.new
joypad.write 0b00011111
joypad.read.should eq 0b00011111
joypad.write 0b00111111
joypad.read.should eq 0b00111111
end
it "toggles direction select" do
joypad = Joypad.new
joypad.write 0b00101111
joypad.read.should eq 0b00101111
joypad.write 0b00111111
joypad.read.should eq 0b00111111
end
it "only allows writing to selection keys" do
joypad = Joypad.new
joypad.write 0b00000000
joypad.read.should eq 0b00001111
joypad.write 0b11111111
joypad.read.should eq 0b00111111
end
it "sets correct bits for one key down" do
joypad = Joypad.new
joypad.down = true
joypad.write 0b00100000
joypad.read.should eq 0b00100111
end
it "sets correct bits for two different keys down" do
joypad = Joypad.new
joypad.down = true
joypad.b = true
joypad.write 0b00000000
joypad.read.should eq 0b00000101
end
it "sets correct bits for two parallel keys down" do
joypad = Joypad.new
joypad.up = true
joypad.select = true
joypad.button_keys = true
joypad.direction_keys = true
joypad.read.should eq 0b00001011
end
end

31
spec/gb/memory_spec.cr Normal file
View file

@ -0,0 +1,31 @@
require "./spec_helper"
describe GB::Memory do
it "can't write over rom" do
bytes = Array.new 0x8000, 0
bytes[0] = 0x01
bytes[1] = 0x02
bytes[2] = 0x03
memory = new_memory bytes
memory[0x0000] = 0x05_u8
memory[0x0001] = 0x06_u8
memory[0x3FFF] = 0x07_u8
memory[0x4000] = 0x07_u8
memory[0x7FFF] = 0x08_u8
memory[0x0000].should eq 0x01
memory[0x0001].should eq 0x02
memory[0x0002].should eq 0x03
memory[0x3FFF].should eq 0x00
memory[0x4000].should eq 0x00
memory[0x7FFF].should eq 0x00
end
it "writes to external ram simple" do
memory = new_memory [0x00]
memory[0xA000] = 0x12.to_u8
memory[0xBFFF] = 0x34.to_u8
memory[0xA000].should eq 0x12
memory[0xBFFF].should eq 0x34
end
end

109
spec/gb/run_test_roms.cr Normal file
View file

@ -0,0 +1,109 @@
require "option_parser"
TEST_RESULTS_DIR = "spec/gb/test_results"
SCREENSHOT_DIR = "#{TEST_RESULTS_DIR}/screenshots"
README_FILE = "#{TEST_RESULTS_DIR}/README.md"
# kill process after given number of seconds
def kill(process : Process, after : Number = 5) : Nil
spawn do
sleep after
process.signal Signal::KILL if process.exists?
end
end
def get_test_name(dir : String, test : String) : String
test.rpartition('.')[0][dir.size + 1, test.size]
end
alias TestResult = NamedTuple(test: String, pass: Bool)
alias TestSuite = NamedTuple(suite: String, results: Array(TestResult))
test_results : Array(TestSuite) = [] of TestSuite
acid_dir = ""
blargg_dir = ""
mealybug_dir = ""
mooneye_dir = ""
OptionParser.parse do |parser|
parser.on("--acid PATH", "Path to directory with acid tests") { |path| acid_dir = path }
parser.on("--blargg PATH", "Path to directory with blargg tests") { |path| blargg = path }
parser.on("--mealybug PATH", "Path to directory with mealybug tests") { |path| mealybug_dir = path }
parser.on("--mooneye PATH", "Path to directory with mooneye tests") { |path| mooneye_dir = path }
parser.invalid_option { abort parser }
end
system "shards build -Dgraphics_test > /dev/null"
unless acid_dir == ""
[true, false].each do |fifo|
test_results << {suite: "Acid#{" Fifo" if fifo}", results: [] of TestResult}
puts "Acid #{"Fifo " if fifo}Tests"
Dir.glob("#{acid_dir}/*acid2.gb*").sort.each do |path|
test_name = get_test_name acid_dir, path
Process.run "bin/crab", [path, "--headless"] + (fifo ? ["--fifo"] : [] of String) do |process|
kill process, after: 1
end
system %[touch out.png] # touch image in case something went wrong
system %[mv out.png #{SCREENSHOT_DIR}/#{test_name}#{"_fifo" if fifo}.png]
system %[compare -metric AE #{SCREENSHOT_DIR}/#{test_name}#{"_fifo" if fifo}.png #{SCREENSHOT_DIR}/expected/#{test_name}.png /tmp/crab_diff 2>/dev/null]
passed = $?.exit_status == 0
test_results[test_results.size - 1][:results] << {test: test_name, pass: passed}
print passed ? "." : "F"
end
print "\n"
end
end
unless mealybug_dir == ""
test_results << {suite: "Mealybug Fifo", results: [] of TestResult}
puts "Mealybug Fifo Tests"
Dir.glob("#{mealybug_dir}/**/*.gb").sort.each do |path|
test_name = get_test_name mealybug_dir, path
Process.run "bin/crab", [path, "--headless", "--fifo"] do |process|
kill process, after: 1
end
system %[touch out.png] # touch image in case something went wrong
system %[mv out.png #{SCREENSHOT_DIR}/#{test_name}.png]
system %[compare -metric AE #{SCREENSHOT_DIR}/#{test_name}.png #{SCREENSHOT_DIR}/expected/#{test_name}.png /tmp/crab_diff 2>/dev/null]
passed = $?.exit_status == 0
test_results[test_results.size - 1][:results] << {test: test_name, pass: passed}
print passed ? "." : "F"
end
print "\n"
end
system "shards build --release -Dprint_serial > /dev/null"
unless mooneye_dir == ""
test_results << {suite: "Mooneye", results: [] of TestResult}
puts "Mooneye Tests"
fib_string = "358132134"
Dir.glob("#{mooneye_dir}/**/*.gb").sort.each do |path|
next if path.includes?("util") || path.includes?("manual-only") || path.includes?("dmg") || path.includes?("mgb") || path.includes?("sgb")
test_name = get_test_name mooneye_dir, path
passed = false
Process.run("bin/crab", [path, "--headless"]) do |process|
kill process, after: 10 # seconds
result = process.output.gets 9
process.terminate if process.exists?
passed = result == fib_string
end
test_results[test_results.size - 1][:results] << {test: test_name, pass: passed}
print passed ? "." : "F"
end
print "\n"
end
File.open README_FILE, "w" do |file|
file.puts "# Test Results"
test_results.each do |test_suite|
file.puts "## #{test_suite[:suite]} Tests"
file.puts "| Result | Test Name |"
file.puts "|--------|-----------|"
test_suite[:results].each do |test_result|
file.puts "| #{test_result[:pass] ? "👌" : "👀"} | #{test_result[:test]} |"
end
end
end

28
spec/gb/spec_helper.cr Normal file
View file

@ -0,0 +1,28 @@
# define a new CPU with the given bytes as rom
def new_cpu(bytes : Array(Int), cgb_enabled = true, boot = false)
interrupts = Interrupts.new
display = Display.new
ppu = PPU.new display, interrupts, pointerof(cgb_enabled)
apu = APU.new
timer = Timer.new interrupts
cpu = CPU.new new_memory(bytes), interrupts, ppu, apu, timer, boot
cpu.sp = 0xFFFE_u16
cpu
end
# define a new Memory with the given bytes as rom
def new_memory(bytes : Array(Int), cgb_enabled = true, bootrom = nil)
rom = Bytes.new 0x8000
bytes.each_with_index do |byte, i|
rom[i] = byte.to_u8!
end
cartridge = GB::Cartridge.new rom
interrupts = GB::Interrupts.new
display = GB::Display.new
ppu = GB::PPU.new display, interrupts, pointerof(cgb_enabled)
apu = GB::APU.new
timer = GB::Timer.new interrupts
joypad = GB::Joypad.new
GB::Memory.new cartridge, interrupts, ppu, apu, timer, joypad, pointerof(cgb_enabled), bootrom
end

View file

@ -0,0 +1,149 @@
# Test Results
## Acid Fifo Tests
| Result | Test Name |
|--------|-----------|
| 👌 | cgb-acid2 |
| 👌 | dmg-acid2 |
## Acid Tests
| Result | Test Name |
|--------|-----------|
| 👌 | cgb-acid2 |
| 👌 | dmg-acid2 |
## Mealybug Fifo Tests
| Result | Test Name |
|--------|-----------|
| 👀 | m2_win_en_toggle |
| 👀 | m3_bgp_change |
| 👀 | m3_bgp_change_sprites |
| 👀 | m3_lcdc_bg_en_change |
| 👀 | m3_lcdc_bg_en_change2 |
| 👀 | m3_lcdc_bg_map_change |
| 👀 | m3_lcdc_bg_map_change2 |
| 👀 | m3_lcdc_obj_en_change |
| 👀 | m3_lcdc_obj_en_change_variant |
| 👀 | m3_lcdc_obj_size_change |
| 👀 | m3_lcdc_obj_size_change_scx |
| 👀 | m3_lcdc_tile_sel_change |
| 👀 | m3_lcdc_tile_sel_change2 |
| 👀 | m3_lcdc_tile_sel_win_change |
| 👀 | m3_lcdc_tile_sel_win_change2 |
| 👀 | m3_lcdc_win_en_change_multiple |
| 👀 | m3_lcdc_win_en_change_multiple_wx |
| 👀 | m3_lcdc_win_map_change |
| 👀 | m3_lcdc_win_map_change2 |
| 👀 | m3_obp0_change |
| 👀 | m3_scx_high_5_bits |
| 👀 | m3_scx_high_5_bits_change2 |
| 👌 | m3_scx_low_3_bits |
| 👀 | m3_scy_change |
| 👀 | m3_scy_change2 |
| 👀 | m3_window_timing |
| 👀 | m3_window_timing_wx_0 |
| 👀 | m3_wx_4_change |
| 👀 | m3_wx_4_change_sprites |
| 👀 | m3_wx_5_change |
| 👀 | m3_wx_6_change |
## Mooneye Tests
| Result | Test Name |
|--------|-----------|
| 👌 | acceptance/add_sp_e_timing |
| 👌 | acceptance/bits/mem_oam |
| 👌 | acceptance/bits/reg_f |
| 👀 | acceptance/bits/unused_hwio-GS |
| 👀 | acceptance/boot_div-S |
| 👀 | acceptance/boot_div2-S |
| 👀 | acceptance/boot_hwio-S |
| 👌 | acceptance/call_cc_timing |
| 👌 | acceptance/call_cc_timing2 |
| 👌 | acceptance/call_timing |
| 👌 | acceptance/call_timing2 |
| 👌 | acceptance/di_timing-GS |
| 👌 | acceptance/div_timing |
| 👌 | acceptance/ei_sequence |
| 👌 | acceptance/ei_timing |
| 👌 | acceptance/halt_ime0_ei |
| 👌 | acceptance/halt_ime0_nointr_timing |
| 👌 | acceptance/halt_ime1_timing |
| 👌 | acceptance/halt_ime1_timing2-GS |
| 👌 | acceptance/if_ie_registers |
| 👌 | acceptance/instr/daa |
| 👌 | acceptance/interrupts/ie_push |
| 👌 | acceptance/intr_timing |
| 👌 | acceptance/jp_cc_timing |
| 👌 | acceptance/jp_timing |
| 👌 | acceptance/ld_hl_sp_e_timing |
| 👌 | acceptance/oam_dma/basic |
| 👌 | acceptance/oam_dma/reg_read |
| 👀 | acceptance/oam_dma/sources-GS |
| 👌 | acceptance/oam_dma_restart |
| 👌 | acceptance/oam_dma_start |
| 👌 | acceptance/oam_dma_timing |
| 👌 | acceptance/pop_timing |
| 👀 | acceptance/ppu/hblank_ly_scx_timing-GS |
| 👌 | acceptance/ppu/intr_1_2_timing-GS |
| 👌 | acceptance/ppu/intr_2_0_timing |
| 👀 | acceptance/ppu/intr_2_mode0_timing |
| 👀 | acceptance/ppu/intr_2_mode0_timing_sprites |
| 👀 | acceptance/ppu/intr_2_mode3_timing |
| 👀 | acceptance/ppu/intr_2_oam_ok_timing |
| 👀 | acceptance/ppu/lcdon_timing-GS |
| 👀 | acceptance/ppu/lcdon_write_timing-GS |
| 👌 | acceptance/ppu/stat_irq_blocking |
| 👀 | acceptance/ppu/stat_lyc_onoff |
| 👀 | acceptance/ppu/vblank_stat_intr-GS |
| 👌 | acceptance/push_timing |
| 👌 | acceptance/rapid_di_ei |
| 👌 | acceptance/ret_cc_timing |
| 👌 | acceptance/ret_timing |
| 👌 | acceptance/reti_intr_timing |
| 👌 | acceptance/reti_timing |
| 👌 | acceptance/rst_timing |
| 👌 | acceptance/timer/div_write |
| 👌 | acceptance/timer/rapid_toggle |
| 👌 | acceptance/timer/tim00 |
| 👌 | acceptance/timer/tim00_div_trigger |
| 👌 | acceptance/timer/tim01 |
| 👌 | acceptance/timer/tim01_div_trigger |
| 👌 | acceptance/timer/tim10 |
| 👌 | acceptance/timer/tim10_div_trigger |
| 👌 | acceptance/timer/tim11 |
| 👌 | acceptance/timer/tim11_div_trigger |
| 👌 | acceptance/timer/tima_reload |
| 👌 | acceptance/timer/tima_write_reloading |
| 👌 | acceptance/timer/tma_write_reloading |
| 👌 | emulator-only/mbc1/bits_bank1 |
| 👌 | emulator-only/mbc1/bits_bank2 |
| 👌 | emulator-only/mbc1/bits_mode |
| 👌 | emulator-only/mbc1/bits_ramg |
| 👀 | emulator-only/mbc1/multicart_rom_8Mb |
| 👌 | emulator-only/mbc1/ram_256kb |
| 👌 | emulator-only/mbc1/ram_64kb |
| 👌 | emulator-only/mbc1/rom_16Mb |
| 👌 | emulator-only/mbc1/rom_1Mb |
| 👌 | emulator-only/mbc1/rom_2Mb |
| 👌 | emulator-only/mbc1/rom_4Mb |
| 👌 | emulator-only/mbc1/rom_512kb |
| 👌 | emulator-only/mbc1/rom_8Mb |
| 👌 | emulator-only/mbc2/bits_ramg |
| 👌 | emulator-only/mbc2/bits_romb |
| 👌 | emulator-only/mbc2/bits_unused |
| 👌 | emulator-only/mbc2/ram |
| 👌 | emulator-only/mbc2/rom_1Mb |
| 👌 | emulator-only/mbc2/rom_2Mb |
| 👌 | emulator-only/mbc2/rom_512kb |
| 👌 | emulator-only/mbc5/rom_16Mb |
| 👌 | emulator-only/mbc5/rom_1Mb |
| 👌 | emulator-only/mbc5/rom_2Mb |
| 👌 | emulator-only/mbc5/rom_32Mb |
| 👌 | emulator-only/mbc5/rom_4Mb |
| 👌 | emulator-only/mbc5/rom_512kb |
| 👌 | emulator-only/mbc5/rom_64Mb |
| 👌 | emulator-only/mbc5/rom_8Mb |
| 👌 | misc/bits/unused_hwio-C |
| 👀 | misc/boot_div-A |
| 👀 | misc/boot_div-cgb0 |
| 👌 | misc/boot_div-cgbABCDE |
| 👀 | misc/boot_hwio-C |
| 👀 | misc/boot_regs-A |
| 👌 | misc/boot_regs-cgb |
| 👀 | misc/ppu/vblank_stat_intr-C |

View file

@ -0,0 +1,149 @@
# Test Results
## Acid Fifo Tests
| Result | Test Name |
|--------|-----------|
| 👌 | cgb-acid2 |
| 👌 | dmg-acid2 |
## Acid Tests
| Result | Test Name |
|--------|-----------|
| 👌 | cgb-acid2 |
| 👌 | dmg-acid2 |
## Mealybug Fifo Tests
| Result | Test Name |
|--------|-----------|
| 👀 | m2_win_en_toggle |
| 👀 | m3_bgp_change |
| 👀 | m3_bgp_change_sprites |
| 👀 | m3_lcdc_bg_en_change |
| 👀 | m3_lcdc_bg_en_change2 |
| 👀 | m3_lcdc_bg_map_change |
| 👀 | m3_lcdc_bg_map_change2 |
| 👀 | m3_lcdc_obj_en_change |
| 👀 | m3_lcdc_obj_en_change_variant |
| 👀 | m3_lcdc_obj_size_change |
| 👀 | m3_lcdc_obj_size_change_scx |
| 👀 | m3_lcdc_tile_sel_change |
| 👀 | m3_lcdc_tile_sel_change2 |
| 👀 | m3_lcdc_tile_sel_win_change |
| 👀 | m3_lcdc_tile_sel_win_change2 |
| 👀 | m3_lcdc_win_en_change_multiple |
| 👀 | m3_lcdc_win_en_change_multiple_wx |
| 👀 | m3_lcdc_win_map_change |
| 👀 | m3_lcdc_win_map_change2 |
| 👀 | m3_obp0_change |
| 👀 | m3_scx_high_5_bits |
| 👀 | m3_scx_high_5_bits_change2 |
| 👌 | m3_scx_low_3_bits |
| 👀 | m3_scy_change |
| 👀 | m3_scy_change2 |
| 👀 | m3_window_timing |
| 👀 | m3_window_timing_wx_0 |
| 👀 | m3_wx_4_change |
| 👀 | m3_wx_4_change_sprites |
| 👀 | m3_wx_5_change |
| 👀 | m3_wx_6_change |
## Mooneye Tests
| Result | Test Name |
|--------|-----------|
| 👌 | acceptance/add_sp_e_timing |
| 👌 | acceptance/bits/mem_oam |
| 👌 | acceptance/bits/reg_f |
| 👀 | acceptance/bits/unused_hwio-GS |
| 👀 | acceptance/boot_div-S |
| 👀 | acceptance/boot_div2-S |
| 👀 | acceptance/boot_hwio-S |
| 👌 | acceptance/call_cc_timing |
| 👌 | acceptance/call_cc_timing2 |
| 👌 | acceptance/call_timing |
| 👌 | acceptance/call_timing2 |
| 👌 | acceptance/di_timing-GS |
| 👌 | acceptance/div_timing |
| 👌 | acceptance/ei_sequence |
| 👌 | acceptance/ei_timing |
| 👌 | acceptance/halt_ime0_ei |
| 👌 | acceptance/halt_ime0_nointr_timing |
| 👌 | acceptance/halt_ime1_timing |
| 👌 | acceptance/halt_ime1_timing2-GS |
| 👌 | acceptance/if_ie_registers |
| 👌 | acceptance/instr/daa |
| 👌 | acceptance/interrupts/ie_push |
| 👌 | acceptance/intr_timing |
| 👌 | acceptance/jp_cc_timing |
| 👌 | acceptance/jp_timing |
| 👌 | acceptance/ld_hl_sp_e_timing |
| 👌 | acceptance/oam_dma/basic |
| 👌 | acceptance/oam_dma/reg_read |
| 👀 | acceptance/oam_dma/sources-GS |
| 👌 | acceptance/oam_dma_restart |
| 👌 | acceptance/oam_dma_start |
| 👌 | acceptance/oam_dma_timing |
| 👌 | acceptance/pop_timing |
| 👀 | acceptance/ppu/hblank_ly_scx_timing-GS |
| 👌 | acceptance/ppu/intr_1_2_timing-GS |
| 👌 | acceptance/ppu/intr_2_0_timing |
| 👀 | acceptance/ppu/intr_2_mode0_timing |
| 👀 | acceptance/ppu/intr_2_mode0_timing_sprites |
| 👀 | acceptance/ppu/intr_2_mode3_timing |
| 👀 | acceptance/ppu/intr_2_oam_ok_timing |
| 👀 | acceptance/ppu/lcdon_timing-GS |
| 👀 | acceptance/ppu/lcdon_write_timing-GS |
| 👌 | acceptance/ppu/stat_irq_blocking |
| 👀 | acceptance/ppu/stat_lyc_onoff |
| 👀 | acceptance/ppu/vblank_stat_intr-GS |
| 👌 | acceptance/push_timing |
| 👌 | acceptance/rapid_di_ei |
| 👌 | acceptance/ret_cc_timing |
| 👌 | acceptance/ret_timing |
| 👌 | acceptance/reti_intr_timing |
| 👌 | acceptance/reti_timing |
| 👌 | acceptance/rst_timing |
| 👌 | acceptance/timer/div_write |
| 👌 | acceptance/timer/rapid_toggle |
| 👌 | acceptance/timer/tim00 |
| 👌 | acceptance/timer/tim00_div_trigger |
| 👌 | acceptance/timer/tim01 |
| 👌 | acceptance/timer/tim01_div_trigger |
| 👌 | acceptance/timer/tim10 |
| 👌 | acceptance/timer/tim10_div_trigger |
| 👌 | acceptance/timer/tim11 |
| 👌 | acceptance/timer/tim11_div_trigger |
| 👌 | acceptance/timer/tima_reload |
| 👌 | acceptance/timer/tima_write_reloading |
| 👌 | acceptance/timer/tma_write_reloading |
| 👌 | emulator-only/mbc1/bits_bank1 |
| 👌 | emulator-only/mbc1/bits_bank2 |
| 👌 | emulator-only/mbc1/bits_mode |
| 👌 | emulator-only/mbc1/bits_ramg |
| 👀 | emulator-only/mbc1/multicart_rom_8Mb |
| 👌 | emulator-only/mbc1/ram_256kb |
| 👌 | emulator-only/mbc1/ram_64kb |
| 👌 | emulator-only/mbc1/rom_16Mb |
| 👌 | emulator-only/mbc1/rom_1Mb |
| 👌 | emulator-only/mbc1/rom_2Mb |
| 👌 | emulator-only/mbc1/rom_4Mb |
| 👌 | emulator-only/mbc1/rom_512kb |
| 👌 | emulator-only/mbc1/rom_8Mb |
| 👌 | emulator-only/mbc2/bits_ramg |
| 👌 | emulator-only/mbc2/bits_romb |
| 👌 | emulator-only/mbc2/bits_unused |
| 👌 | emulator-only/mbc2/ram |
| 👌 | emulator-only/mbc2/rom_1Mb |
| 👌 | emulator-only/mbc2/rom_2Mb |
| 👌 | emulator-only/mbc2/rom_512kb |
| 👌 | emulator-only/mbc5/rom_16Mb |
| 👌 | emulator-only/mbc5/rom_1Mb |
| 👌 | emulator-only/mbc5/rom_2Mb |
| 👌 | emulator-only/mbc5/rom_32Mb |
| 👌 | emulator-only/mbc5/rom_4Mb |
| 👌 | emulator-only/mbc5/rom_512kb |
| 👌 | emulator-only/mbc5/rom_64Mb |
| 👌 | emulator-only/mbc5/rom_8Mb |
| 👌 | misc/bits/unused_hwio-C |
| 👀 | misc/boot_div-A |
| 👀 | misc/boot_div-cgb0 |
| 👌 | misc/boot_div-cgbABCDE |
| 👀 | misc/boot_hwio-C |
| 👀 | misc/boot_regs-A |
| 👌 | misc/boot_regs-cgb |
| 👀 | misc/ppu/vblank_stat_intr-C |

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 870 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 718 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 794 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 791 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 778 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 654 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 921 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 860 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,014 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 647 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 760 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,010 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 812 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 812 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,018 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,018 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,010 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 841 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 670 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

17
spec/gb/util_spec.cr Normal file
View file

@ -0,0 +1,17 @@
require "./spec_helper"
describe "util" do
describe "array_to_uint8" do
it "converts array to uint8" do
res = array_to_uint8 [false, true, 0, 1, 0_u8, 1_u8, -0, -1]
res.should eq 0b01010101_u8
end
end
describe "array_to_uint16" do
it "converts array to uint16" do
res = array_to_uint16 [false, true, 0, 1, 0_u8, 1_u8, -0, -1, false, true, 0, 1, 0_u8, 1_u8, -0, -1]
res.should eq 0b0101010101010101_u16
end
end
end