[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