copied over cryboy tests and made them run again
772
spec/gb/cpu_spec.cr
Normal 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
|
@ -0,0 +1,4 @@
|
|||
require "./spec_helper"
|
||||
|
||||
describe Crab do
|
||||
end
|
54
spec/gb/joypad_spec.cr
Normal 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
|
@ -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
|
@ -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
|
@ -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
|
149
spec/gb/test_results/README.md
Normal 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 |
|
149
spec/gb/test_results/readme.md
Normal 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 |
|
BIN
spec/gb/test_results/screenshots/cgb-acid2.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
spec/gb/test_results/screenshots/cgb-acid2_fifo.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
spec/gb/test_results/screenshots/dmg-acid2.png
Normal file
After Width: | Height: | Size: 2 KiB |
BIN
spec/gb/test_results/screenshots/dmg-acid2_fifo.png
Normal file
After Width: | Height: | Size: 2 KiB |
BIN
spec/gb/test_results/screenshots/expected/cgb-acid2.png
Normal file
After Width: | Height: | Size: 870 B |
BIN
spec/gb/test_results/screenshots/expected/dmg-acid2.png
Normal file
After Width: | Height: | Size: 787 B |
BIN
spec/gb/test_results/screenshots/expected/m2_win_en_toggle.png
Normal file
After Width: | Height: | Size: 718 B |
BIN
spec/gb/test_results/screenshots/expected/m3_bgp_change.png
Normal file
After Width: | Height: | Size: 404 B |
After Width: | Height: | Size: 794 B |
After Width: | Height: | Size: 791 B |
After Width: | Height: | Size: 778 B |
After Width: | Height: | Size: 472 B |
After Width: | Height: | Size: 654 B |
After Width: | Height: | Size: 357 B |
After Width: | Height: | Size: 452 B |
After Width: | Height: | Size: 737 B |
After Width: | Height: | Size: 421 B |
After Width: | Height: | Size: 506 B |
After Width: | Height: | Size: 921 B |
After Width: | Height: | Size: 483 B |
After Width: | Height: | Size: 860 B |
After Width: | Height: | Size: 362 B |
After Width: | Height: | Size: 636 B |
After Width: | Height: | Size: 456 B |
After Width: | Height: | Size: 561 B |
BIN
spec/gb/test_results/screenshots/expected/m3_obp0_change.png
Normal file
After Width: | Height: | Size: 599 B |
BIN
spec/gb/test_results/screenshots/expected/m3_scx_high_5_bits.png
Normal file
After Width: | Height: | Size: 1,014 B |
After Width: | Height: | Size: 647 B |
BIN
spec/gb/test_results/screenshots/expected/m3_scx_low_3_bits.png
Normal file
After Width: | Height: | Size: 328 B |
BIN
spec/gb/test_results/screenshots/expected/m3_scy_change.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
spec/gb/test_results/screenshots/expected/m3_scy_change2.png
Normal file
After Width: | Height: | Size: 760 B |
BIN
spec/gb/test_results/screenshots/expected/m3_window_timing.png
Normal file
After Width: | Height: | Size: 300 B |
After Width: | Height: | Size: 307 B |
BIN
spec/gb/test_results/screenshots/expected/m3_wx_4_change.png
Normal file
After Width: | Height: | Size: 499 B |
After Width: | Height: | Size: 296 B |
BIN
spec/gb/test_results/screenshots/expected/m3_wx_5_change.png
Normal file
After Width: | Height: | Size: 342 B |
BIN
spec/gb/test_results/screenshots/expected/m3_wx_6_change.png
Normal file
After Width: | Height: | Size: 577 B |
BIN
spec/gb/test_results/screenshots/m2_win_en_toggle.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
spec/gb/test_results/screenshots/m3_bgp_change.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
spec/gb/test_results/screenshots/m3_bgp_change_sprites.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
spec/gb/test_results/screenshots/m3_lcdc_bg_en_change.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
spec/gb/test_results/screenshots/m3_lcdc_bg_en_change2.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
spec/gb/test_results/screenshots/m3_lcdc_bg_map_change.png
Normal file
After Width: | Height: | Size: 1,010 B |
BIN
spec/gb/test_results/screenshots/m3_lcdc_bg_map_change2.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
spec/gb/test_results/screenshots/m3_lcdc_obj_en_change.png
Normal file
After Width: | Height: | Size: 812 B |
After Width: | Height: | Size: 812 B |
BIN
spec/gb/test_results/screenshots/m3_lcdc_obj_size_change.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
spec/gb/test_results/screenshots/m3_lcdc_obj_size_change_scx.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
spec/gb/test_results/screenshots/m3_lcdc_tile_sel_change.png
Normal file
After Width: | Height: | Size: 1,018 B |
BIN
spec/gb/test_results/screenshots/m3_lcdc_tile_sel_change2.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
spec/gb/test_results/screenshots/m3_lcdc_tile_sel_win_change.png
Normal file
After Width: | Height: | Size: 1,018 B |
After Width: | Height: | Size: 2 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 1 KiB |
BIN
spec/gb/test_results/screenshots/m3_lcdc_win_map_change.png
Normal file
After Width: | Height: | Size: 1,010 B |
BIN
spec/gb/test_results/screenshots/m3_lcdc_win_map_change2.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
spec/gb/test_results/screenshots/m3_obp0_change.png
Normal file
After Width: | Height: | Size: 841 B |
BIN
spec/gb/test_results/screenshots/m3_scx_high_5_bits.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
spec/gb/test_results/screenshots/m3_scx_high_5_bits_change2.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
spec/gb/test_results/screenshots/m3_scx_low_3_bits.png
Normal file
After Width: | Height: | Size: 670 B |
BIN
spec/gb/test_results/screenshots/m3_scy_change.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
spec/gb/test_results/screenshots/m3_scy_change2.png
Normal file
After Width: | Height: | Size: 3 KiB |
BIN
spec/gb/test_results/screenshots/m3_window_timing.png
Normal file
After Width: | Height: | Size: 930 B |
BIN
spec/gb/test_results/screenshots/m3_window_timing_wx_0.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
spec/gb/test_results/screenshots/m3_wx_4_change.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
spec/gb/test_results/screenshots/m3_wx_4_change_sprites.png
Normal file
After Width: | Height: | Size: 574 B |
BIN
spec/gb/test_results/screenshots/m3_wx_5_change.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
spec/gb/test_results/screenshots/m3_wx_6_change.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
17
spec/gb/util_spec.cr
Normal 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
|