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