Search
lxdream.org :: lxdream/src/pvr2/pvr2mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/pvr2mem.c
changeset 645:a7392098299c
prev561:533f6b478071
next669:ab344e42bca9
author nkeynes
date Fri Mar 28 12:32:25 2008 +0000 (11 years ago)
permissions -rw-r--r--
last change Merge lxdream-render branch (643:670) to trunk
file annotate diff log raw
nkeynes@284
     1
/**
nkeynes@561
     2
 * $Id$
nkeynes@284
     3
 *
nkeynes@284
     4
 * PVR2 (Video) VRAM handling routines (mainly for the 64-bit region)
nkeynes@284
     5
 *
nkeynes@284
     6
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@284
     7
 *
nkeynes@284
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@284
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@284
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@284
    11
 * (at your option) any later version.
nkeynes@284
    12
 *
nkeynes@284
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@284
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@284
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@284
    16
 * GNU General Public License for more details.
nkeynes@284
    17
 */
nkeynes@645
    18
#include <string.h>
nkeynes@645
    19
#include <stdio.h>
nkeynes@645
    20
#include <errno.h>
nkeynes@284
    21
#include "pvr2.h"
nkeynes@325
    22
#include "asic.h"
nkeynes@284
    23
nkeynes@429
    24
extern unsigned char *video_base;
nkeynes@284
    25
nkeynes@429
    26
void pvr2_dma_write( sh4addr_t destaddr, unsigned char *src, uint32_t count )
nkeynes@325
    27
{
nkeynes@325
    28
    int region;
nkeynes@325
    29
nkeynes@325
    30
    switch( destaddr & 0x13800000 ) {
nkeynes@325
    31
    case 0x10000000:
nkeynes@325
    32
    case 0x12000000:
nkeynes@325
    33
	pvr2_ta_write( src, count );
nkeynes@325
    34
	break;
nkeynes@325
    35
    case 0x11000000:
nkeynes@325
    36
    case 0x11800000:
nkeynes@325
    37
	region = MMIO_READ( ASIC, PVRDMARGN1 );
nkeynes@325
    38
	if( region == 0 ) {
nkeynes@325
    39
	    pvr2_vram64_write( destaddr, src, count );
nkeynes@325
    40
	} else {
nkeynes@502
    41
	    unsigned char *dest = mem_get_region(destaddr);
nkeynes@325
    42
	    memcpy( dest, src, count );
nkeynes@325
    43
	}
nkeynes@325
    44
	break;
nkeynes@325
    45
    case 0x10800000:
nkeynes@325
    46
    case 0x12800000:
nkeynes@325
    47
	pvr2_yuv_write( src, count );
nkeynes@325
    48
	break;
nkeynes@325
    49
    case 0x13000000:
nkeynes@325
    50
    case 0x13800000:
nkeynes@325
    51
	region = MMIO_READ( ASIC, PVRDMARGN2 );
nkeynes@325
    52
	if( region == 0 ) {
nkeynes@325
    53
	    pvr2_vram64_write( destaddr, src, count );
nkeynes@325
    54
	} else {
nkeynes@502
    55
	    unsigned char *dest = mem_get_region(destaddr);
nkeynes@325
    56
	    memcpy( dest, src, count );
nkeynes@325
    57
	}
nkeynes@325
    58
    }	    
nkeynes@325
    59
}
nkeynes@325
    60
nkeynes@429
    61
void pvr2_vram64_write( sh4addr_t destaddr, unsigned char *src, uint32_t length )
nkeynes@284
    62
{
nkeynes@284
    63
    int bank_flag = (destaddr & 0x04) >> 2;
nkeynes@284
    64
    uint32_t *banks[2];
nkeynes@284
    65
    uint32_t *dwsrc;
nkeynes@284
    66
    int i;
nkeynes@284
    67
nkeynes@284
    68
    destaddr = destaddr & 0x7FFFFF;
nkeynes@284
    69
    if( destaddr + length > 0x800000 ) {
nkeynes@284
    70
	length = 0x800000 - destaddr;
nkeynes@284
    71
    }
nkeynes@284
    72
nkeynes@284
    73
    for( i=destaddr & 0xFFFFF000; i < destaddr + length; i+= PAGE_SIZE ) {
nkeynes@284
    74
	texcache_invalidate_page( i );
nkeynes@284
    75
    }
nkeynes@284
    76
nkeynes@284
    77
    banks[0] = ((uint32_t *)(video_base + ((destaddr & 0x007FFFF8) >>1)));
nkeynes@284
    78
    banks[1] = banks[0] + 0x100000;
nkeynes@284
    79
    if( bank_flag ) 
nkeynes@284
    80
	banks[0]++;
nkeynes@284
    81
    
nkeynes@284
    82
    /* Handle non-aligned start of source */
nkeynes@284
    83
    if( destaddr & 0x03 ) {
nkeynes@429
    84
	unsigned char *dest = ((unsigned char *)banks[bank_flag]) + (destaddr & 0x03);
nkeynes@284
    85
	for( i= destaddr & 0x03; i < 4 && length > 0; i++, length-- ) {
nkeynes@284
    86
	    *dest++ = *src++;
nkeynes@284
    87
	}
nkeynes@284
    88
	bank_flag = !bank_flag;
nkeynes@284
    89
    }
nkeynes@284
    90
nkeynes@284
    91
    dwsrc = (uint32_t *)src;
nkeynes@284
    92
    while( length >= 4 ) {
nkeynes@284
    93
	*banks[bank_flag]++ = *dwsrc++;
nkeynes@284
    94
	bank_flag = !bank_flag;
nkeynes@284
    95
	length -= 4;
nkeynes@284
    96
    }
nkeynes@284
    97
    
nkeynes@284
    98
    /* Handle non-aligned end of source */
nkeynes@284
    99
    if( length ) {
nkeynes@429
   100
	src = (unsigned char *)dwsrc;
nkeynes@429
   101
	unsigned char *dest = (unsigned char *)banks[bank_flag];
nkeynes@284
   102
	while( length-- > 0 ) {
nkeynes@284
   103
	    *dest++ = *src++;
nkeynes@284
   104
	}
nkeynes@284
   105
    }  
nkeynes@284
   106
}
nkeynes@284
   107
nkeynes@284
   108
/**
nkeynes@284
   109
 * Write an image to 64-bit vram, with a line-stride different from the line-size.
nkeynes@284
   110
 * The destaddr must be 32-bit aligned, and both line_bytes and line_stride_bytes
nkeynes@284
   111
 * must be multiples of 4.
nkeynes@284
   112
 */
nkeynes@429
   113
void pvr2_vram64_write_stride( sh4addr_t destaddr, unsigned char *src, uint32_t line_bytes, 
nkeynes@284
   114
			       uint32_t line_stride_bytes, uint32_t line_count )
nkeynes@284
   115
{
nkeynes@284
   116
    int bank_flag = (destaddr & 0x04) >> 2;
nkeynes@284
   117
    uint32_t *banks[2];
nkeynes@284
   118
    uint32_t *dwsrc;
nkeynes@284
   119
    uint32_t line_gap;
nkeynes@284
   120
    int line_gap_flag;
nkeynes@284
   121
    int i,j;
nkeynes@284
   122
nkeynes@284
   123
    destaddr = destaddr & 0x7FFFF8;
nkeynes@284
   124
    i = line_stride_bytes - line_bytes;
nkeynes@284
   125
    line_gap_flag = i & 0x04;
nkeynes@284
   126
    line_gap = i >> 3;
nkeynes@284
   127
    line_bytes >>= 2;
nkeynes@284
   128
nkeynes@284
   129
    for( i=destaddr & 0xFFFFF000; i < destaddr + line_stride_bytes*line_count; i+= PAGE_SIZE ) {
nkeynes@284
   130
	texcache_invalidate_page( i );
nkeynes@284
   131
    }
nkeynes@284
   132
nkeynes@284
   133
    banks[0] = (uint32_t *)(video_base + (destaddr >>1));
nkeynes@284
   134
    banks[1] = banks[0] + 0x100000;
nkeynes@284
   135
    if( bank_flag ) 
nkeynes@284
   136
	banks[0]++;
nkeynes@284
   137
    
nkeynes@284
   138
    dwsrc = (uint32_t *)src;
nkeynes@284
   139
    for( i=0; i<line_count; i++ ) {
nkeynes@284
   140
	for( j=0; j<line_bytes; j++ ) {
nkeynes@284
   141
	    *banks[bank_flag]++ = *dwsrc++;
nkeynes@284
   142
	    bank_flag = !bank_flag;
nkeynes@284
   143
	}
nkeynes@285
   144
	banks[0] += line_gap;
nkeynes@285
   145
	banks[1] += line_gap;
nkeynes@284
   146
	if( line_gap_flag ) {
nkeynes@285
   147
	    banks[bank_flag]++;
nkeynes@284
   148
	    bank_flag = !bank_flag;
nkeynes@284
   149
	}
nkeynes@284
   150
    }    
nkeynes@284
   151
}
nkeynes@284
   152
nkeynes@284
   153
/**
nkeynes@284
   154
 * Read an image from 64-bit vram, with a destination line-stride different from the line-size.
nkeynes@284
   155
 * The srcaddr must be 32-bit aligned, and both line_bytes and line_stride_bytes
nkeynes@284
   156
 * must be multiples of 4. line_stride_bytes must be >= line_bytes.
nkeynes@284
   157
 * This method is used to extract a "stride" texture from vram.
nkeynes@284
   158
 */
nkeynes@429
   159
void pvr2_vram64_read_stride( unsigned char *dest, uint32_t dest_line_bytes, sh4addr_t srcaddr,
nkeynes@284
   160
				   uint32_t src_line_bytes, uint32_t line_count )
nkeynes@284
   161
{
nkeynes@284
   162
    int bank_flag = (srcaddr & 0x04) >> 2;
nkeynes@284
   163
    uint32_t *banks[2];
nkeynes@284
   164
    uint32_t *dwdest;
nkeynes@429
   165
    uint32_t dest_line_gap = 0;
nkeynes@429
   166
    uint32_t src_line_gap = 0;
nkeynes@284
   167
    uint32_t line_bytes;
nkeynes@284
   168
    int src_line_gap_flag;
nkeynes@284
   169
    int i,j;
nkeynes@284
   170
nkeynes@284
   171
    srcaddr = srcaddr & 0x7FFFF8;
nkeynes@284
   172
    if( src_line_bytes <= dest_line_bytes ) {
nkeynes@284
   173
	dest_line_gap = (dest_line_bytes - src_line_bytes) >> 2;
nkeynes@284
   174
	src_line_gap = 0;
nkeynes@284
   175
	src_line_gap_flag = 0;
nkeynes@284
   176
	line_bytes = src_line_bytes >> 2;
nkeynes@284
   177
    } else {
nkeynes@284
   178
	i = (src_line_bytes - dest_line_bytes);
nkeynes@284
   179
	src_line_gap_flag = i & 0x04;
nkeynes@284
   180
	src_line_gap = i >> 3;
nkeynes@284
   181
	line_bytes = dest_line_bytes >> 2;
nkeynes@284
   182
    }
nkeynes@284
   183
	
nkeynes@284
   184
    banks[0] = (uint32_t *)(video_base + (srcaddr>>1));
nkeynes@284
   185
    banks[1] = banks[0] + 0x100000;
nkeynes@284
   186
    if( bank_flag )
nkeynes@284
   187
	banks[0]++;
nkeynes@284
   188
    
nkeynes@284
   189
    dwdest = (uint32_t *)dest;
nkeynes@284
   190
    for( i=0; i<line_count; i++ ) {
nkeynes@284
   191
	for( j=0; j<line_bytes; j++ ) {
nkeynes@284
   192
	    *dwdest++ = *banks[bank_flag]++;
nkeynes@284
   193
	    bank_flag = !bank_flag;
nkeynes@284
   194
	}
nkeynes@284
   195
	dwdest += dest_line_gap;
nkeynes@284
   196
	banks[0] += src_line_gap;
nkeynes@284
   197
	banks[1] += src_line_gap;
nkeynes@284
   198
	if( src_line_gap_flag ) {
nkeynes@284
   199
	    banks[bank_flag]++;
nkeynes@284
   200
	    bank_flag = !bank_flag;
nkeynes@284
   201
	}
nkeynes@310
   202
    }    
nkeynes@310
   203
}
nkeynes@310
   204
nkeynes@315
   205
nkeynes@310
   206
/**
nkeynes@310
   207
 * @param dest Destination image buffer
nkeynes@310
   208
 * @param banks Source data expressed as two bank pointers
nkeynes@310
   209
 * @param offset Offset into banks[0] specifying where the next byte
nkeynes@310
   210
 *  to read is (0..3)
nkeynes@310
   211
 * @param x1,y1 Destination coordinates
nkeynes@310
   212
 * @param width Width of current destination block
nkeynes@315
   213
 * @param stride Total width of image (ie stride) in bytes
nkeynes@315
   214
 */
nkeynes@315
   215
nkeynes@315
   216
static void pvr2_vram64_detwiddle_4( uint8_t *dest, uint8_t *banks[2], int offset,
nkeynes@315
   217
				     int x1, int y1, int width, int stride )
nkeynes@315
   218
{
nkeynes@315
   219
    if( width == 2 ) {
nkeynes@315
   220
	x1 = x1 >> 1;
nkeynes@315
   221
	uint8_t t1 = *banks[offset<4?0:1]++;
nkeynes@315
   222
	uint8_t t2 = *banks[offset<3?0:1]++;
nkeynes@315
   223
	dest[y1*stride + x1] = (t1 & 0x0F) | (t2<<4);
nkeynes@315
   224
	dest[(y1+1)*stride + x1] = (t1>>4) | (t2&0xF0);
nkeynes@315
   225
    } else if( width == 4 ) {
nkeynes@315
   226
	pvr2_vram64_detwiddle_4( dest, banks, offset, x1, y1, 2, stride );
nkeynes@315
   227
	pvr2_vram64_detwiddle_4( dest, banks, offset+2, x1, y1+2, 2, stride );
nkeynes@315
   228
	pvr2_vram64_detwiddle_4( dest, banks, offset+4, x1+2, y1, 2, stride );
nkeynes@315
   229
	pvr2_vram64_detwiddle_4( dest, banks, offset+6, x1+2, y1+2, 2, stride );
nkeynes@315
   230
	
nkeynes@315
   231
    } else {
nkeynes@315
   232
	int subdivide = width >> 1;
nkeynes@315
   233
	pvr2_vram64_detwiddle_4( dest, banks, offset, x1, y1, subdivide, stride );
nkeynes@315
   234
	pvr2_vram64_detwiddle_4( dest, banks, offset, x1, y1+subdivide, subdivide, stride );
nkeynes@315
   235
	pvr2_vram64_detwiddle_4( dest, banks, offset, x1+subdivide, y1, subdivide, stride );
nkeynes@315
   236
	pvr2_vram64_detwiddle_4( dest, banks, offset, x1+subdivide, y1+subdivide, subdivide, stride );
nkeynes@315
   237
    }
nkeynes@315
   238
}
nkeynes@315
   239
nkeynes@315
   240
/**
nkeynes@315
   241
 * @param dest Destination image buffer
nkeynes@315
   242
 * @param banks Source data expressed as two bank pointers
nkeynes@315
   243
 * @param offset Offset into banks[0] specifying where the next byte
nkeynes@315
   244
 *  to read is (0..3)
nkeynes@315
   245
 * @param x1,y1 Destination coordinates
nkeynes@315
   246
 * @param width Width of current destination block
nkeynes@315
   247
 * @param stride Total width of image (ie stride)
nkeynes@310
   248
 */
nkeynes@310
   249
nkeynes@310
   250
static void pvr2_vram64_detwiddle_8( uint8_t *dest, uint8_t *banks[2], int offset,
nkeynes@315
   251
				     int x1, int y1, int width, int stride )
nkeynes@310
   252
{
nkeynes@310
   253
    if( width == 2 ) {
nkeynes@315
   254
	dest[y1*stride + x1] = *banks[0]++;
nkeynes@315
   255
	dest[(y1+1)*stride + x1] = *banks[offset<3?0:1]++;
nkeynes@315
   256
	dest[y1*stride + x1 + 1] = *banks[offset<2?0:1]++;
nkeynes@315
   257
	dest[(y1+1)*stride + x1 + 1] = *banks[offset==0?0:1]++;
nkeynes@310
   258
	uint8_t *tmp = banks[0]; /* swap banks */
nkeynes@310
   259
	banks[0] = banks[1];
nkeynes@310
   260
	banks[1] = tmp;
nkeynes@310
   261
    } else {
nkeynes@310
   262
	int subdivide = width >> 1;
nkeynes@315
   263
	pvr2_vram64_detwiddle_8( dest, banks, offset, x1, y1, subdivide, stride );
nkeynes@315
   264
	pvr2_vram64_detwiddle_8( dest, banks, offset, x1, y1+subdivide, subdivide, stride );
nkeynes@315
   265
	pvr2_vram64_detwiddle_8( dest, banks, offset, x1+subdivide, y1, subdivide, stride );
nkeynes@315
   266
	pvr2_vram64_detwiddle_8( dest, banks, offset, x1+subdivide, y1+subdivide, subdivide, stride );
nkeynes@284
   267
    }
nkeynes@310
   268
}
nkeynes@310
   269
nkeynes@310
   270
/**
nkeynes@310
   271
 * @param dest Destination image buffer
nkeynes@310
   272
 * @param banks Source data expressed as two bank pointers
nkeynes@310
   273
 * @param offset Offset into banks[0] specifying where the next word
nkeynes@310
   274
 *  to read is (0 or 1)
nkeynes@310
   275
 * @param x1,y1 Destination coordinates
nkeynes@310
   276
 * @param width Width of current destination block
nkeynes@315
   277
 * @param stride Total width of image (ie stride)
nkeynes@310
   278
 */
nkeynes@310
   279
nkeynes@310
   280
static void pvr2_vram64_detwiddle_16( uint16_t *dest, uint16_t *banks[2], int offset,
nkeynes@315
   281
				      int x1, int y1, int width, int stride )
nkeynes@310
   282
{
nkeynes@310
   283
    if( width == 2 ) {
nkeynes@315
   284
	dest[y1*stride + x1] = *banks[0]++;
nkeynes@315
   285
	dest[(y1+1)*stride + x1] = *banks[offset]++;
nkeynes@315
   286
	dest[y1*stride + x1 + 1] = *banks[1]++;
nkeynes@315
   287
	dest[(y1+1)*stride + x1 + 1] = *banks[offset^1]++;
nkeynes@310
   288
    } else {
nkeynes@310
   289
	int subdivide = width >> 1;
nkeynes@315
   290
	pvr2_vram64_detwiddle_16( dest, banks, offset, x1, y1, subdivide, stride );
nkeynes@315
   291
	pvr2_vram64_detwiddle_16( dest, banks, offset, x1, y1+subdivide, subdivide, stride );
nkeynes@315
   292
	pvr2_vram64_detwiddle_16( dest, banks, offset, x1+subdivide, y1, subdivide, stride );
nkeynes@315
   293
	pvr2_vram64_detwiddle_16( dest, banks, offset, x1+subdivide, y1+subdivide, subdivide, stride );
nkeynes@310
   294
    }
nkeynes@310
   295
}
nkeynes@310
   296
nkeynes@310
   297
/**
nkeynes@315
   298
 * Read an image from 64-bit vram stored as twiddled 4-bit pixels. The 
nkeynes@315
   299
 * image is written out to the destination in detwiddled form.
nkeynes@315
   300
 * @param dest destination buffer, which must be at least width*height/2 in length
nkeynes@315
   301
 * @param srcaddr source address in vram
nkeynes@315
   302
 * @param width image width (must be a power of 2)
nkeynes@315
   303
 * @param height image height (must be a power of 2)
nkeynes@315
   304
 */
nkeynes@429
   305
void pvr2_vram64_read_twiddled_4( unsigned char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height )
nkeynes@315
   306
{
nkeynes@315
   307
    int offset_flag = (srcaddr & 0x07);
nkeynes@315
   308
    uint8_t *banks[2];
nkeynes@315
   309
    uint8_t *wdest = (uint8_t*)dest;
nkeynes@315
   310
    uint32_t stride = width >> 1;
nkeynes@429
   311
    int i;
nkeynes@315
   312
nkeynes@315
   313
    srcaddr = srcaddr & 0x7FFFF8;
nkeynes@315
   314
nkeynes@315
   315
    banks[0] = (uint8_t *)(video_base + (srcaddr>>1));
nkeynes@315
   316
    banks[1] = banks[0] + 0x400000;
nkeynes@315
   317
    if( offset_flag & 0x04 ) { // If source is not 64-bit aligned, swap the banks
nkeynes@315
   318
	uint8_t *tmp = banks[0];
nkeynes@315
   319
	banks[0] = banks[1];
nkeynes@315
   320
	banks[1] = tmp + 4;
nkeynes@315
   321
	offset_flag &= 0x03;
nkeynes@315
   322
    }
nkeynes@315
   323
    banks[0] += offset_flag;
nkeynes@315
   324
nkeynes@315
   325
    if( width > height ) {
nkeynes@315
   326
	for( i=0; i<width; i+=height ) {
nkeynes@315
   327
	    pvr2_vram64_detwiddle_4( wdest, banks, offset_flag, i, 0, height, stride );
nkeynes@315
   328
	}
nkeynes@315
   329
    } else if( height > width ) {
nkeynes@315
   330
	for( i=0; i<height; i+=width ) {
nkeynes@315
   331
	    pvr2_vram64_detwiddle_4( wdest, banks, offset_flag, 0, i, width, stride );
nkeynes@315
   332
	}
nkeynes@315
   333
    } else if( width == 1 ) {
nkeynes@315
   334
	*wdest = *banks[0];
nkeynes@315
   335
    } else {
nkeynes@315
   336
	pvr2_vram64_detwiddle_4( wdest, banks, offset_flag, 0, 0, width, stride );
nkeynes@315
   337
    }   
nkeynes@315
   338
}
nkeynes@315
   339
nkeynes@315
   340
/**
nkeynes@310
   341
 * Read an image from 64-bit vram stored as twiddled 8-bit pixels. The 
nkeynes@310
   342
 * image is written out to the destination in detwiddled form.
nkeynes@310
   343
 * @param dest destination buffer, which must be at least width*height in length
nkeynes@310
   344
 * @param srcaddr source address in vram
nkeynes@310
   345
 * @param width image width (must be a power of 2)
nkeynes@310
   346
 * @param height image height (must be a power of 2)
nkeynes@310
   347
 */
nkeynes@429
   348
void pvr2_vram64_read_twiddled_8( unsigned char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height )
nkeynes@310
   349
{
nkeynes@310
   350
    int offset_flag = (srcaddr & 0x07);
nkeynes@310
   351
    uint8_t *banks[2];
nkeynes@310
   352
    uint8_t *wdest = (uint8_t*)dest;
nkeynes@429
   353
    int i;
nkeynes@310
   354
nkeynes@310
   355
    srcaddr = srcaddr & 0x7FFFF8;
nkeynes@310
   356
nkeynes@310
   357
    banks[0] = (uint8_t *)(video_base + (srcaddr>>1));
nkeynes@310
   358
    banks[1] = banks[0] + 0x400000;
nkeynes@310
   359
    if( offset_flag & 0x04 ) { // If source is not 64-bit aligned, swap the banks
nkeynes@310
   360
	uint8_t *tmp = banks[0];
nkeynes@310
   361
	banks[0] = banks[1];
nkeynes@310
   362
	banks[1] = tmp + 4;
nkeynes@310
   363
	offset_flag &= 0x03;
nkeynes@310
   364
    }
nkeynes@310
   365
    banks[0] += offset_flag;
nkeynes@310
   366
nkeynes@310
   367
    if( width > height ) {
nkeynes@310
   368
	for( i=0; i<width; i+=height ) {
nkeynes@310
   369
	    pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, i, 0, height, width );
nkeynes@310
   370
	}
nkeynes@310
   371
    } else if( height > width ) {
nkeynes@310
   372
	for( i=0; i<height; i+=width ) {
nkeynes@310
   373
	    pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, 0, i, width, width );
nkeynes@310
   374
	}
nkeynes@310
   375
    } else if( width == 1 ) {
nkeynes@310
   376
	*wdest = *banks[0];
nkeynes@310
   377
    } else {
nkeynes@310
   378
	pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, 0, 0, width, width );
nkeynes@310
   379
    }   
nkeynes@310
   380
}
nkeynes@310
   381
nkeynes@310
   382
/**
nkeynes@310
   383
 * Read an image from 64-bit vram stored as twiddled 16-bit pixels. The 
nkeynes@310
   384
 * image is written out to the destination in detwiddled form.
nkeynes@310
   385
 * @param dest destination buffer, which must be at least width*height*2 in length
nkeynes@310
   386
 * @param srcaddr source address in vram (must be 16-bit aligned)
nkeynes@310
   387
 * @param width image width (must be a power of 2)
nkeynes@310
   388
 * @param height image height (must be a power of 2)
nkeynes@310
   389
 */
nkeynes@429
   390
void pvr2_vram64_read_twiddled_16( unsigned char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height ) {
nkeynes@310
   391
    int offset_flag = (srcaddr & 0x06) >> 1;
nkeynes@310
   392
    uint16_t *banks[2];
nkeynes@310
   393
    uint16_t *wdest = (uint16_t*)dest;
nkeynes@429
   394
    int i;
nkeynes@310
   395
nkeynes@310
   396
    srcaddr = srcaddr & 0x7FFFF8;
nkeynes@310
   397
nkeynes@310
   398
    banks[0] = (uint16_t *)(video_base + (srcaddr>>1));
nkeynes@310
   399
    banks[1] = banks[0] + 0x200000;
nkeynes@310
   400
    if( offset_flag & 0x02 ) { // If source is not 64-bit aligned, swap the banks
nkeynes@310
   401
	uint16_t *tmp = banks[0];
nkeynes@310
   402
	banks[0] = banks[1];
nkeynes@310
   403
	banks[1] = tmp + 2;
nkeynes@310
   404
	offset_flag &= 0x01;
nkeynes@310
   405
    }
nkeynes@310
   406
    banks[0] += offset_flag;
nkeynes@310
   407
	
nkeynes@310
   408
nkeynes@310
   409
    if( width > height ) {
nkeynes@310
   410
	for( i=0; i<width; i+=height ) {
nkeynes@310
   411
	    pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, i, 0, height, width );
nkeynes@310
   412
	}
nkeynes@310
   413
    } else if( height > width ) {
nkeynes@310
   414
	for( i=0; i<height; i+=width ) {
nkeynes@310
   415
	    pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, 0, i, width, width );
nkeynes@310
   416
	}
nkeynes@310
   417
    } else if( width == 1 ) {
nkeynes@310
   418
	*wdest = *banks[0];
nkeynes@310
   419
    } else {
nkeynes@310
   420
	pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, 0, 0, width, width );
nkeynes@310
   421
    }    
nkeynes@284
   422
}
nkeynes@284
   423
nkeynes@429
   424
void pvr2_vram_write_invert( sh4addr_t destaddr, unsigned char *src, uint32_t length, uint32_t line_length,
nkeynes@333
   425
			     uint32_t src_stride )
nkeynes@284
   426
{
nkeynes@429
   427
    unsigned char *dest = video_base + (destaddr & 0x007FFFFF);
nkeynes@429
   428
    unsigned char *p = src + length - src_stride;
nkeynes@284
   429
    while( p >= src ) {
nkeynes@284
   430
	memcpy( dest, p, line_length );
nkeynes@333
   431
	p -= src_stride;
nkeynes@284
   432
	dest += line_length;
nkeynes@284
   433
    }
nkeynes@284
   434
}
nkeynes@284
   435
nkeynes@429
   436
void pvr2_vram64_read( unsigned char *dest, sh4addr_t srcaddr, uint32_t length )
nkeynes@284
   437
{
nkeynes@284
   438
    int bank_flag = (srcaddr & 0x04) >> 2;
nkeynes@284
   439
    uint32_t *banks[2];
nkeynes@284
   440
    uint32_t *dwdest;
nkeynes@284
   441
    int i;
nkeynes@284
   442
nkeynes@284
   443
    srcaddr = srcaddr & 0x7FFFFF;
nkeynes@284
   444
    if( srcaddr + length > 0x800000 )
nkeynes@284
   445
	length = 0x800000 - srcaddr;
nkeynes@284
   446
nkeynes@284
   447
    banks[0] = ((uint32_t *)(video_base + ((srcaddr&0x007FFFF8)>>1)));
nkeynes@284
   448
    banks[1] = banks[0] + 0x100000;
nkeynes@284
   449
    if( bank_flag )
nkeynes@284
   450
	banks[0]++;
nkeynes@284
   451
    
nkeynes@284
   452
    /* Handle non-aligned start of source */
nkeynes@284
   453
    if( srcaddr & 0x03 ) {
nkeynes@284
   454
	char *src = ((char *)banks[bank_flag]) + (srcaddr & 0x03);
nkeynes@284
   455
	for( i= srcaddr & 0x03; i < 4 && length > 0; i++, length-- ) {
nkeynes@284
   456
	    *dest++ = *src++;
nkeynes@284
   457
	}
nkeynes@284
   458
	bank_flag = !bank_flag;
nkeynes@284
   459
    }
nkeynes@284
   460
nkeynes@284
   461
    dwdest = (uint32_t *)dest;
nkeynes@284
   462
    while( length >= 4 ) {
nkeynes@284
   463
	*dwdest++ = *banks[bank_flag]++;
nkeynes@284
   464
	bank_flag = !bank_flag;
nkeynes@284
   465
	length -= 4;
nkeynes@284
   466
    }
nkeynes@284
   467
    
nkeynes@284
   468
    /* Handle non-aligned end of source */
nkeynes@284
   469
    if( length ) {
nkeynes@429
   470
	dest = (unsigned char *)dwdest;
nkeynes@429
   471
	unsigned char *src = (unsigned char *)banks[bank_flag];
nkeynes@284
   472
	while( length-- > 0 ) {
nkeynes@284
   473
	    *dest++ = *src++;
nkeynes@284
   474
	}
nkeynes@284
   475
    }
nkeynes@284
   476
}
nkeynes@284
   477
nkeynes@309
   478
void pvr2_vram64_dump_file( sh4addr_t addr, uint32_t length, gchar *filename )
nkeynes@309
   479
{
nkeynes@309
   480
    uint32_t tmp[length>>2];
nkeynes@309
   481
    FILE *f = fopen(filename, "wo");
nkeynes@309
   482
    unsigned int i, j;
nkeynes@309
   483
nkeynes@309
   484
    if( f == NULL ) {
nkeynes@309
   485
	ERROR( "Unable to write to dump file '%s' (%s)", filename, strerror(errno) );
nkeynes@309
   486
	return;
nkeynes@309
   487
    }
nkeynes@429
   488
    pvr2_vram64_read( (unsigned char *)tmp, addr, length );
nkeynes@309
   489
    fprintf( f, "%08X\n", addr );
nkeynes@309
   490
    for( i =0; i<length>>2; i+=8 ) {
nkeynes@309
   491
	for( j=i; j<i+8; j++ ) {
nkeynes@309
   492
	    if( j < length )
nkeynes@309
   493
		fprintf( f, " %08X", tmp[j] );
nkeynes@309
   494
	    else
nkeynes@309
   495
		fprintf( f, "         " );
nkeynes@309
   496
	}
nkeynes@309
   497
	fprintf( f, "\n" );
nkeynes@309
   498
    }
nkeynes@309
   499
    fclose(f);
nkeynes@309
   500
}
nkeynes@309
   501
nkeynes@284
   502
void pvr2_vram64_dump( sh4addr_t addr, uint32_t length, FILE *f ) 
nkeynes@284
   503
{
nkeynes@429
   504
    unsigned char tmp[length];
nkeynes@284
   505
    pvr2_vram64_read( tmp, addr, length );
nkeynes@284
   506
    fwrite_dump( tmp, length, f );
nkeynes@284
   507
}
nkeynes@315
   508
nkeynes@315
   509
nkeynes@315
   510
nkeynes@315
   511
/**
nkeynes@315
   512
 * Flush the indicated render buffer back to PVR. Caller is responsible for
nkeynes@315
   513
 * tracking whether there is actually anything in the buffer.
nkeynes@315
   514
 *
nkeynes@315
   515
 * @param buffer A render buffer indicating the address to store to, and the
nkeynes@315
   516
 * format the data needs to be in.
nkeynes@315
   517
 * @param backBuffer TRUE to flush the back buffer, FALSE for 
nkeynes@315
   518
 * the front buffer.
nkeynes@315
   519
 */
nkeynes@352
   520
void pvr2_render_buffer_copy_to_sh4( render_buffer_t buffer )
nkeynes@315
   521
{
nkeynes@429
   522
    if( (buffer->address & 0xFF000000) == 0x04000000 ) {
nkeynes@315
   523
	/* Interlaced buffer. Go the double copy... :( */
nkeynes@429
   524
	unsigned char target[buffer->size];
nkeynes@477
   525
	display_driver->read_render_buffer( target, buffer, buffer->rowstride, buffer->colour_format );
nkeynes@352
   526
	pvr2_vram64_write( buffer->address, target, buffer->size );
nkeynes@315
   527
    } else {
nkeynes@315
   528
	/* Regular buffer */
nkeynes@429
   529
        unsigned char target[buffer->size];
nkeynes@352
   530
	int line_size = buffer->width * colour_formats[buffer->colour_format].bpp;
nkeynes@477
   531
	display_driver->read_render_buffer( target, buffer, buffer->rowstride, buffer->colour_format );
nkeynes@352
   532
        if( (buffer->scale & 0xFFFF) == 0x0800 ) {
nkeynes@352
   533
            pvr2_vram_write_invert( buffer->address, target, buffer->size, line_size, line_size << 1 );
nkeynes@352
   534
        } else {
nkeynes@352
   535
            pvr2_vram_write_invert( buffer->address, target, buffer->size, line_size, line_size );
nkeynes@352
   536
        }
nkeynes@315
   537
    }
nkeynes@315
   538
}
nkeynes@315
   539
.