[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