[pypy-svn] r57624 - in pypy/dist/pypy/lang/gameboy: . test
cami at codespeak.net
cami at codespeak.net
Tue Aug 26 12:08:17 CEST 2008
Author: cami
Date: Tue Aug 26 12:08:16 2008
New Revision: 57624
Added:
pypy/dist/pypy/lang/gameboy/test/test_video_registers.py
Removed:
pypy/dist/pypy/lang/gameboy/test/test_video_control.py
Modified:
pypy/dist/pypy/lang/gameboy/cartridge.py
pypy/dist/pypy/lang/gameboy/cpu.py
pypy/dist/pypy/lang/gameboy/gameboy.py
pypy/dist/pypy/lang/gameboy/gameboy_implementation.py
pypy/dist/pypy/lang/gameboy/interrupt.py
pypy/dist/pypy/lang/gameboy/joypad.py
pypy/dist/pypy/lang/gameboy/ram.py
pypy/dist/pypy/lang/gameboy/serial.py
pypy/dist/pypy/lang/gameboy/sound.py
pypy/dist/pypy/lang/gameboy/test/test_video.py
pypy/dist/pypy/lang/gameboy/timer.py
pypy/dist/pypy/lang/gameboy/video.py
Log:
added new status register with some doc for video
added tests for StatusRegister
rename VideoControl to ControlRegister
adapted implementation to handle the new register
removed some debug print outs
Modified: pypy/dist/pypy/lang/gameboy/cartridge.py
==============================================================================
--- pypy/dist/pypy/lang/gameboy/cartridge.py (original)
+++ pypy/dist/pypy/lang/gameboy/cartridge.py Tue Aug 26 12:08:16 2008
@@ -365,7 +365,7 @@
class MBC1(MBC):
"""
- PyGirl GameBoy (TM) Emulator
+ PyGirl Emulator
Memory Bank Controller 1 (2MB ROM, 32KB RAM)
@@ -427,8 +427,7 @@
class MBC2(MBC):
"""
- PyGirl GameBoy (TM) Emulator
-
+ PyGirl GameBoPyGirl
Memory Bank Controller 2 (256KB ROM, 512x4bit RAM)
0000-3FFF ROM Bank 0 (16KB)
@@ -488,9 +487,7 @@
class MBC3(MBC):
"""
- PyGirl GameBoy (TM) Emulator
-
- Memory Bank Controller 3 (2MB ROM, 32KB RAM, Real Time Clock)
+ PyGirl GameBoy (TM) EmulatPyGirlBank Controller 3 (2MB ROM, 32KB RAM, Real Time Clock)
0000-3FFF ROM Bank 0 (16KB)
4000-7FFF ROM Bank 1-127 (16KB)
@@ -642,7 +639,7 @@
"""
PyGirl GameBoy (TM) Emulator
- Memory Bank Controller 5 (8MB ROM, 128KB RAM)
+ MPyGirler 5 (8MB ROM, 128KB RAM)
*
0000-3FFF ROM Bank 0 (16KB)
4000-7FFF ROM Bank 1-511 (16KB)
@@ -703,7 +700,7 @@
"""
PyGirl GameBoy (TM) Emulator
- Hudson Memory Bank Controller 3 (2MB ROM, 128KB RAM, RTC)
+ Hudson Memory PyGirl2MB ROM, 128KB RAM, RTC)
0000-3FFF ROM Bank 0 (16KB)
4000-7FFF ROM Bank 1-127 (16KB)
Modified: pypy/dist/pypy/lang/gameboy/cpu.py
==============================================================================
--- pypy/dist/pypy/lang/gameboy/cpu.py (original)
+++ pypy/dist/pypy/lang/gameboy/cpu.py Tue Aug 26 12:08:16 2008
@@ -425,7 +425,6 @@
self.double_register_inverse_call(CPUFetchCaller(self), register)
def push(self, data, use_cycles=True):
- print hex(data)
# Stack, 2 cycles
self.sp.dec(use_cycles) # 2 cycles
self.memory.write(self.sp.get(use_cycles), data)
Modified: pypy/dist/pypy/lang/gameboy/gameboy.py
==============================================================================
--- pypy/dist/pypy/lang/gameboy/gameboy.py (original)
+++ pypy/dist/pypy/lang/gameboy/gameboy.py Tue Aug 26 12:08:16 2008
@@ -1,5 +1,5 @@
"""
-PyGirl GameBoy (TM) Emulator
+PyGirl Emulator
GameBoy Scheduler and Memory Mapper
@@ -92,7 +92,6 @@
def emulate(self, ticks):
while ticks > 0:
count = self.get_cycles()
- print "python: ticks", count
self.cpu.emulate(count)
self.serial.emulate(count)
self.timer.emulate(count)
@@ -128,7 +127,7 @@
receiver = self.get_receiver(address)
if receiver is None:
return
- raise Exception("invalid read address given")
+ #raise Exception("invalid read address given")
receiver.write(address, data)
if address == constants.STAT or address == 0xFFFF:
self.cpu.handle_pending_interrupts()
Modified: pypy/dist/pypy/lang/gameboy/gameboy_implementation.py
==============================================================================
--- pypy/dist/pypy/lang/gameboy/gameboy_implementation.py (original)
+++ pypy/dist/pypy/lang/gameboy/gameboy_implementation.py Tue Aug 26 12:08:16 2008
@@ -85,7 +85,6 @@
self.screen = RSDL.SetVideoMode(self.width, self.height, 32, 0)
def update_display(self):
- #print " update_display"
RSDL.LockSurface(self.screen)
self.draw_pixels()
RSDL.UnlockSurface(self.screen)
@@ -172,7 +171,9 @@
# SOUND DRIVER -----------------------------------------------------------------
class SoundDriverImplementation(SoundDriver):
-
+ """
+ The current implementation doesnt handle sound yet
+ """
def __init__(self):
SoundDriver.__init__(self)
self.create_sound_driver()
Modified: pypy/dist/pypy/lang/gameboy/interrupt.py
==============================================================================
--- pypy/dist/pypy/lang/gameboy/interrupt.py (original)
+++ pypy/dist/pypy/lang/gameboy/interrupt.py Tue Aug 26 12:08:16 2008
@@ -30,7 +30,7 @@
class Interrupt(iMemory):
"""
- PyGirl GameBoy (TM) Emulator
+ PyGirl Emulator
Interrupt Controller
"""
Modified: pypy/dist/pypy/lang/gameboy/joypad.py
==============================================================================
--- pypy/dist/pypy/lang/gameboy/joypad.py (original)
+++ pypy/dist/pypy/lang/gameboy/joypad.py Tue Aug 26 12:08:16 2008
@@ -5,7 +5,7 @@
class Joypad(iMemory):
"""
- PyGirl GameBoy (TM) Emulator
+ PyGirl Emulator
Joypad Input
"""
@@ -31,7 +31,6 @@
if self.driver.is_raised():
self.update()
self.cycles = constants.JOYPAD_CLOCK
- #self.cycles = 150
def write(self, address, data):
if address == constants.JOYP:
@@ -61,6 +60,10 @@
class JoypadDriver(object):
"""
Maps the Input to the Button and Direction Codes
+ get_button_code and get_direction_code are called by the system
+ to check for pressed buttons
+ On Button change an interrupt flag self.raised is set to send later
+ and interrupt to inform the system for a pressed button
"""
def __init__(self):
self.raised = False
Modified: pypy/dist/pypy/lang/gameboy/ram.py
==============================================================================
--- pypy/dist/pypy/lang/gameboy/ram.py (original)
+++ pypy/dist/pypy/lang/gameboy/ram.py Tue Aug 26 12:08:16 2008
@@ -1,5 +1,5 @@
"""
-PyGirl GameBoy (TM) Emulator
+PyGirl Emulator
Work and High RAM
"""
Modified: pypy/dist/pypy/lang/gameboy/serial.py
==============================================================================
--- pypy/dist/pypy/lang/gameboy/serial.py (original)
+++ pypy/dist/pypy/lang/gameboy/serial.py Tue Aug 26 12:08:16 2008
@@ -5,7 +5,7 @@
class Serial(iMemory):
"""
- PyGirl GameBoy (TM) Emulator
+ PyGirl Emulator
Serial Link Controller
"""
Modified: pypy/dist/pypy/lang/gameboy/sound.py
==============================================================================
--- pypy/dist/pypy/lang/gameboy/sound.py (original)
+++ pypy/dist/pypy/lang/gameboy/sound.py Tue Aug 26 12:08:16 2008
@@ -1,5 +1,5 @@
"""
-PyGirl GameBoy (TM) Emulator
+PyGirl Emulator
Audio Processor Unit (Sharp LR35902 APU)
"""
Modified: pypy/dist/pypy/lang/gameboy/test/test_video.py
==============================================================================
--- pypy/dist/pypy/lang/gameboy/test/test_video.py (original)
+++ pypy/dist/pypy/lang/gameboy/test/test_video.py Tue Aug 26 12:08:16 2008
@@ -30,7 +30,8 @@
video = get_video()
assert video.cycles == constants.MODE_2_TICKS
assert video.control.read() == 0x91
- assert video.stat == 2
+ assert video.status.read(extend=False) == 2
+ assert video.status.read(extend=True) == 2 + 0x80
assert video.line_y == 0
assert video.line_y_compare == 0
assert video.dma == 0xFF
@@ -80,7 +81,6 @@
def test_read_write_control():
video = get_video()
- (0xFF40, "control")
value = 0x2
video.write(0xFF40, value)
assert video.control.read() == value
@@ -88,14 +88,15 @@
def test_set_status():
video = get_video()
- value = 0x95
- valueb = 0xD2
- video.stat = valueb
- video.write(0xFF41, value)
- assert video.stat == (valueb & 0x87) | (value & 0x78)
+ valueA = 0x95
+ for valueB in range(0, 0xFF):
+ video.status.write(valueB, write_all=True)
+ assert video.status.read(extend=True) == valueB
+ video.write(0xFF41, valueA)
+ assert video.get_status() == (valueB & 0x87) | (valueA & 0x78)
video.control.write(0x80)
- video.stat = 0x01
+ video.status.write(0x01, write_all=True)
video.write(0xFF41, 0x01)
assert video.interrupt.lcd.is_pending()
@@ -108,30 +109,31 @@
video.control.write(0x80)
video.line_y = value -1
- video.stat = 0xFF
+ video.status.write(0xFF, write_all=True)
+ assert video.status.read(extend=True) == 0xFF
video.write(0xFF45, value)
- assert video.stat == 0xFB
+ assert video.status.read(extend=True) == 0xFB
assert video.interrupt.lcd.is_pending() == False
video.control.write(0x80)
video.line_y = 0xF6
- video.stat = 0x04
+ video.status.write(0x04, write_all=True)
video.write(0xFF45, value)
- assert video.stat == 0x04
+ assert video.status.read(extend=True) == 0x04
assert video.interrupt.lcd.is_pending() == False
video.control.write(0x80)
video.line_y = 0xF6
- video.stat = 0x00
+ video.status.write(0x00, write_all=True)
video.write(0xFF45, value)
- assert video.stat == 0x04
+ assert video.status.read(extend=True) == 0x04
assert video.interrupt.lcd.is_pending() == False
video.control.write(0x80)
video.line_y = 0xF6
- video.stat = 0x40
+ video.status.write(0x40, write_all=True)
video.write(0xFF45, value)
- assert video.stat == 0x44
+ assert video.status.read(extend=True) == 0x44
assert video.interrupt.lcd.is_pending() == True
@@ -158,12 +160,12 @@
def test_control_reset1():
video = get_video()
video.control.write(0)
- video.stat = 0x30
+ video.status.write(0x30, write_all=True)
video.line_y = 1
video.display = True
video.write(0xFF40, 0x80)
assert video.control.read() == 0x80
- assert video.stat == 0x30 + 0x02
+ assert video.status.read(extend=True) == 0x30 + 0x02
assert video.cycles == constants.MODE_2_TICKS
assert video.line_y == 0
assert video.display == False
@@ -171,12 +173,12 @@
def test_control_reset2():
video = get_video()
video.control.write(0x80)
- video.stat = 0x30
+ video.status.write(0x30, write_all=True)
video.line_y = 1
video.display = True
video.write(0xFF40, 0x30)
assert video.control.read() == 0x30
- assert video.stat == 0x30
+ assert video.status.read(extend=True) == 0x30
assert video.cycles == constants.MODE_1_TICKS
assert video.line_y == 0
assert video.display == True
@@ -223,10 +225,10 @@
def test_emulate_OAM():
video = get_video()
video.transfer = False
- video.stat = 0xFE
+ video.status.write(0xFE, write_all=True)
video.cycles = 0
video.emulate_oam()
- assert video.stat == 0xFF
+ assert video.status.read(extend=True) == 0xFF
assert video.cycles == constants.MODE_3_BEGIN_TICKS
assert video.transfer == True
@@ -235,42 +237,90 @@
video.transfer = False
video.cycles = 0
- video.stat = 0xF0
+ video.status.write(0xF0, write_all=True)
video.emulate_transfer()
- assert video.stat == 0xF0
+ assert video.status.read(extend=True) == 0xF0
assert video.cycles == constants.MODE_0_TICKS
assert not video.interrupt.lcd.is_pending()
video.transfer = False
video.cycles = 0
- video.stat = 0xF8
+ video.status.write(0xF8, write_all=True)
assert not video.interrupt.lcd.is_pending()
video.emulate_transfer()
- assert video.stat == 0xF8
+ assert video.status.read(extend=True) == 0xF8
assert video.cycles == constants.MODE_0_TICKS
assert video.interrupt.lcd.is_pending()
video.transfer = True
video.cycles = 0
- video.stat = 0xFC
+ video.status.write(0xFC, write_all=True)
video.emulate_transfer()
assert video.cycles == constants.MODE_3_END_TICKS
assert video.transfer == False
- assert video.stat == 0xFF
+ assert video.status.read(extend=True) == 0xFF
+
+
+def test_emulate_hblank_line_y_compare():
+ video = get_video()
+ video.line_y = 0x12
+ video.line_y_compare = 0x13
+ video.status.line_y_compare_flag = True
+ video.status.line_y_compare_interrupt = False
+ video.emulate_hblank_line_y_compare()
+ assert not video.status.line_y_compare_flag
+ assert not video.interrupt.lcd.is_pending()
+
+ video.reset()
+ video.line_y = 0x12
+ video.line_y_compare = 0x12
+ video.status.line_y_compare_flag = False
+ video.status.line_y_compare_interrupt = False
+ video.emulate_hblank_line_y_compare()
+ assert video.status.line_y_compare_flag
+ assert not video.interrupt.lcd.is_pending()
+
+ video.reset()
+ video.line_y = 0x12
+ video.line_y_compare = 0x12
+ video.status.line_y_compare_flag = False
+ video.status.line_y_compare_interrupt = True
+ video.emulate_hblank_line_y_compare()
+ assert video.status.line_y_compare_flag
+ assert video.interrupt.lcd.is_pending()
+def test_emulate_hblank_line_y_compare_status_check():
+ video = get_video()
+ video.line_y = 0x12
+ video.line_y_compare = 0x12
+ video.status.line_y_compare_flag = True
+ video.status.line_y_compare_interrupt = True
+ video.emulate_hblank_line_y_compare(stat_check=True)
+ assert video.status.line_y_compare_flag
+ assert not video.interrupt.lcd.is_pending()
+
+ video.reset()
+ video.line_y = 0x12
+ video.line_y_compare = 0x12
+ video.status.line_y_compare_flag = False
+ video.status.line_y_compare_interrupt = True
+ video.emulate_hblank_line_y_compare(stat_check=True)
+ assert video.status.line_y_compare_flag
+ assert video.interrupt.lcd.is_pending()
def test_emulate_h_blank_part_1_1():
video = get_video()
video.line_y = 0
video.line_y_compare = 1
- video.stat = 0x20
+ video.status.write(0x20, write_all=True)
video.cycles = 0
video.frames = 0
assert not video.interrupt.lcd.is_pending()
video.emulate_hblank()
assert video.cycles == constants.MODE_2_TICKS
assert video.interrupt.lcd.is_pending()
- assert video.stat == 0x20 + 0x04 + 0x2
+ assert video.status.get_mode() == 2
+ assert video.status.read(extend=True) == 0x20 + 0x04 + 0x2
assert video.line_y == 1
assert video.frames == 0
@@ -279,21 +329,21 @@
video = get_video()
video.line_y = 1
video.line_y_compare = 0
- video.stat = 0x0F
+ video.status.write(0x0F, write_all=True)
video.cycles = 0
video.frames = 0
video.emulate_hblank()
assert video.line_y == 2
assert video.cycles == constants.MODE_2_TICKS
assert not video.interrupt.lcd.is_pending()
- assert video.stat == 0x0B&0xFC + 0x2
+ assert video.status.read(extend=True) == 0x0B&0xFC + 0x2
assert video.frames == 0
def test_emulate_h_blank_part_2_2():
video = get_video()
video.line_y = 144
video.line_y_compare = 0
- video.stat = 0xFB
+ video.status.write(0xFB, write_all=True)
video.cycles = 0
video.frames = 0
video.frame_skip = 20
@@ -303,7 +353,7 @@
assert video.line_y == 145
assert video.cycles == constants.MODE_1_BEGIN_TICKS
assert not video.interrupt.lcd.is_pending()
- assert video.stat == 0xFB & 0xFC + 0x01
+ assert video.status.read(extend=True) == 0xFB & 0xFC + 0x01
assert video.frames == 1
assert video.display == False
assert video.vblank == True
@@ -313,7 +363,7 @@
video = get_video()
video.line_y = 144
video.line_y_compare = 0
- video.stat = 0xFB
+ video.status.write(0xFB, write_all=True)
video.cycles = 0
video.frames = 10
video.frame_skip = 10
@@ -323,7 +373,7 @@
assert video.line_y == 145
assert video.cycles == constants.MODE_1_BEGIN_TICKS
assert not video.interrupt.lcd.is_pending()
- assert video.stat == 0xFB & 0xFC + 0x01
+ assert video.status.read(extend=True) == 0xFB & 0xFC + 0x01
assert video.frames == 0
assert video.vblank == True
@@ -331,23 +381,24 @@
def test_emulate_v_vblank_1():
video = get_video()
video.interrupt.set_interrupt_flag(0)
- video.stat = 0xFE
+ video.status.write(0xFE, write_all=True)
video.vblank = True
video.cycles = 0
video.emulate_vblank()
assert video.vblank == False
- assert video.stat == 0xFD
+ assert video.status.get_mode() == 1
+ assert video.status.read(extend=True) == 0xFD
assert video.cycles == constants.MODE_1_TICKS - constants.MODE_1_BEGIN_TICKS
assert video.interrupt.vblank.is_pending()
assert video.interrupt.lcd.is_pending()
video.interrupt.set_interrupt_flag(0)
- video.stat = 0x00
+ video.status.write(0x00, write_all=True)
video.vblank = True
assert not video.interrupt.vblank.is_pending()
assert not video.interrupt.lcd.is_pending()
video.emulate_vblank()
- assert video.stat == 0x01
+ assert video.status.read(extend=True) == 0x01
assert video.interrupt.vblank.is_pending()
assert not video.interrupt.lcd.is_pending()
@@ -356,22 +407,22 @@
def test_emulate_v_vblank_2():
video = get_video()
video.interrupt.set_interrupt_flag(0)
- video.stat = 0x2D
+ video.status.write(0x2D, write_all=True)
video.vblank = False
video.cycles = 0
video.line_y = 0
video.emulate_vblank()
assert video.vblank == False
- assert video.stat == 0x2E
+ assert video.status.read(extend=True) == 0x2E
assert video.cycles == constants.MODE_2_TICKS
assert not video.interrupt.vblank.is_pending()
assert video.interrupt.lcd.is_pending()
video.interrupt.set_interrupt_flag(0)
video.cycles = 0
- video.stat = 0xFD
+ video.status.write(0xFD, write_all=True)
video.emulate_vblank()
assert video.vblank == False
- assert video.stat == 0xFE
+ assert video.status.read(extend=True) == 0xFE
assert video.cycles == constants.MODE_2_TICKS
assert not video.interrupt.lcd.is_pending()
Added: pypy/dist/pypy/lang/gameboy/test/test_video_registers.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/lang/gameboy/test/test_video_registers.py Tue Aug 26 12:08:16 2008
@@ -0,0 +1,75 @@
+from pypy.lang.gameboy import constants
+from pypy.lang.gameboy.video import ControlRegister
+from pypy.lang.gameboy.video import StatusRegister
+import py
+
+
+# ControlRegister --------------------------------------------------------------
+
+def test_video_control_reset():
+ control = ControlRegister()
+ assert control.read() == 0x91
+ control.write(0xFF)
+ assert control.read() == 0xFF
+ control.reset()
+ assert control.read() == 0x91
+
+
+def test_video_control_read_write_properties():
+ control = ControlRegister()
+ properties = ["lcd_enabled",
+ "window_upper_tile_map_selected",
+ "window_enabled",
+ "background_and_window_lower_tile_data_selected",
+ "background_upper_tile_map_selected",
+ "big_sprite_size_selected",
+ "sprite_display_enabled",
+ "background_enabled"]
+ properties.reverse()
+ for index in range(8):
+ property = properties[index];
+ control.write(0x00)
+ assert control.read() == 0x00
+ assert control.__getattribute__(property) == False
+
+ control.write(0xFF)
+ assert control.read() == 0xFF
+ assert control.__getattribute__(property) == True
+
+ control.write(0x00)
+ control.__setattr__(property, True)
+ assert control.__getattribute__(property) == True
+ assert control.read() & (1 << index) == (1 << index)
+ assert control.read() & (~(1 << index)) == 0
+
+ control.write(1 << index)
+ assert control.__getattribute__(property) == True
+ assert control.read() & (1 << index) == (1 << index)
+ assert control.read() & (~(1 << index)) == 0
+
+
+# StatusRegister ---------------------------------------------------------------
+
+def test_video_status_reset():
+ status = StatusRegister()
+ assert status.read(extend=True) == 0x02 + 0x80
+
+ status.write(0x00, write_all=True)
+ assert status.read(extend=True) == 0x00
+ status.reset()
+ assert status.read(extend=True) == 0x02 + 0x80
+
+ status.write(0xFF, write_all=True)
+ assert status.read(extend=True) == 0xFF
+ status.reset()
+ assert status.read(extend=True) == 0x02 + 0x80
+
+def test_video_status_mode():
+ status = StatusRegister()
+ assert status.get_mode() == 2
+
+ for i in range(3):
+ status.set_mode(i)
+ assert status.get_mode() == i
+ status.set_mode(4)
+ assert status.get_mode() == 0
\ No newline at end of file
Modified: pypy/dist/pypy/lang/gameboy/timer.py
==============================================================================
--- pypy/dist/pypy/lang/gameboy/timer.py (original)
+++ pypy/dist/pypy/lang/gameboy/timer.py Tue Aug 26 12:08:16 2008
@@ -1,5 +1,5 @@
"""
-PyGirl GameBoy (TM) Emulator
+PyGirl Emulator
Timer and Divider
"""
Modified: pypy/dist/pypy/lang/gameboy/video.py
==============================================================================
--- pypy/dist/pypy/lang/gameboy/video.py (original)
+++ pypy/dist/pypy/lang/gameboy/video.py Tue Aug 26 12:08:16 2008
@@ -1,5 +1,5 @@
"""
- PyGirl GameBoy (TM) Emulator
+ PyGirl Emulator
constants.LCD Video Display Processor
"""
@@ -31,7 +31,7 @@
# -----------------------------------------------------------------------------
-class VideoControl(object):
+class ControlRegister(object):
# used for enabled or disabled window or background
# Bit 7 - LCD Display Enable (0=Off, 1=On)
# Bit 6 - Window Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF)
@@ -47,11 +47,11 @@
def reset(self):
self.lcd_enabled = True
- self.window_upper_tile_map_selected = False
+ self.window_upper_tile_map_selected = False
self.window_enabled = False
self.background_and_window_lower_tile_data_selected = True
- self.background_upper_tile_map_selected = False
- self.big_sprite_size_selected = False
+ self.background_upper_tile_map_selected = False
+ self.big_sprite_size_selected = False
self.sprite_display_enabled = False
self.background_enabled = True
@@ -78,18 +78,79 @@
self.sprite_display_enabled = bool(value & (1 << 1))
self.background_enabled = bool(value & (1 << 0))
- def get_bg_tile_data_address(self):
- pass
# -----------------------------------------------------------------------------
+class StatusRegister(object):
+
+ """
+ Bit 6 - LYC=LY Coincidence Interrupt (1=Enable) (Read/Write)
+ Bit 5 - Mode 2 OAM Interrupt (1=Enable) (Read/Write)
+ Bit 4 - Mode 1 V-Blank Interrupt (1=Enable) (Read/Write)
+ Bit 3 - Mode 0 H-Blank Interrupt (1=Enable) (Read/Write)
+ Bit 2 - Coincidence Flag (0:LYC<>LY, 1:LYC=LY) (Read Only)
+ Bit 1-0 - Mode Flag (Mode 0-3, see below) (Read Only)
+ 0: During H-Blank
+ 1: During V-Blank
+ 2: During Searching OAM-RAM
+ 3: During Transfering Data to LCD Driver
+ """
+
+ def __init__(self):
+ self.reset()
+
+ def reset(self):
+ self._mode = 0x02
+ self.line_y_compare_flag = False
+ self.mode_0_h_blank_interrupt = False
+ self.mode_1_v_blank_interrupt = False
+ self.mode_2_oam_interrupt = False
+ self.line_y_compare_interrupt = False
+ self.status = True
+
+
+ def read(self, extend=False):
+ value = self._mode
+ value += self.line_y_compare_flag << 2
+ value += self.mode_0_h_blank_interrupt << 3
+ value += self.mode_1_v_blank_interrupt << 4
+ value += self.mode_2_oam_interrupt << 5
+ value += self.line_y_compare_interrupt << 6
+ if extend:
+ value += int(self.status) << 7
+ return value
+
+
+ def write(self, value, write_all=False, \
+ keep_mode_0_h_blank_interrupt=False):
+ if write_all:
+ self._mode = value & 0x03
+ self.line_y_compare_flag = bool(value & (1 << 2))
+ self.status = bool(value & (1 << 7))
+ self.mode_0_h_blank_interrupt = bool(value & (1 << 3))
+ self.mode_1_v_blank_interrupt = bool(value & (1 << 4))
+ self.mode_2_oam_interrupt = bool(value & (1 << 5))
+ self.line_y_compare_interrupt = bool(value & (1 << 6))
+
+ def get_mode(self):
+ return self._mode
+
+ def set_mode(self, mode):
+ self._mode = mode & 0x03
+
+ def line_y_compare_check(self):
+ return not self.line_y_compare_flag or not self.line_y_compare_interrupt
+
+# -----------------------------------------------------------------------------
+
class Video(iMemory):
def __init__(self, video_driver, interrupt, memory):
assert isinstance(video_driver, VideoDriver)
self.driver = video_driver
self.interrupt = interrupt
- self.control = VideoControl()
+ self.control = ControlRegister()
+ self.status = StatusRegister()
self.memory = memory
self.reset()
@@ -102,7 +163,7 @@
def reset(self):
self.cycles = constants.MODE_2_TICKS
self.control.reset()
- self.stat = 2
+ self.status.reset()
self.line_y = 0
self.line_y_compare = 0
self.dma = 0xFF
@@ -177,7 +238,6 @@
self.vram[address - constants.VRAM_ADDR] = data & 0xFF
def read(self, address):
- print address, hex(address)
if address == constants.LCDC:
return self.get_control()
elif address == constants.STAT:
@@ -225,7 +285,7 @@
def consume_cycles(self):
while self.cycles <= 0:
- mode = self.stat & 0x03
+ mode = self.status.get_mode()
if mode == 0:
self.emulate_hblank()
elif mode == 1:
@@ -239,11 +299,10 @@
return self.control.read()
def set_control(self, data):
- if (self.control.read() & 0x80) != (data & 0x80):
+ if self.control.lcd_enabled != bool(data & 0x80):
self.reset_control(data)
# don't draw window if it was not enabled and not being drawn before
- if not self.control.window_enabled and \
- (data & 0x20) != 0 and \
+ if not self.control.window_enabled and (data & 0x20) != 0 and \
self.window_line_y == 0 and self.line_y > self.window_y:
self.window_line_y = 144
self.control.write(data)
@@ -251,27 +310,27 @@
def reset_control(self, data):
# NOTE: do not reset constants.LY=LYC flag (bit 2) of the STAT register (Mr. Do!)
self.line_y = 0
- self.stat = (self.stat & 0xFC)
if (data & 0x80) != 0:
- self.stat |= 0x02
+ self.status.set_mode(0x02)
self.cycles = constants.MODE_2_TICKS
self.display = False
else:
+ self.status.set_mode(0)
self.cycles = constants.MODE_1_TICKS
self.clear_frame()
def get_status(self):
- return 0x80 | self.stat
+ return self.status.read(extend=True)
def set_status(self, data):
- self.stat = (self.stat & 0x87) | (data & 0x78)
+ self.status.write(data)
self.set_status_bug()
def set_status_bug(self) :
# Gameboy Bug
if self.control.lcd_enabled and \
- (self.stat & 0x03) == 0x01 and \
- (self.stat & 0x44) != 0x44:
+ self.status.get_mode() == 0x01 and \
+ self.status.line_y_compare_check():
self.interrupt.raise_interrupt(constants.LCD)
def get_scroll_y(self):
@@ -309,25 +368,25 @@
return self.background_palette
def set_background_palette(self, data):
- if self.background_palette == data: return
- self.background_palette = data
- self.dirty = True
+ if self.background_palette != data:
+ self.background_palette = data
+ self.dirty = True
def get_object_palette_0(self):
return self.object_palette_0
def set_object_palette_0(self, data):
- if self.object_palette_0 == data: return
- self.object_palette_0 = data
- self.dirty = True
+ if self.object_palette_0 != data:
+ self.object_palette_0 = data
+ self.dirty = True
def get_object_palette_1(self):
return self.object_palette_1
def set_object_palette_1(self, data):
- if self.object_palette_1 == data: return
- self.object_palette_1 = data
- self.dirty = True
+ if self.object_palette_1 != data:
+ self.object_palette_1 = data
+ self.dirty = True
def get_window_y(self):
return self.window_y
@@ -355,58 +414,61 @@
# interrupt checks ---------------------------------------------------
def h_blank_interrupt_check(self):
- if (self.stat & 0x08) != 0 and (self.stat & 0x44) != 0x44:
+ if self.status.mode_0_h_blank_interrupt and \
+ self.status.line_y_compare_check():
self.interrupt.raise_interrupt(constants.LCD)
def oam_interrupt_check(self):
- if (self.stat & 0x20) != 0 and (self.stat & 0x44) != 0x44:
+ if self.status.mode_2_oam_interrupt and \
+ self.status.line_y_compare_check():
self.interrupt.raise_interrupt(constants.LCD)
def v_blank_interrupt_check(self):
- if (self.stat & 0x10) != 0:
+ if self.status.mode_1_v_blank_interrupt:
self.interrupt.raise_interrupt(constants.LCD)
def line_y_line_y_compare_interrupt_check(self):
- self.stat |= 0x04
- if (self.stat & 0x40) != 0:
+ print "line_y_line_y_compare_interrupt_check"
+ self.status.line_y_compare_flag = True
+ if self.status.line_y_compare_interrupt:
self.interrupt.raise_interrupt(constants.LCD)
# mode setting -----------------------------------------------------------
def set_mode_3_begin(self):
- self.stat = (self.stat & 0xFC) | 0x03
+ self.status.set_mode(3)
self.cycles += constants.MODE_3_BEGIN_TICKS
self.transfer = True
def set_mode_3_end(self):
- self.stat = (self.stat & 0xFC) | 0x03
+ self.status.set_mode(3)
self.cycles += constants.MODE_3_END_TICKS
self.transfer = False
def set_mode_0(self):
- self.stat = (self.stat & 0xFC)
+ self.status.set_mode(0)
self.cycles += constants.MODE_0_TICKS
self.h_blank_interrupt_check()
def set_mode_2(self):
- self.stat = (self.stat & 0xFC) | 0x02
+ self.status.set_mode(2)
self.cycles += constants.MODE_2_TICKS
self.oam_interrupt_check()
def set_mode_1_begin(self):
- self.stat = (self.stat & 0xFC) | 0x01
+ self.status.set_mode(1)
self.cycles += constants.MODE_1_BEGIN_TICKS
def set_mode_1(self):
- self.stat = (self.stat & 0xFC) | 0x01
+ self.status.set_mode(1)
self.cycles += constants.MODE_1_TICKS
def set_mode_1_between(self):
- self.stat = (self.stat & 0xFC) | 0x01
+ self.status.set_mode(1)
self.cycles += constants.MODE_1_TICKS - constants.MODE_1_BEGIN_TICKS
def set_mode_1_end(self):
- self.stat = (self.stat & 0xFC) | 0x01
+ self.status.set_mode(1)
self.cycles += constants.MODE_1_END_TICKS
# ----------------------------------------------------------------
@@ -422,12 +484,12 @@
def emulate_hblank_line_y_compare(self, stat_check=False):
if self.line_y == self.line_y_compare:
if stat_check:
- if (self.stat & 0x04) == 0:
+ if not self.status.line_y_compare_flag:
self.line_y_line_y_compare_interrupt_check()
else:
self.line_y_line_y_compare_interrupt_check()
else:
- self.stat &= 0xFB
+ self.status.line_y_compare_flag = False
def emulate_hblank_part_2(self):
if self.display:
@@ -507,8 +569,7 @@
return tile_map, tile_data
def draw_window(self):
- if self.line_y < self.window_y or \
- self.window_x >= 167 or \
+ if self.line_y < self.window_y or self.window_x >= 167 or \
self.window_line_y >= 144:
return
tile_map, tile_data = self.prepare_window_data()
More information about the Pypy-commit
mailing list