[pypy-svn] r58455 - in pypy/dist/pypy/lang/gameboy: . test

cami at codespeak.net cami at codespeak.net
Sun Sep 28 00:39:25 CEST 2008


Author: cami
Date: Sun Sep 28 00:39:24 2008
New Revision: 58455

Added:
   pypy/dist/pypy/lang/gameboy/video_mode.py
   pypy/dist/pypy/lang/gameboy/video_register.py
   pypy/dist/pypy/lang/gameboy/video_sprite.py
Modified:
   pypy/dist/pypy/lang/gameboy/test/test_video_registers.py
   pypy/dist/pypy/lang/gameboy/test/test_video_sprite.py
   pypy/dist/pypy/lang/gameboy/video.py
Log:
created separated files for video elements to cleanup
adapted tests according to split up
adapted imports for the different files


Modified: pypy/dist/pypy/lang/gameboy/test/test_video_registers.py
==============================================================================
--- pypy/dist/pypy/lang/gameboy/test/test_video_registers.py	(original)
+++ pypy/dist/pypy/lang/gameboy/test/test_video_registers.py	Sun Sep 28 00:39:24 2008
@@ -1,8 +1,8 @@
 from pypy.lang.gameboy import constants
-from pypy.lang.gameboy.video import ControlRegister
-from pypy.lang.gameboy.video import StatusRegister
-from pypy.lang.gameboy.video import Window
-from pypy.lang.gameboy.video import Background
+from pypy.lang.gameboy.video_register import ControlRegister
+from pypy.lang.gameboy.video_register import StatusRegister
+from pypy.lang.gameboy.video_sprite import Window
+from pypy.lang.gameboy.video_sprite import Background
 from pypy.lang.gameboy.test.test_video import get_video
 import py
 
@@ -22,7 +22,7 @@
     control.write(0xFF)
     assert control.read() == 0xFF
     control.reset()
-    assert control.read() == 0x91
+    assert control.read() ==                                            0x91
     
     
 def test_video_control_read_write_properties():

Modified: pypy/dist/pypy/lang/gameboy/test/test_video_sprite.py
==============================================================================
--- pypy/dist/pypy/lang/gameboy/test/test_video_sprite.py	(original)
+++ pypy/dist/pypy/lang/gameboy/test/test_video_sprite.py	Sun Sep 28 00:39:24 2008
@@ -1,5 +1,5 @@
 from pypy.lang.gameboy import constants
-from pypy.lang.gameboy.video import Sprite
+from pypy.lang.gameboy.video_sprite import Sprite
 from pypy.lang.gameboy.video import Video
 from pypy.lang.gameboy.test.test_video import get_video
 import py

Modified: pypy/dist/pypy/lang/gameboy/video.py
==============================================================================
--- pypy/dist/pypy/lang/gameboy/video.py	(original)
+++ pypy/dist/pypy/lang/gameboy/video.py	Sun Sep 28 00:39:24 2008
@@ -5,9 +5,13 @@
 import math
 import operator
 from pypy.lang.gameboy import constants
-from pypy.lang.gameboy.constants import SPRITE_SIZE, GAMEBOY_SCREEN_WIDTH, GAMEBOY_SCREEN_HEIGHT
+from pypy.lang.gameboy.constants import SPRITE_SIZE, GAMEBOY_SCREEN_WIDTH, \
+                                        GAMEBOY_SCREEN_HEIGHT
 from pypy.lang.gameboy.ram import iMemory
 from pypy.lang.gameboy.cpu import process_2s_complement
+from pypy.lang.gameboy.video_register import ControlRegister, StatusRegister
+from pypy.lang.gameboy.video_sprite import Sprite, Tile, Background, Window
+from pypy.lang.gameboy.video_mode import Mode0, Mode1, Mode2, Mode3
 
 # -----------------------------------------------------------------------------
 class VideoCallWraper(object):
@@ -29,600 +33,7 @@
     
     def call(self, pos, color, mask):
         self.video.set_tile_line(pos, color, mask)
-    
-
-# -----------------------------------------------------------------------------
-
-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)
-    Bit 5 - Window Display Enable          (0=Off, 1=On)
-    Bit 4 - BG & Window Tile Data Select   (0=8800-97FF, 1=8000-8FFF)
-    Bit 3 - BG Tile Map Display Select     (0=9800-9BFF, 1=9C00-9FFF)
-    Bit 2 - OBJ (Sprite) Size              (0=8x8, 1=8x16)
-    Bit 1 - OBJ (Sprite) Display Enable    (0=Off, 1=On)
-    Bit 0 - BG Display (for CGB see below) (0=Off, 1=On)
-    """
-    def __init__(self, window, background):
-        self.window     = window
-        self.background = background
-        self.reset()
-        
-    def reset(self):
-        self.lcd_enabled                              = True
-        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.sprites_enabled                           = False
-        self.background.enabled                       = True
-        
-    def read(self):
-        value = 0
-        value += int(self.lcd_enabled)                        << 7 
-        value += int(self.window.upper_tile_map_selected)     << 6 
-        value += int(self.window.enabled)                     << 5
-        value += int(self.background_and_window_lower_tile_data_selected)  << 4
-        value += int(self.background.upper_tile_map_selected) << 3
-        value += int(self.big_sprite_size_selected)           << 2
-        value += int(self.sprites_enabled)                    << 1
-        value += int(self.background.enabled)                 << 0
-        return value
-        
-    def write(self, value):
-        self.lcd_enabled                             = bool(value & (1 << 7))
-        self.window.upper_tile_map_selected          = bool(value & (1 << 6))
-        self.window.enabled                          = bool(value & (1 << 5))
-        self.background_and_window_lower_tile_data_selected = \
-                                                       bool(value & (1 << 4))
-        self.background.upper_tile_map_selected      = bool(value & (1 << 3))
-        self.big_sprite_size_selected                = bool(value & (1 << 2))
-        self.sprites_enabled                         = bool(value & (1 << 1))
-        self.background.enabled                      = bool(value & (1 << 0))
-    
-    
-    def get_selected_tile_data_space(self):
-        if self.window.upper_tile_map_selected:
-            return constants.VRAM_DATA_A
-        else:
-            return  constants.VRAM_DATA_B
-
-# -----------------------------------------------------------------------------
-class InvalidModeOrderException(Exception):
-    def __init__(self, mode, previous_mode):
-        Exception.__init__(self, \
-                           "Wrong Mode order! No valid transition %i => %i" \
-                           % (previous_mode.id(), mode.id()))
-       
-class HandleSubclassException(Exception): 
-    def __init__(self):
-        Exception.__init__(self, "")
-        
-class Mode(object):
-
-    """
-    The two lower STAT bits show the current status of the LCD controller.
-    """
-
-    def __init__(self, video):
-        self.video = video
-        self.reset()
-        
-    def reset(self):
-        raise Exception("unimplemented method")
-                        
-    def id(self):
-        raise Exception("unimplemented method")
-    
-    def activate(self, previous_mode):
-        raise Exception("unimplemented method")
-    
-    def emulate(self):
-        raise Exception("unimplemented method")
-
-    def emulate_hblank_line_y_compare(self, stat_check=False):
-        if self.video.line_y == self.video.line_y_compare:
-            if not (stat_check and self.video.status.line_y_compare_flag):
-                self.line_y_line_y_compare_interrupt_check()
-        else:
-            self.video.status.line_y_compare_flag = False
-            
-    def line_y_line_y_compare_interrupt_check(self):
-        self.video.status.line_y_compare_flag = True
-        if self.video.status.line_y_compare_interrupt:
-            self.video.lcd_interrupt_flag.set_pending()
-
-class Mode0(Mode):
-    """
-     Mode 0: The LCD controller is in the H-Blank period and
-          the CPU can access both the display RAM (8000h-9FFFh)
-          and OAM (FE00h-FE9Fh)
-    """
-    
-    def reset(self):
-        self.h_blank_interrupt = False
-    
-    def id(self):
-        return 0
-    
-    def activate(self, previous_mode):
-        #if previous_mode.id() == 3:
-            self.video.cycles += constants.MODE_0_TICKS
-            self.h_blank_interrupt_check()
-        #else:
-            # video.reset_control() can be called in any position
-         #   pass
-            #raise InvalidModeOrderException(self, previous_mode)
-    
-    def h_blank_interrupt_check(self):
-        if self.h_blank_interrupt and \
-        self.video.status.line_y_compare_check():
-            self.video.lcd_interrupt_flag.set_pending()
-            
-    def emulate(self):
-        #self.video.emulate_hblank()
-        self.emulate_hblank()
-        
-    def emulate_hblank(self):
-        self.video.line_y += 1
-        self.emulate_hblank_line_y_compare()
-        if self.video.line_y < GAMEBOY_SCREEN_HEIGHT:
-            self.video.status.set_mode(2)
-        else:
-            self.emulate_hblank_part_2()
-            
-    def emulate_hblank_part_2(self):
-        if self.video.display:
-            self.video.draw_frame()
-        self.video.frames += 1
-        if self.video.frames >= self.video.frame_skip:
-            self.video.display = True
-            self.video.frames = 0
-        else:
-            self.video.display = False
-        self.video.status.set_mode(1)
-        self.video.v_blank  = True
-                 
-class Mode1(Mode):
-    """
-    Mode 1: The LCD contoller is in the V-Blank period (or the
-          display is disabled) and the CPU can access both the
-          display RAM (8000h-9FFFh) and OAM (FE00h-FE9Fh)
-    """
-    
-    def reset(self):
-        self.v_blank_interrupt = False
-        
-    def id(self):
-        return 1
-    
-    def activate(self, previous_mode):
-        #if previous_mode.id() == 0:
-            self.set_begin()
-        #else:
-        #    pass
-            #raise InvalidModeOrderException(self, previous_mode)
-
-    def set_begin(self):
-        self.video.cycles += constants.MODE_1_BEGIN_TICKS
-    
-    def set_between(self):
-        self.video.cycles += constants.MODE_1_TICKS - constants.MODE_1_BEGIN_TICKS
-        
-    def set_end(self):
-        self.video.cycles += constants.MODE_1_END_TICKS
-    
-    def emulate(self):
-        self.emulate_v_blank()
-   
-    def emulate_v_blank(self):
-        if self.video.v_blank:
-            self.emulate_v_blank_v_blank()
-        elif self.video.line_y == 0:
-            self.video.status.set_mode(2)
-        else:
-            self.emulate_v_blank_other()
- 
-    def emulate_v_blank_v_blank(self):
-        self.video.v_blank  = False
-        self.set_between()
-        self.v_blank_interrupt_check()
-                  
-    def v_blank_interrupt_check(self):
-        if self.v_blank_interrupt:
-            self.video.lcd_interrupt_flag.set_pending()
-        self.video.v_blank_interrupt_flag.set_pending()
-        
-    def emulate_v_blank_other(self):
-        if self.video.line_y < 153:
-            self.emulate_v_blank_mode_1()
-        else:
-            self.video.line_y        = 0
-            self.video.window.line_y = 0
-            self.set_between()
-        self.emulate_hblank_line_y_compare() 
-                
-    def emulate_v_blank_mode_1(self):
-        self.video.line_y += 1
-        if self.video.line_y != 153:
-            self.video.cycles += constants.MODE_1_TICKS
-        else:
-            self.set_end()
-            
-class Mode2(Mode):
-    """
-    Mode 2: The LCD controller is reading from OAM memory.
-          The CPU <cannot> access OAM memory (FE00h-FE9Fh)
-          during this period.
-    """
-    
-    def reset(self):
-        self.oam_interrupt = False
-        
-    def id(self):
-        return 2
-    
-    def activate(self, previous_mode):
-        #if previous_mode.id() == 0 or previous_mode.id() == 1:
-            self.video.cycles += constants.MODE_2_TICKS
-            self.oam_interrupt_check()
-        #else:
-        #    pass
-            #raise InvalidModeOrderException(self, previous_mode)
-     
-    def oam_interrupt_check(self):
-        if self.oam_interrupt and \
-        self.video.status.line_y_compare_check():
-            self.video.lcd_interrupt_flag.set_pending()
-            
-    def emulate(self):
-        self.emulate_oam()
-        
-    def emulate_oam(self):
-        self.video.status.set_mode(3)
-
-class Mode3(Mode):
-    """
-       Mode 3: The LCD controller is reading from both OAM and VRAM,
-          The CPU <cannot> access OAM and VRAM during this period.
-          CGB Mode: Cannot access Palette Data (FF69,FF6B) either.
-    """
-    
-    def reset(self):
-        pass
-    
-    def id(self):
-        return 3
-    
-    def activate(self, previous_mode):
-        #if previous_mode.id() == 2:
-            self.set_begin()
-        #else:
-        #    pass
-        #    #raise InvalidModeOrderException(self, previous_mode)
-    
-    def set_begin(self):
-        self.video.cycles  += constants.MODE_3_BEGIN_TICKS
-        self.video.transfer = True
-        
-    def set_end(self):
-        self.video.cycles  += constants.MODE_3_END_TICKS
-        self.video.transfer = False
-        
-    def emulate(self):
-        self.emulate_transfer()
-        
-    def emulate_transfer(self):
-        if self.video.transfer:
-            if self.video.display:
-                self.video.draw_line()
-                #print "mode 3 ", self.video.status.get_mode() 
-            self.set_end()
-        else:
-            self.video.status.set_mode(0)
-        
-# -----------------------------------------------------------------------------
-
-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, video):
-        self.create_modes(video)
-        self.reset()
-        
-    def create_modes(self, video):
-        self.mode0 = Mode0(video)
-        self.mode1 = Mode1(video)
-        self.mode2 = Mode2(video)
-        self.mode3 = Mode3(video)
-        self.modes   = [self.mode0, self.mode1, self.mode2, self.mode3]
-        
-        
-        
-    def reset(self):
-        self.current_mode               = self.mode2
-        self.line_y_compare_flag      = False
-        self.line_y_compare_interrupt = False
-        for mode in self.modes:
-            mode.reset()
-        #self.mode_0_h_blank_interrupt = False
-        #self.mode_1_v_blank_interrupt = False
-        #self.mode_2_oam_interrupt     = False
-        self.status                   = True
-        
-        
-    def read(self, extend=False):
-        value =  self.get_mode()
-        value += self.line_y_compare_flag      << 2
-        value += self.mode0.h_blank_interrupt  << 3
-        value += self.mode1.v_blank_interrupt  << 4
-        value += self.mode2.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.current_mode          = self.modes[value & 0x03]
-            self.line_y_compare_flag   = bool(value & (1 << 2))
-            self.status                = bool(value & (1 << 7))
-        self.mode0.h_blank_interrupt   = bool(value & (1 << 3))
-        self.mode1.v_blank_interrupt   = bool(value & (1 << 4))
-        self.mode2.oam_interrupt       = bool(value & (1 << 5))
-        self.line_y_compare_interrupt  = bool(value & (1 << 6))
-        
-    def get_mode(self):
-        return self.current_mode.id()
-    
-    def set_mode(self, mode):
-        old_mode = self.current_mode
-        self.current_mode = self.modes[mode & 0x03]
-        self.current_mode.activate(old_mode)
-        
-    def line_y_compare_check(self):
-        return not self.line_y_compare_flag or not self.line_y_compare_interrupt
-
-# -----------------------------------------------------------------------------
-
-class Sprite(object):
-    
-    def __init__(self, video):
-        self.video = video
-        self.big_size = False
-        self.reset()
-
-    def reset(self):
-        self.x              = 0
-        self.y              = 0
-        self.tile           = None
-        self.object_behind_background = False
-        self.x_flipped      = False
-        self.y_flipped      = False
-        self.palette_number = 0
-        self.hidden         = True
-        
-        
-    def get_data(self):
-        return [self.y, self.x, self.tile_number, self.get_attributes_and_flags()]
-    
-    def set_data(self, byte0=-1, byte1=-1, byte2=-1, byte3=-1):
-        """
-        extracts the sprite data from an oam entry
-        """
-        if byte0 is not -1:
-            self.extract_y_position(byte0)
-        if byte0 is not -1:
-            self.extract_x_position(byte1)
-        if byte0 is not -1:
-            self.extract_tile_number(byte2)
-        if byte0 is not -1:
-            self.extract_attributes_and_flags(byte3)
-        
-    def extract_y_position(self, data):
-        """
-        extracts the  Y Position
-        Specifies the sprites vertical position on the screen (minus 16).
-        An offscreen value (for example, Y=0 or Y>=160) hides the sprite.
-        """
-        self.y = data # - 16
-        self.hide_check()
-    
-    def extract_x_position(self, data):
-        """
-        extracts the  X Position
-        Specifies the sprites horizontal position on the screen (minus 8).
-        An offscreen value (X=0 or X>=168) hides the sprite, but the sprite
-        still affects the priority ordering - a better way to hide a sprite is 
-        to set its Y-coordinate offscreen.
-        """
-        self.x = data # - 8
-        self.hide_check()
-    
-    def extract_tile_number(self, data):
-        """
-        extracts the Tile/Pattern Number
-        Specifies the sprites Tile Number (00-FF). This (unsigned) value selects
-        a tile from memory at 8000h-8FFFh. In CGB Mode this could be either in
-        VRAM Bank 0 or 1, depending on Bit 3 of the following byte.
-        In 8x16 mode, the lower bit of the tile number is ignored. Ie. the 
-        upper 8x8 tile is "NN AND FEh", and the lower 8x8 tile is "NN OR 01h".
-        """
-        self.tile_number = data
-    
-    def extract_attributes_and_flags(self, data):
-        """
-        extracts the Attributes/Flags:
-        Bit7   OBJ-to-BG Priority (0=OBJ Above BG, 1=OBJ Behind BG color 1-3)
-                 (Used for both BG and Window. BG color 0 is always behind OBJ)
-        Bit6   Y flip          (0=Normal, 1=Vertically mirrored)
-        Bit5   X flip          (0=Normal, 1=Horizontally mirrored)
-        Bit4   Palette number  **Non CGB Mode Only** (0=OBP0, 1=OBP1)
-        """
-        self.object_behind_background   = bool(data  & (1 << 7))
-        self.x_flipped                  = bool(data  & (1 << 6))
-        self.y_flipped                  = bool(data  & (1 << 5))
-        self.palette_number             = bool(data  & (1 << 3)) 
-        
-    def get_attributes_and_flags(self):
-        value = 0
-        value += int(self.object_behind_background) << 7
-        value += int(self.x_flipped)                << 6
-        value += int(self.y_flipped)                << 5
-        value += int(self.palette_number )          << 3
-        return value
-        
-    def hide_check(self):
-        if self.y <= 0  or self.y >= GAMEBOY_SCREEN_WIDTH:
-            self.hidden = True
-        elif self.x <= 0  or self.x >= GAMEBOY_SCREEN_WIDTH+SPRITE_SIZE:
-            self.hidden = True
-        else:
-            self.hidden = False
-        
-    def get_tile_number(self):
-        return self.tile.id
-    
-    def get_width(self):
-        return SPRITE_SIZE
-    
-    def get_height(self):
-        if self.big_size:
-            return 2*SPRITE_SIZE
-        else:
-            return SPRITE_SIZE
-         
-    def overlaps_on_line(self, sprite, line):
-        return False
-    
-    def intersects_line(self, line):
-        return line >= self.y and line <= self.y + self.get_height()
-    
-    def draw(self):
-        pass
-    
-    def draw_overlapped(self):
-        pass
-    
-# -----------------------------------------------------------------------------
-    
-    
-class Tile(object):
-    
-    def __init__(self):
-        self.reset()
-        
-    def reset(self):
-        pass
-    
-    def set_tile_data(self, data):
-        pass
-
-    def get_pixel_data(self):
-        return self.pixel_data
-    
-    def get_selected_tile_map_space(self):
-        pass
-# -----------------------------------------------------------------------------
-
-class Window(object):
-    
-    def __init__(self, video):
-        self.video = video
-        self.reset()
-
-    def reset(self):
-        self.x       = 0
-        self.y       = 0
-        self.line_y  = 0
-        self.enabled = False
-        self.upper_tile_map_selected  = False
-        
-    def update_line_y(self, data):
-         # don't draw window if it was not enabled and not being drawn before
-        if not self.enabled and (data & 0x20) != 0 and \
-        self.line_y == 0 and self.video.line_y > self.y:
-            self.line_y = GAMEBOY_SCREEN_HEIGHT    
-    
-    def get_tile_map_space(self):
-        #if (self.control.read() & mask) != 0:
-        if self.upper_tile_map_selected:
-            return constants.VRAM_MAP_B
-        else:
-            return constants.VRAM_MAP_A
-        
-    def draw_line(self, line_y):
-        if line_y  < self.y or self.x >= 167 or \
-           self.line_y >= GAMEBOY_SCREEN_HEIGHT:
-                return
-        else:
-            tile_map, tile_data = self.prepare_window_data()
-            self.video.draw_tiles(self.x + 1, tile_map, tile_data)
-            self.line_y += 1
-
-    def prepare_window_data(self):
-        tile_map   = self.get_tile_map_space()
-        tile_map  += (self.line_y >> 3) << 5
-        tile_data  = self.video.control.get_selected_tile_data_space()
-        tile_data += (self.line_y & 7) << 1
-        return tile_map, tile_data;
-        
-# -----------------------------------------------------------------------------
 
-class Background(object):
-    
-    def __init__(self, video):
-        self.video = video
-        self.reset()
-        
-    def reset(self):
-        # SCROLLX and SCROLLY hold the coordinates of background to
-        # be displayed in the left upper corner of the screen.
-        self.scroll_x   = 0
-        self.scroll_y   = 0
-        self.enabled    = True
-        self.upper_tile_map_selected = False
-      
-    def get_tile_map_space(self):
-        #if (self.control.read() & mask) != 0:
-        if self.upper_tile_map_selected:
-            return constants.VRAM_MAP_B
-        else:
-            return constants.VRAM_MAP_A
-          
-    def draw_clean_line(self, line_y):
-        for x in range(8+GAMEBOY_SCREEN_WIDTH+8):
-            self.video.line[x] = 0x00
-    
-    def draw_line(self, line_y):
-        y          = (self.scroll_y + line_y) & 0xFF
-        x          = self.scroll_x            & 0xFF
-        tile_map, tile_data = self.prepare_background_data(x, y)
-        self.video.draw_tiles(8 - (x & 7), tile_map, tile_data)
-        
-    def prepare_background_data(self, x, y):
-        tile_map   = self.get_tile_map_space()
-        tile_map  += ((y >> 3) << 5) + (x >> 3)
-        tile_data  = self.video.control.get_selected_tile_data_space()
-        tile_data += (y & 7) << 1
-        return tile_map, tile_data
-    
-        
 # -----------------------------------------------------------------------------
 
 class Video(iMemory):

Added: pypy/dist/pypy/lang/gameboy/video_mode.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/lang/gameboy/video_mode.py	Sun Sep 28 00:39:24 2008
@@ -0,0 +1,239 @@
+
+from pypy.lang.gameboy import constants
+from pypy.lang.gameboy.constants import SPRITE_SIZE, GAMEBOY_SCREEN_WIDTH, \
+                                        GAMEBOY_SCREEN_HEIGHT
+
+# -----------------------------------------------------------------------------
+class InvalidModeOrderException(Exception):
+    def __init__(self, mode, previous_mode):
+        Exception.__init__(self, \
+                           "Wrong Mode order! No valid transition %i => %i" \
+                           % (previous_mode.id(), mode.id()))
+       
+class HandleSubclassException(Exception): 
+    def __init__(self):
+        Exception.__init__(self, "")
+        
+class Mode(object):
+
+    """
+    The two lower STAT bits show the current status of the LCD controller.
+    """
+
+    def __init__(self, video):
+        self.video = video
+        self.reset()
+        
+    def reset(self):
+        raise Exception("unimplemented method")
+                        
+    def id(self):
+        raise Exception("unimplemented method")
+    
+    def activate(self, previous_mode):
+        raise Exception("unimplemented method")
+    
+    def emulate(self):
+        raise Exception("unimplemented method")
+
+    def emulate_hblank_line_y_compare(self, stat_check=False):
+        if self.video.line_y == self.video.line_y_compare:
+            if not (stat_check and self.video.status.line_y_compare_flag):
+                self.line_y_line_y_compare_interrupt_check()
+        else:
+            self.video.status.line_y_compare_flag = False
+            
+    def line_y_line_y_compare_interrupt_check(self):
+        self.video.status.line_y_compare_flag = True
+        if self.video.status.line_y_compare_interrupt:
+            self.video.lcd_interrupt_flag.set_pending()
+
+class Mode0(Mode):
+    """
+     Mode 0: The LCD controller is in the H-Blank period and
+          the CPU can access both the display RAM (8000h-9FFFh)
+          and OAM (FE00h-FE9Fh)
+    """
+    
+    def reset(self):
+        self.h_blank_interrupt = False
+    
+    def id(self):
+        return 0
+    
+    def activate(self, previous_mode):
+        #if previous_mode.id() == 3:
+            self.video.cycles += constants.MODE_0_TICKS
+            self.h_blank_interrupt_check()
+        #else:
+            # video.reset_control() can be called in any position
+         #   pass
+            #raise InvalidModeOrderException(self, previous_mode)
+    
+    def h_blank_interrupt_check(self):
+        if self.h_blank_interrupt and \
+        self.video.status.line_y_compare_check():
+            self.video.lcd_interrupt_flag.set_pending()
+            
+    def emulate(self):
+        #self.video.emulate_hblank()
+        self.emulate_hblank()
+        
+    def emulate_hblank(self):
+        self.video.line_y += 1
+        self.emulate_hblank_line_y_compare()
+        if self.video.line_y < GAMEBOY_SCREEN_HEIGHT:
+            self.video.status.set_mode(2)
+        else:
+            self.emulate_hblank_part_2()
+            
+    def emulate_hblank_part_2(self):
+        if self.video.display:
+            self.video.draw_frame()
+        self.video.frames += 1
+        if self.video.frames >= self.video.frame_skip:
+            self.video.display = True
+            self.video.frames = 0
+        else:
+            self.video.display = False
+        self.video.status.set_mode(1)
+        self.video.v_blank  = True
+                 
+class Mode1(Mode):
+    """
+    Mode 1: The LCD contoller is in the V-Blank period (or the
+          display is disabled) and the CPU can access both the
+          display RAM (8000h-9FFFh) and OAM (FE00h-FE9Fh)
+    """
+    
+    def reset(self):
+        self.v_blank_interrupt = False
+        
+    def id(self):
+        return 1
+    
+    def activate(self, previous_mode):
+        #if previous_mode.id() == 0:
+            self.set_begin()
+        #else:
+        #    pass
+            #raise InvalidModeOrderException(self, previous_mode)
+
+    def set_begin(self):
+        self.video.cycles += constants.MODE_1_BEGIN_TICKS
+    
+    def set_between(self):
+        self.video.cycles += constants.MODE_1_TICKS - constants.MODE_1_BEGIN_TICKS
+        
+    def set_end(self):
+        self.video.cycles += constants.MODE_1_END_TICKS
+    
+    def emulate(self):
+        self.emulate_v_blank()
+   
+    def emulate_v_blank(self):
+        if self.video.v_blank:
+            self.emulate_v_blank_v_blank()
+        elif self.video.line_y == 0:
+            self.video.status.set_mode(2)
+        else:
+            self.emulate_v_blank_other()
+ 
+    def emulate_v_blank_v_blank(self):
+        self.video.v_blank  = False
+        self.set_between()
+        self.v_blank_interrupt_check()
+                  
+    def v_blank_interrupt_check(self):
+        if self.v_blank_interrupt:
+            self.video.lcd_interrupt_flag.set_pending()
+        self.video.v_blank_interrupt_flag.set_pending()
+        
+    def emulate_v_blank_other(self):
+        if self.video.line_y < 153:
+            self.emulate_v_blank_mode_1()
+        else:
+            self.video.line_y        = 0
+            self.video.window.line_y = 0
+            self.set_between()
+        self.emulate_hblank_line_y_compare() 
+                
+    def emulate_v_blank_mode_1(self):
+        self.video.line_y += 1
+        if self.video.line_y != 153:
+            self.video.cycles += constants.MODE_1_TICKS
+        else:
+            self.set_end()
+            
+class Mode2(Mode):
+    """
+    Mode 2: The LCD controller is reading from OAM memory.
+          The CPU <cannot> access OAM memory (FE00h-FE9Fh)
+          during this period.
+    """
+    
+    def reset(self):
+        self.oam_interrupt = False
+        
+    def id(self):
+        return 2
+    
+    def activate(self, previous_mode):
+        #if previous_mode.id() == 0 or previous_mode.id() == 1:
+            self.video.cycles += constants.MODE_2_TICKS
+            self.oam_interrupt_check()
+        #else:
+        #    pass
+            #raise InvalidModeOrderException(self, previous_mode)
+     
+    def oam_interrupt_check(self):
+        if self.oam_interrupt and \
+        self.video.status.line_y_compare_check():
+            self.video.lcd_interrupt_flag.set_pending()
+            
+    def emulate(self):
+        self.emulate_oam()
+        
+    def emulate_oam(self):
+        self.video.status.set_mode(3)
+
+class Mode3(Mode):
+    """
+       Mode 3: The LCD controller is reading from both OAM and VRAM,
+          The CPU <cannot> access OAM and VRAM during this period.
+          CGB Mode: Cannot access Palette Data (FF69,FF6B) either.
+    """
+    
+    def reset(self):
+        pass
+    
+    def id(self):
+        return 3
+    
+    def activate(self, previous_mode):
+        #if previous_mode.id() == 2:
+            self.set_begin()
+        #else:
+        #    pass
+        #    #raise InvalidModeOrderException(self, previous_mode)
+    
+    def set_begin(self):
+        self.video.cycles  += constants.MODE_3_BEGIN_TICKS
+        self.video.transfer = True
+        
+    def set_end(self):
+        self.video.cycles  += constants.MODE_3_END_TICKS
+        self.video.transfer = False
+        
+    def emulate(self):
+        self.emulate_transfer()
+        
+    def emulate_transfer(self):
+        if self.video.transfer:
+            if self.video.display:
+                self.video.draw_line()
+                #print "mode 3 ", self.video.status.get_mode() 
+            self.set_end()
+        else:
+            self.video.status.set_mode(0)
+        
\ No newline at end of file

Added: pypy/dist/pypy/lang/gameboy/video_register.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/lang/gameboy/video_register.py	Sun Sep 28 00:39:24 2008
@@ -0,0 +1,134 @@
+
+from pypy.lang.gameboy import constants
+from pypy.lang.gameboy.video_mode import Mode0, Mode1, Mode2, Mode3
+# -----------------------------------------------------------------------------
+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, video):
+        self.create_modes(video)
+        self.reset()
+        
+    def create_modes(self, video):
+        self.mode0 = Mode0(video)
+        self.mode1 = Mode1(video)
+        self.mode2 = Mode2(video)
+        self.mode3 = Mode3(video)
+        self.modes   = [self.mode0, self.mode1, self.mode2, self.mode3]
+        
+        
+        
+    def reset(self):
+        self.current_mode               = self.mode2
+        self.line_y_compare_flag      = False
+        self.line_y_compare_interrupt = False
+        for mode in self.modes:
+            mode.reset()
+        #self.mode_0_h_blank_interrupt = False
+        #self.mode_1_v_blank_interrupt = False
+        #self.mode_2_oam_interrupt     = False
+        self.status                   = True
+        
+        
+    def read(self, extend=False):
+        value =  self.get_mode()
+        value += self.line_y_compare_flag      << 2
+        value += self.mode0.h_blank_interrupt  << 3
+        value += self.mode1.v_blank_interrupt  << 4
+        value += self.mode2.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.current_mode          = self.modes[value & 0x03]
+            self.line_y_compare_flag   = bool(value & (1 << 2))
+            self.status                = bool(value & (1 << 7))
+        self.mode0.h_blank_interrupt   = bool(value & (1 << 3))
+        self.mode1.v_blank_interrupt   = bool(value & (1 << 4))
+        self.mode2.oam_interrupt       = bool(value & (1 << 5))
+        self.line_y_compare_interrupt  = bool(value & (1 << 6))
+        
+    def get_mode(self):
+        return self.current_mode.id()
+    
+    def set_mode(self, mode):
+        old_mode = self.current_mode
+        self.current_mode = self.modes[mode & 0x03]
+        self.current_mode.activate(old_mode)
+        
+    def line_y_compare_check(self):
+        return not self.line_y_compare_flag or not self.line_y_compare_interrupt
+
+# -----------------------------------------------------------------------------
+
+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)
+    Bit 5 - Window Display Enable          (0=Off, 1=On)
+    Bit 4 - BG & Window Tile Data Select   (0=8800-97FF, 1=8000-8FFF)
+    Bit 3 - BG Tile Map Display Select     (0=9800-9BFF, 1=9C00-9FFF)
+    Bit 2 - OBJ (Sprite) Size              (0=8x8, 1=8x16)
+    Bit 1 - OBJ (Sprite) Display Enable    (0=Off, 1=On)
+    Bit 0 - BG Display (for CGB see below) (0=Off, 1=On)
+    """
+    def __init__(self, window, background):
+        self.window     = window
+        self.background = background
+        self.reset()
+        
+    def reset(self):
+        self.lcd_enabled                              = True
+        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.sprites_enabled                          = False
+        self.background.enabled                       = True
+        
+    def read(self):
+        value = 0
+        value += int(self.lcd_enabled)                        << 7 
+        value += int(self.window.upper_tile_map_selected)     << 6 
+        value += int(self.window.enabled)                     << 5
+        value += int(self.background_and_window_lower_tile_data_selected)  << 4
+        value += int(self.background.upper_tile_map_selected) << 3
+        value += int(self.big_sprite_size_selected)           << 2
+        value += int(self.sprites_enabled)                    << 1
+        value += int(self.background.enabled)                 << 0
+        return value
+        
+    def write(self, value):
+        self.lcd_enabled                             = bool(value & (1 << 7))
+        self.window.upper_tile_map_selected          = bool(value & (1 << 6))
+        self.window.enabled                          = bool(value & (1 << 5))
+        self.background_and_window_lower_tile_data_selected = \
+                                                       bool(value & (1 << 4))
+        self.background.upper_tile_map_selected      = bool(value & (1 << 3))
+        self.big_sprite_size_selected                = bool(value & (1 << 2))
+        self.sprites_enabled                         = bool(value & (1 << 1))
+        self.background.enabled                      = bool(value & (1 << 0))
+    
+    
+    def get_selected_tile_data_space(self):
+        if self.window.upper_tile_map_selected:
+            return constants.VRAM_DATA_A
+        else:
+            return  constants.VRAM_DATA_B

Added: pypy/dist/pypy/lang/gameboy/video_sprite.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/lang/gameboy/video_sprite.py	Sun Sep 28 00:39:24 2008
@@ -0,0 +1,231 @@
+
+from pypy.lang.gameboy import constants
+from pypy.lang.gameboy.constants import SPRITE_SIZE, GAMEBOY_SCREEN_WIDTH, \
+                                        GAMEBOY_SCREEN_HEIGHT
+
+# -----------------------------------------------------------------------------
+
+
+class Sprite(object):
+    
+    def __init__(self, video):
+        self.video = video
+        self.big_size = False
+        self.reset()
+
+    def reset(self):
+        self.x              = 0
+        self.y              = 0
+        self.tile           = None
+        self.object_behind_background = False
+        self.x_flipped      = False
+        self.y_flipped      = False
+        self.palette_number = 0
+        self.hidden         = True
+        
+        
+    def get_data(self):
+        return [self.y, self.x, self.tile_number, self.get_attributes_and_flags()]
+    
+    def set_data(self, byte0=-1, byte1=-1, byte2=-1, byte3=-1):
+        """
+        extracts the sprite data from an oam entry
+        """
+        if byte0 is not -1:
+            self.extract_y_position(byte0)
+        if byte0 is not -1:
+            self.extract_x_position(byte1)
+        if byte0 is not -1:
+            self.extract_tile_number(byte2)
+        if byte0 is not -1:
+            self.extract_attributes_and_flags(byte3)
+        
+    def extract_y_position(self, data):
+        """
+        extracts the  Y Position
+        Specifies the sprites vertical position on the screen (minus 16).
+        An offscreen value (for example, Y=0 or Y>=160) hides the sprite.
+        """
+        self.y = data # - 16
+        self.hide_check()
+    
+    def extract_x_position(self, data):
+        """
+        extracts the  X Position
+        Specifies the sprites horizontal position on the screen (minus 8).
+        An offscreen value (X=0 or X>=168) hides the sprite, but the sprite
+        still affects the priority ordering - a better way to hide a sprite is 
+        to set its Y-coordinate offscreen.
+        """
+        self.x = data # - 8
+        self.hide_check()
+    
+    def extract_tile_number(self, data):
+        """
+        extracts the Tile/Pattern Number
+        Specifies the sprites Tile Number (00-FF). This (unsigned) value selects
+        a tile from memory at 8000h-8FFFh. In CGB Mode this could be either in
+        VRAM Bank 0 or 1, depending on Bit 3 of the following byte.
+        In 8x16 mode, the lower bit of the tile number is ignored. Ie. the 
+        upper 8x8 tile is "NN AND FEh", and the lower 8x8 tile is "NN OR 01h".
+        """
+        self.tile_number = data
+    
+    def extract_attributes_and_flags(self, data):
+        """
+        extracts the Attributes/Flags:
+        Bit7   OBJ-to-BG Priority (0=OBJ Above BG, 1=OBJ Behind BG color 1-3)
+                 (Used for both BG and Window. BG color 0 is always behind OBJ)
+        Bit6   Y flip          (0=Normal, 1=Vertically mirrored)
+        Bit5   X flip          (0=Normal, 1=Horizontally mirrored)
+        Bit4   Palette number  **Non CGB Mode Only** (0=OBP0, 1=OBP1)
+        """
+        self.object_behind_background   = bool(data  & (1 << 7))
+        self.x_flipped                  = bool(data  & (1 << 6))
+        self.y_flipped                  = bool(data  & (1 << 5))
+        self.palette_number             = bool(data  & (1 << 3)) 
+        
+    def get_attributes_and_flags(self):
+        value = 0
+        value += int(self.object_behind_background) << 7
+        value += int(self.x_flipped)                << 6
+        value += int(self.y_flipped)                << 5
+        value += int(self.palette_number )          << 3
+        return value
+        
+    def hide_check(self):
+        if self.y <= 0  or self.y >= GAMEBOY_SCREEN_WIDTH:
+            self.hidden = True
+        elif self.x <= 0  or self.x >= GAMEBOY_SCREEN_WIDTH+SPRITE_SIZE:
+            self.hidden = True
+        else:
+            self.hidden = False
+        
+    def get_tile_number(self):
+        return self.tile.id
+    
+    def get_width(self):
+        return SPRITE_SIZE
+    
+    def get_height(self):
+        if self.big_size:
+            return 2*SPRITE_SIZE
+        else:
+            return SPRITE_SIZE
+         
+    def overlaps_on_line(self, sprite, line):
+        return False
+    
+    def intersects_line(self, line):
+        return line >= self.y and line <= self.y + self.get_height()
+    
+    def draw(self):
+        pass
+    
+    def draw_overlapped(self):
+        pass
+    
+# -----------------------------------------------------------------------------
+    
+    
+class Tile(object):
+    
+    def __init__(self):
+        self.reset()
+        
+    def reset(self):
+        pass
+    
+    def set_tile_data(self, data):
+        pass
+
+    def get_pixel_data(self):
+        return self.pixel_data
+    
+    def get_selected_tile_map_space(self):
+        pass
+# -----------------------------------------------------------------------------
+
+class Window(object):
+    
+    def __init__(self, video):
+        self.video = video
+        self.reset()
+
+    def reset(self):
+        self.x       = 0
+        self.y       = 0
+        self.line_y  = 0
+        self.enabled = False
+        self.upper_tile_map_selected  = False
+        
+    def update_line_y(self, data):
+         # don't draw window if it was not enabled and not being drawn before
+        if not self.enabled and (data & 0x20) != 0 and \
+        self.line_y == 0 and self.video.line_y > self.y:
+            self.line_y = GAMEBOY_SCREEN_HEIGHT    
+    
+    def get_tile_map_space(self):
+        #if (self.control.read() & mask) != 0:
+        if self.upper_tile_map_selected:
+            return constants.VRAM_MAP_B
+        else:
+            return constants.VRAM_MAP_A
+        
+    def draw_line(self, line_y):
+        if line_y  < self.y or self.x >= 167 or \
+           self.line_y >= GAMEBOY_SCREEN_HEIGHT:
+                return
+        else:
+            tile_map, tile_data = self.prepare_window_data()
+            self.video.draw_tiles(self.x + 1, tile_map, tile_data)
+            self.line_y += 1
+
+    def prepare_window_data(self):
+        tile_map   = self.get_tile_map_space()
+        tile_map  += (self.line_y >> 3) << 5
+        tile_data  = self.video.control.get_selected_tile_data_space()
+        tile_data += (self.line_y & 7) << 1
+        return tile_map, tile_data;
+        
+# -----------------------------------------------------------------------------
+
+class Background(object):
+    
+    def __init__(self, video):
+        self.video = video
+        self.reset()
+        
+    def reset(self):
+        # SCROLLX and SCROLLY hold the coordinates of background to
+        # be displayed in the left upper corner of the screen.
+        self.scroll_x   = 0
+        self.scroll_y   = 0
+        self.enabled    = True
+        self.upper_tile_map_selected = False
+      
+    def get_tile_map_space(self):
+        #if (self.control.read() & mask) != 0:
+        if self.upper_tile_map_selected:
+            return constants.VRAM_MAP_B
+        else:
+            return constants.VRAM_MAP_A
+          
+    def draw_clean_line(self, line_y):
+        for x in range(8+GAMEBOY_SCREEN_WIDTH+8):
+            self.video.line[x] = 0x00
+    
+    def draw_line(self, line_y):
+        y          = (self.scroll_y + line_y) & 0xFF
+        x          = self.scroll_x            & 0xFF
+        tile_map, tile_data = self.prepare_background_data(x, y)
+        self.video.draw_tiles(8 - (x & 7), tile_map, tile_data)
+        
+    def prepare_background_data(self, x, y):
+        tile_map   = self.get_tile_map_space()
+        tile_map  += ((y >> 3) << 5) + (x >> 3)
+        tile_data  = self.video.control.get_selected_tile_data_space()
+        tile_data += (y & 7) << 1
+        return tile_map, tile_data
+    
+      
\ No newline at end of file



More information about the Pypy-commit mailing list