Search
lxdream.org :: lxdream/src/pvr2/pvr2.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/pvr2.c
changeset 265:5daf59b7f31b
prev261:93fdb2a70e18
next269:e41f9b1490d1
author nkeynes
date Sat Jan 06 04:06:36 2007 +0000 (17 years ago)
permissions -rw-r--r--
last change Implement event queue.
Fix pvr2 timing (yes, again).
view annotate diff log raw
     1 /**
     2  * $Id: pvr2.c,v 1.35 2007-01-06 04:06:36 nkeynes Exp $
     3  *
     4  * PVR2 (Video) Core module implementation and MMIO registers.
     5  *
     6  * Copyright (c) 2005 Nathan Keynes.
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16  * GNU General Public License for more details.
    17  */
    18 #define MODULE pvr2_module
    20 #include "dream.h"
    21 #include "eventq.h"
    22 #include "display.h"
    23 #include "mem.h"
    24 #include "asic.h"
    25 #include "clock.h"
    26 #include "pvr2/pvr2.h"
    27 #include "sh4/sh4core.h"
    28 #define MMIO_IMPL
    29 #include "pvr2/pvr2mmio.h"
    31 char *video_base;
    33 static void pvr2_init( void );
    34 static void pvr2_reset( void );
    35 static uint32_t pvr2_run_slice( uint32_t );
    36 static void pvr2_save_state( FILE *f );
    37 static int pvr2_load_state( FILE *f );
    38 static void pvr2_update_raster_posn( uint32_t nanosecs );
    39 static void pvr2_schedule_line_event( int eventid, int line );
    40 static void pvr2_schedule_scanline_event( int eventid, int line );
    41 uint32_t pvr2_get_sync_status();
    43 void pvr2_display_frame( void );
    45 int colour_format_bytes[] = { 2, 2, 2, 1, 3, 4, 1, 1 };
    47 struct dreamcast_module pvr2_module = { "PVR2", pvr2_init, pvr2_reset, NULL, 
    48 					pvr2_run_slice, NULL,
    49 					pvr2_save_state, pvr2_load_state };
    52 display_driver_t display_driver = NULL;
    54 struct video_timing {
    55     int fields_per_second;
    56     int total_lines;
    57     int retrace_lines;
    58     int line_time_ns;
    59 };
    61 struct video_timing pal_timing = { 50, 625, 65, 31945 };
    62 struct video_timing ntsc_timing= { 60, 525, 65, 31746 };
    64 struct pvr2_state {
    65     uint32_t frame_count;
    66     uint32_t line_count;
    67     uint32_t line_remainder;
    68     uint32_t cycles_run; /* Cycles already executed prior to main time slice */
    69     uint32_t irq_vpos1;
    70     uint32_t irq_vpos2;
    71     uint32_t odd_even_field; /* 1 = odd, 0 = even */
    73     /* timing */
    74     uint32_t dot_clock;
    75     uint32_t total_lines;
    76     uint32_t line_size;
    77     uint32_t line_time_ns;
    78     uint32_t vsync_lines;
    79     uint32_t hsync_width_ns;
    80     uint32_t front_porch_ns;
    81     uint32_t back_porch_ns;
    82     uint32_t retrace_start_line;
    83     uint32_t retrace_end_line;
    84     gboolean interlaced;
    85     struct video_timing timing;
    86 } pvr2_state;
    88 struct video_buffer video_buffer[2];
    89 int video_buffer_idx = 0;
    91 /**
    92  * Event handler for the retrace callback (fires on line 0 normally)
    93  */
    94 static void pvr2_retrace_callback( int eventid ) {
    95     asic_event( eventid );
    96     pvr2_update_raster_posn(sh4r.slice_cycle);
    97     pvr2_schedule_line_event( EVENT_RETRACE, 0 );
    98 }
   100 /**
   101  * Event handler for the scanline callbacks. Fires the corresponding
   102  * ASIC event, and resets the timer for the next field.
   103  */
   104 static void pvr2_scanline_callback( int eventid ) {
   105     asic_event( eventid );
   106     pvr2_update_raster_posn(sh4r.slice_cycle);
   107     if( eventid == EVENT_SCANLINE1 ) {
   108 	pvr2_schedule_scanline_event( eventid, pvr2_state.irq_vpos1 );
   109     } else {
   110 	pvr2_schedule_scanline_event( eventid, pvr2_state.irq_vpos2 );
   111     }
   112 }
   114 static void pvr2_init( void )
   115 {
   116     register_io_region( &mmio_region_PVR2 );
   117     register_io_region( &mmio_region_PVR2PAL );
   118     register_io_region( &mmio_region_PVR2TA );
   119     register_event_callback( EVENT_RETRACE, pvr2_retrace_callback );
   120     register_event_callback( EVENT_SCANLINE1, pvr2_scanline_callback );
   121     register_event_callback( EVENT_SCANLINE2, pvr2_scanline_callback );
   122     video_base = mem_get_region_by_name( MEM_REGION_VIDEO );
   123     texcache_init();
   124     pvr2_reset();
   125     pvr2_ta_reset();
   126 }
   128 static void pvr2_reset( void )
   129 {
   130     pvr2_state.line_count = 0;
   131     pvr2_state.line_remainder = 0;
   132     pvr2_state.cycles_run = 0;
   133     pvr2_state.irq_vpos1 = 0;
   134     pvr2_state.irq_vpos2 = 0;
   135     pvr2_state.timing = ntsc_timing;
   136     pvr2_state.dot_clock = PVR2_DOT_CLOCK;
   137     pvr2_state.back_porch_ns = 4000;
   138     mmio_region_PVR2_write( DISP_TOTAL, 0x0270035F );
   139     mmio_region_PVR2_write( DISP_SYNCTIME, 0x07D6A53F );
   140     video_buffer_idx = 0;
   142     pvr2_ta_init();
   143     pvr2_render_init();
   144     texcache_flush();
   145 }
   147 static void pvr2_save_state( FILE *f )
   148 {
   149     fwrite( &pvr2_state, sizeof(pvr2_state), 1, f );
   150     pvr2_ta_save_state( f );
   151 }
   153 static int pvr2_load_state( FILE *f )
   154 {
   155     if( fread( &pvr2_state, sizeof(pvr2_state), 1, f ) != 1 )
   156 	return 1;
   157     return pvr2_ta_load_state(f);
   158 }
   160 /**
   161  * Update the current raster position to the given number of nanoseconds,
   162  * relative to the last time slice. (ie the raster will be adjusted forward
   163  * by nanosecs - nanosecs_already_run_this_timeslice)
   164  */
   165 static void pvr2_update_raster_posn( uint32_t nanosecs )
   166 {
   167     uint32_t old_line_count = pvr2_state.line_count;
   168     if( pvr2_state.line_time_ns == 0 ) {
   169 	return; /* do nothing */
   170     }
   171     pvr2_state.line_remainder += (nanosecs - pvr2_state.cycles_run);
   172     pvr2_state.cycles_run = nanosecs;
   173     while( pvr2_state.line_remainder >= pvr2_state.line_time_ns ) {
   174 	pvr2_state.line_count ++;
   175 	pvr2_state.line_remainder -= pvr2_state.line_time_ns;
   176     }
   178     if( pvr2_state.line_count >= pvr2_state.total_lines ) {
   179 	pvr2_state.line_count -= pvr2_state.total_lines;
   180 	if( pvr2_state.interlaced ) {
   181 	    pvr2_state.odd_even_field = !pvr2_state.odd_even_field;
   182 	}
   183     }
   184     if( pvr2_state.line_count >= pvr2_state.retrace_end_line &&
   185 	(old_line_count < pvr2_state.retrace_end_line ||
   186 	 old_line_count > pvr2_state.line_count) ) {
   187 	pvr2_display_frame();
   188     }
   189 }
   191 static uint32_t pvr2_run_slice( uint32_t nanosecs ) 
   192 {
   193     pvr2_update_raster_posn( nanosecs );
   194     pvr2_state.cycles_run = 0;
   195     return nanosecs;
   196 }
   198 int pvr2_get_frame_count() 
   199 {
   200     return pvr2_state.frame_count;
   201 }
   203 /**
   204  * Display the next frame, copying the current contents of video ram to
   205  * the window. If the video configuration has changed, first recompute the
   206  * new frame size/depth.
   207  */
   208 void pvr2_display_frame( void )
   209 {
   210     uint32_t display_addr = MMIO_READ( PVR2, DISP_ADDR1 );
   212     int dispsize = MMIO_READ( PVR2, DISP_SIZE );
   213     int dispmode = MMIO_READ( PVR2, DISP_MODE );
   214     int vidcfg = MMIO_READ( PVR2, DISP_SYNCCFG );
   215     int vid_stride = ((dispsize & DISPSIZE_MODULO) >> 20) - 1;
   216     int vid_lpf = ((dispsize & DISPSIZE_LPF) >> 10) + 1;
   217     int vid_ppl = ((dispsize & DISPSIZE_PPL)) + 1;
   218     gboolean bEnabled = (dispmode & DISPMODE_DE) && (vidcfg & DISPCFG_VO ) ? TRUE : FALSE;
   219     gboolean interlaced = (vidcfg & DISPCFG_I ? TRUE : FALSE);
   220     video_buffer_t buffer = &video_buffer[video_buffer_idx];
   221     video_buffer_idx = !video_buffer_idx;
   222     video_buffer_t last = &video_buffer[video_buffer_idx];
   223     buffer->rowstride = (vid_ppl + vid_stride) << 2;
   224     buffer->data = video_base + MMIO_READ( PVR2, DISP_ADDR1 );
   225     buffer->vres = vid_lpf;
   226     if( interlaced ) buffer->vres <<= 1;
   227     switch( (dispmode & DISPMODE_COL) >> 2 ) {
   228     case 0: 
   229 	buffer->colour_format = COLFMT_ARGB1555;
   230 	buffer->hres = vid_ppl << 1; 
   231 	break;
   232     case 1: 
   233 	buffer->colour_format = COLFMT_RGB565;
   234 	buffer->hres = vid_ppl << 1; 
   235 	break;
   236     case 2:
   237 	buffer->colour_format = COLFMT_RGB888;
   238 	buffer->hres = (vid_ppl << 2) / 3; 
   239 	break;
   240     case 3: 
   241 	buffer->colour_format = COLFMT_ARGB8888;
   242 	buffer->hres = vid_ppl; 
   243 	break;
   244     }
   246     if( buffer->hres <=8 )
   247 	buffer->hres = 640;
   248     if( buffer->vres <=8 )
   249 	buffer->vres = 480;
   250     if( display_driver != NULL ) {
   251 	if( buffer->hres != last->hres ||
   252 	    buffer->vres != last->vres ||
   253 	    buffer->colour_format != last->colour_format) {
   254 	    display_driver->set_display_format( buffer->hres, buffer->vres,
   255 						buffer->colour_format );
   256 	}
   257 	if( !bEnabled ) {
   258 	    display_driver->display_blank_frame( 0 );
   259 	} else if( MMIO_READ( PVR2, DISP_CFG2 ) & 0x08 ) { /* Blanked */
   260 	    uint32_t colour = MMIO_READ( PVR2, DISP_BORDER );
   261 	    display_driver->display_blank_frame( colour );
   262 	} else if( !pvr2_render_display_frame( PVR2_RAM_BASE + display_addr ) ) {
   263 	    display_driver->display_frame( buffer );
   264 	}
   265     }
   266     pvr2_state.frame_count++;
   267 }
   269 /**
   270  * This has to handle every single register individually as they all get masked 
   271  * off differently (and its easier to do it at write time)
   272  */
   273 void mmio_region_PVR2_write( uint32_t reg, uint32_t val )
   274 {
   275     if( reg >= 0x200 && reg < 0x600 ) { /* Fog table */
   276         MMIO_WRITE( PVR2, reg, val );
   277         return;
   278     }
   280     switch(reg) {
   281     case PVRID:
   282     case PVRVER:
   283     case GUNPOS: /* Read only registers */
   284 	break;
   285     case PVRRESET:
   286 	val &= 0x00000007; /* Do stuff? */
   287 	MMIO_WRITE( PVR2, reg, val );
   288 	break;
   289     case RENDER_START:
   290 	if( val == 0xFFFFFFFF || val == 0x00000001 )
   291 	    pvr2_render_scene();
   292 	break;
   293     case RENDER_POLYBASE:
   294     	MMIO_WRITE( PVR2, reg, val&0x00F00000 );
   295     	break;
   296     case RENDER_TSPCFG:
   297     	MMIO_WRITE( PVR2, reg, val&0x00010101 );
   298     	break;
   299     case DISP_BORDER:
   300     	MMIO_WRITE( PVR2, reg, val&0x01FFFFFF );
   301     	break;
   302     case DISP_MODE:
   303     	MMIO_WRITE( PVR2, reg, val&0x00FFFF7F );
   304     	break;
   305     case RENDER_MODE:
   306     	MMIO_WRITE( PVR2, reg, val&0x00FFFF0F );
   307     	break;
   308     case RENDER_SIZE:
   309     	MMIO_WRITE( PVR2, reg, val&0x000001FF );
   310     	break;
   311     case DISP_ADDR1:
   312 	val &= 0x00FFFFFC;
   313 	MMIO_WRITE( PVR2, reg, val );
   314 	pvr2_update_raster_posn(sh4r.slice_cycle);
   315 	if( pvr2_state.line_count >= pvr2_state.retrace_start_line ||
   316 	    pvr2_state.line_count < pvr2_state.retrace_end_line ) {
   317 	    pvr2_display_frame();
   318 	}
   319 	break;
   320     case DISP_ADDR2:
   321     	MMIO_WRITE( PVR2, reg, val&0x00FFFFFC );
   322     	break;
   323     case DISP_SIZE:
   324     	MMIO_WRITE( PVR2, reg, val&0x3FFFFFFF );
   325     	break;
   326     case RENDER_ADDR1:
   327     case RENDER_ADDR2:
   328     	MMIO_WRITE( PVR2, reg, val&0x01FFFFFC );
   329     	break;
   330     case RENDER_HCLIP:
   331 	MMIO_WRITE( PVR2, reg, val&0x07FF07FF );
   332 	break;
   333     case RENDER_VCLIP:
   334 	MMIO_WRITE( PVR2, reg, val&0x03FF03FF );
   335 	break;
   336     case DISP_HPOSIRQ:
   337 	MMIO_WRITE( PVR2, reg, val&0x03FF33FF );
   338 	break;
   339     case DISP_VPOSIRQ:
   340 	val = val & 0x03FF03FF;
   341 	pvr2_state.irq_vpos1 = (val >> 16);
   342 	pvr2_state.irq_vpos2 = val & 0x03FF;
   343 	pvr2_update_raster_posn(sh4r.slice_cycle);
   344 	pvr2_schedule_scanline_event( EVENT_SCANLINE1, pvr2_state.irq_vpos1 );
   345 	pvr2_schedule_scanline_event( EVENT_SCANLINE2, pvr2_state.irq_vpos2 );
   346 	MMIO_WRITE( PVR2, reg, val );
   347 	break;
   348     case RENDER_NEARCLIP:
   349 	MMIO_WRITE( PVR2, reg, val & 0x7FFFFFFF );
   350 	break;
   351     case RENDER_SHADOW:
   352 	MMIO_WRITE( PVR2, reg, val&0x000001FF );
   353 	break;
   354     case RENDER_OBJCFG:
   355     	MMIO_WRITE( PVR2, reg, val&0x003FFFFF );
   356     	break;
   357     case RENDER_TSPCLIP:
   358     	MMIO_WRITE( PVR2, reg, val&0x7FFFFFFF );
   359     	break;
   360     case RENDER_FARCLIP:
   361 	MMIO_WRITE( PVR2, reg, val&0xFFFFFFF0 );
   362 	break;
   363     case RENDER_BGPLANE:
   364     	MMIO_WRITE( PVR2, reg, val&0x1FFFFFFF );
   365     	break;
   366     case RENDER_ISPCFG:
   367     	MMIO_WRITE( PVR2, reg, val&0x00FFFFF9 );
   368     	break;
   369     case VRAM_CFG1:
   370 	MMIO_WRITE( PVR2, reg, val&0x000000FF );
   371 	break;
   372     case VRAM_CFG2:
   373 	MMIO_WRITE( PVR2, reg, val&0x003FFFFF );
   374 	break;
   375     case VRAM_CFG3:
   376 	MMIO_WRITE( PVR2, reg, val&0x1FFFFFFF );
   377 	break;
   378     case RENDER_FOGTBLCOL:
   379     case RENDER_FOGVRTCOL:
   380 	MMIO_WRITE( PVR2, reg, val&0x00FFFFFF );
   381 	break;
   382     case RENDER_FOGCOEFF:
   383 	MMIO_WRITE( PVR2, reg, val&0x0000FFFF );
   384 	break;
   385     case RENDER_CLAMPHI:
   386     case RENDER_CLAMPLO:
   387 	MMIO_WRITE( PVR2, reg, val );
   388 	break;
   389     case RENDER_TEXSIZE:
   390 	MMIO_WRITE( PVR2, reg, val&0x00031F1F );
   391 	break;
   392     case RENDER_PALETTE:
   393 	MMIO_WRITE( PVR2, reg, val&0x00000003 );
   394 	break;
   396 	/********** CRTC registers *************/
   397     case DISP_HBORDER:
   398     case DISP_VBORDER:
   399 	MMIO_WRITE( PVR2, reg, val&0x03FF03FF );
   400 	break;
   401     case DISP_TOTAL:
   402 	val = val & 0x03FF03FF;
   403 	MMIO_WRITE( PVR2, reg, val );
   404 	pvr2_update_raster_posn(sh4r.slice_cycle);
   405 	pvr2_state.total_lines = (val >> 16) + 1;
   406 	pvr2_state.line_size = (val & 0x03FF) + 1;
   407 	pvr2_state.line_time_ns = 1000000 * pvr2_state.line_size / pvr2_state.dot_clock;
   408 	pvr2_state.retrace_end_line = 0x2A;
   409 	pvr2_state.retrace_start_line = pvr2_state.total_lines - 6;
   410 	pvr2_schedule_line_event( EVENT_RETRACE, 0 );
   411 	pvr2_schedule_scanline_event( EVENT_SCANLINE1, pvr2_state.irq_vpos1 );
   412 	pvr2_schedule_scanline_event( EVENT_SCANLINE2, pvr2_state.irq_vpos2 );
   413 	break;
   414     case DISP_SYNCCFG:
   415 	MMIO_WRITE( PVR2, reg, val&0x000003FF );
   416 	pvr2_state.interlaced = (val & 0x0010) ? TRUE : FALSE;
   417 	break;
   418     case DISP_SYNCTIME:
   419 	pvr2_state.vsync_lines = (val >> 8) & 0x0F;
   420 	pvr2_state.hsync_width_ns = ((val & 0x7F) + 1) * 1000000 / pvr2_state.dot_clock;
   421 	MMIO_WRITE( PVR2, reg, val&0xFFFFFF7F );
   422 	break;
   423     case DISP_CFG2:
   424 	MMIO_WRITE( PVR2, reg, val&0x003F01FF );
   425 	break;
   426     case DISP_HPOS:
   427 	val = val & 0x03FF;
   428 	pvr2_state.front_porch_ns = (val + 1) * 1000000 / pvr2_state.dot_clock;
   429 	MMIO_WRITE( PVR2, reg, val );
   430 	break;
   431     case DISP_VPOS:
   432 	MMIO_WRITE( PVR2, reg, val&0x03FF03FF );
   433 	break;
   435 	/*********** Tile accelerator registers ***********/
   436     case TA_POLYPOS:
   437     case TA_LISTPOS:
   438 	/* Readonly registers */
   439 	break;
   440     case TA_TILEBASE:
   441     case TA_LISTEND:
   442     case TA_LISTBASE:
   443 	MMIO_WRITE( PVR2, reg, val&0x00FFFFE0 );
   444 	break;
   445     case RENDER_TILEBASE:
   446     case TA_POLYBASE:
   447     case TA_POLYEND:
   448 	MMIO_WRITE( PVR2, reg, val&0x00FFFFFC );
   449 	break;
   450     case TA_TILESIZE:
   451 	MMIO_WRITE( PVR2, reg, val&0x000F003F );
   452 	break;
   453     case TA_TILECFG:
   454 	MMIO_WRITE( PVR2, reg, val&0x00133333 );
   455 	break;
   456     case TA_INIT:
   457 	if( val & 0x80000000 )
   458 	    pvr2_ta_init();
   459 	break;
   460     case TA_REINIT:
   461 	break;
   462 	/**************** Scaler registers? ****************/
   463     case SCALERCFG:
   464 	MMIO_WRITE( PVR2, reg, val&0x0007FFFF );
   465 	break;
   467     case YUV_ADDR:
   468 	MMIO_WRITE( PVR2, reg, val&0x00FFFFF8 );
   469 	break;
   470     case YUV_CFG:
   471 	MMIO_WRITE( PVR2, reg, val&0x01013F3F );
   472 	break;
   475 	/**************** Unknowns ***************/
   476     case PVRUNK1:
   477     	MMIO_WRITE( PVR2, reg, val&0x000007FF );
   478     	break;
   479     case PVRUNK2:
   480 	MMIO_WRITE( PVR2, reg, val&0x00000007 );
   481 	break;
   482     case PVRUNK3:
   483 	MMIO_WRITE( PVR2, reg, val&0x000FFF3F );
   484 	break;
   485     case PVRUNK5:
   486 	MMIO_WRITE( PVR2, reg, val&0x0000FFFF );
   487 	break;
   488     case PVRUNK6:
   489 	MMIO_WRITE( PVR2, reg, val&0x000000FF );
   490 	break;
   491     case PVRUNK7:
   492 	MMIO_WRITE( PVR2, reg, val&0x00000001 );
   493 	break;
   494     }
   495 }
   497 /**
   498  * Calculate the current read value of the syncstat register, using
   499  * the current SH4 clock time as an offset from the last timeslice.
   500  * The register reads (LSB to MSB) as:
   501  *     0..9  Current scan line
   502  *     10    Odd/even field (1 = odd, 0 = even)
   503  *     11    Display active (including border and overscan)
   504  *     12    Horizontal sync off
   505  *     13    Vertical sync off
   506  * Note this method is probably incorrect for anything other than straight
   507  * interlaced PAL/NTSC, and needs further testing. 
   508  */
   509 uint32_t pvr2_get_sync_status()
   510 {
   511     pvr2_update_raster_posn(sh4r.slice_cycle);
   512     uint32_t result = pvr2_state.line_count;
   514     if( pvr2_state.odd_even_field ) {
   515 	result |= 0x0400;
   516     }
   517     if( (pvr2_state.line_count & 0x01) == pvr2_state.odd_even_field ) {
   518 	if( pvr2_state.line_remainder > pvr2_state.hsync_width_ns ) {
   519 	    result |= 0x1000; /* !HSYNC */
   520 	}
   521 	if( pvr2_state.line_count >= pvr2_state.vsync_lines ) {
   522 	    if( pvr2_state.line_remainder > pvr2_state.front_porch_ns ) {
   523 		result |= 0x2800; /* Display active */
   524 	    } else {
   525 		result |= 0x2000; /* Front porch */
   526 	    }
   527 	}
   528     } else {
   529 	if( pvr2_state.line_remainder < (pvr2_state.line_time_ns - pvr2_state.back_porch_ns) &&
   530 	    pvr2_state.line_count >= pvr2_state.vsync_lines ) {
   531 	    result |= 0x3800; /* Display active */
   532 	} else {
   533 	    result |= 0x1000; /* Back porch */
   534 	}
   535     }
   537     return result;
   538 }
   540 /**
   541  * Schedule an event for the start of the given line. If the line is actually
   542  * the current line, schedules it for the next field. 
   543  * The raster position should be updated before calling this method.
   544  */
   545 static void pvr2_schedule_line_event( int eventid, int line )
   546 {
   547     uint32_t time;
   548     if( line <= pvr2_state.line_count ) {
   549 	time = (pvr2_state.total_lines - pvr2_state.line_count + line) * pvr2_state.line_time_ns
   550 	    - pvr2_state.line_remainder;
   551     } else {
   552 	time = (line - pvr2_state.line_count) * pvr2_state.line_time_ns - pvr2_state.line_remainder;
   553     }
   555     if( line < pvr2_state.total_lines ) {
   556 	event_schedule( eventid, time );
   557     } else {
   558 	event_cancel( eventid );
   559     }
   560 }
   562 /**
   563  * Schedule a "scanline" event. This actually goes off at
   564  * 2 * line in even fields and 2 * line + 1 in odd fields.
   565  * Otherwise this behaves as per pvr2_schedule_line_event().
   566  * The raster position should be updated before calling this
   567  * method.
   568  */
   569 static void pvr2_schedule_scanline_event( int eventid, int line )
   570 {
   571     uint32_t field = pvr2_state.odd_even_field;
   572     if( line <= pvr2_state.line_count && pvr2_state.interlaced ) {
   573 	field = !field;
   574     }
   576     line <<= 1;
   577     if( field ) {
   578 	line += 1;
   579     }
   580     pvr2_schedule_line_event( eventid, line );
   581 }
   583 MMIO_REGION_READ_FN( PVR2, reg )
   584 {
   585     switch( reg ) {
   586         case DISP_SYNCSTAT:
   587             return pvr2_get_sync_status();
   588         default:
   589             return MMIO_READ( PVR2, reg );
   590     }
   591 }
   593 MMIO_REGION_DEFFNS( PVR2PAL )
   595 void pvr2_set_base_address( uint32_t base ) 
   596 {
   597     mmio_region_PVR2_write( DISP_ADDR1, base );
   598 }
   603 int32_t mmio_region_PVR2TA_read( uint32_t reg )
   604 {
   605     return 0xFFFFFFFF;
   606 }
   608 void mmio_region_PVR2TA_write( uint32_t reg, uint32_t val )
   609 {
   610     pvr2_ta_write( (char *)&val, sizeof(uint32_t) );
   611 }
   614 void pvr2_vram64_write( sh4addr_t destaddr, char *src, uint32_t length )
   615 {
   616     int bank_flag = (destaddr & 0x04) >> 2;
   617     uint32_t *banks[2];
   618     uint32_t *dwsrc;
   619     int i;
   621     destaddr = destaddr & 0x7FFFFF;
   622     if( destaddr + length > 0x800000 ) {
   623 	length = 0x800000 - destaddr;
   624     }
   626     for( i=destaddr & 0xFFFFF000; i < destaddr + length; i+= PAGE_SIZE ) {
   627 	texcache_invalidate_page( i );
   628     }
   630     banks[0] = ((uint32_t *)(video_base + ((destaddr & 0x007FFFF8) >>1)));
   631     banks[1] = banks[0] + 0x100000;
   632     if( bank_flag ) 
   633 	banks[0]++;
   635     /* Handle non-aligned start of source */
   636     if( destaddr & 0x03 ) {
   637 	char *dest = ((char *)banks[bank_flag]) + (destaddr & 0x03);
   638 	for( i= destaddr & 0x03; i < 4 && length > 0; i++, length-- ) {
   639 	    *dest++ = *src++;
   640 	}
   641 	bank_flag = !bank_flag;
   642     }
   644     dwsrc = (uint32_t *)src;
   645     while( length >= 4 ) {
   646 	*banks[bank_flag]++ = *dwsrc++;
   647 	bank_flag = !bank_flag;
   648 	length -= 4;
   649     }
   651     /* Handle non-aligned end of source */
   652     if( length ) {
   653 	src = (char *)dwsrc;
   654 	char *dest = (char *)banks[bank_flag];
   655 	while( length-- > 0 ) {
   656 	    *dest++ = *src++;
   657 	}
   658     }  
   659 }
   661 void pvr2_vram_write_invert( sh4addr_t destaddr, char *src, uint32_t length, uint32_t line_length )
   662 {
   663     char *dest = video_base + (destaddr & 0x007FFFFF);
   664     char *p = src + length - line_length;
   665     while( p >= src ) {
   666 	memcpy( dest, p, line_length );
   667 	p -= line_length;
   668 	dest += line_length;
   669     }
   670 }
   672 void pvr2_vram64_read( char *dest, sh4addr_t srcaddr, uint32_t length )
   673 {
   674     int bank_flag = (srcaddr & 0x04) >> 2;
   675     uint32_t *banks[2];
   676     uint32_t *dwdest;
   677     int i;
   679     srcaddr = srcaddr & 0x7FFFFF;
   680     if( srcaddr + length > 0x800000 )
   681 	length = 0x800000 - srcaddr;
   683     banks[0] = ((uint32_t *)(video_base + ((srcaddr&0x007FFFF8)>>1)));
   684     banks[1] = banks[0] + 0x100000;
   685     if( bank_flag )
   686 	banks[0]++;
   688     /* Handle non-aligned start of source */
   689     if( srcaddr & 0x03 ) {
   690 	char *src = ((char *)banks[bank_flag]) + (srcaddr & 0x03);
   691 	for( i= srcaddr & 0x03; i < 4 && length > 0; i++, length-- ) {
   692 	    *dest++ = *src++;
   693 	}
   694 	bank_flag = !bank_flag;
   695     }
   697     dwdest = (uint32_t *)dest;
   698     while( length >= 4 ) {
   699 	*dwdest++ = *banks[bank_flag]++;
   700 	bank_flag = !bank_flag;
   701 	length -= 4;
   702     }
   704     /* Handle non-aligned end of source */
   705     if( length ) {
   706 	dest = (char *)dwdest;
   707 	char *src = (char *)banks[bank_flag];
   708 	while( length-- > 0 ) {
   709 	    *dest++ = *src++;
   710 	}
   711     }
   712 }
   714 void pvr2_vram64_dump( sh4addr_t addr, uint32_t length, FILE *f ) 
   715 {
   716     char tmp[length];
   717     pvr2_vram64_read( tmp, addr, length );
   718     fwrite_dump( tmp, length, f );
   719 }
.