2 * $Id: pvr2mem.c,v 1.4 2007-01-22 11:45:37 nkeynes Exp $
4 * PVR2 (Video) VRAM handling routines (mainly for the 64-bit region)
6 * Copyright (c) 2005 Nathan Keynes.
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.
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.
22 extern char *video_base;
24 void pvr2_vram64_write( sh4addr_t destaddr, char *src, uint32_t length )
26 int bank_flag = (destaddr & 0x04) >> 2;
31 destaddr = destaddr & 0x7FFFFF;
32 if( destaddr + length > 0x800000 ) {
33 length = 0x800000 - destaddr;
36 for( i=destaddr & 0xFFFFF000; i < destaddr + length; i+= PAGE_SIZE ) {
37 texcache_invalidate_page( i );
40 banks[0] = ((uint32_t *)(video_base + ((destaddr & 0x007FFFF8) >>1)));
41 banks[1] = banks[0] + 0x100000;
45 /* Handle non-aligned start of source */
46 if( destaddr & 0x03 ) {
47 char *dest = ((char *)banks[bank_flag]) + (destaddr & 0x03);
48 for( i= destaddr & 0x03; i < 4 && length > 0; i++, length-- ) {
51 bank_flag = !bank_flag;
54 dwsrc = (uint32_t *)src;
55 while( length >= 4 ) {
56 *banks[bank_flag]++ = *dwsrc++;
57 bank_flag = !bank_flag;
61 /* Handle non-aligned end of source */
64 char *dest = (char *)banks[bank_flag];
65 while( length-- > 0 ) {
72 * Write an image to 64-bit vram, with a line-stride different from the line-size.
73 * The destaddr must be 32-bit aligned, and both line_bytes and line_stride_bytes
74 * must be multiples of 4.
76 void pvr2_vram64_write_stride( sh4addr_t destaddr, char *src, uint32_t line_bytes,
77 uint32_t line_stride_bytes, uint32_t line_count )
79 int bank_flag = (destaddr & 0x04) >> 2;
86 destaddr = destaddr & 0x7FFFF8;
87 i = line_stride_bytes - line_bytes;
88 line_gap_flag = i & 0x04;
92 for( i=destaddr & 0xFFFFF000; i < destaddr + line_stride_bytes*line_count; i+= PAGE_SIZE ) {
93 texcache_invalidate_page( i );
96 banks[0] = (uint32_t *)(video_base + (destaddr >>1));
97 banks[1] = banks[0] + 0x100000;
101 dwsrc = (uint32_t *)src;
102 for( i=0; i<line_count; i++ ) {
103 for( j=0; j<line_bytes; j++ ) {
104 *banks[bank_flag]++ = *dwsrc++;
105 bank_flag = !bank_flag;
107 banks[0] += line_gap;
108 banks[1] += line_gap;
109 if( line_gap_flag ) {
111 bank_flag = !bank_flag;
117 * Read an image from 64-bit vram, with a destination line-stride different from the line-size.
118 * The srcaddr must be 32-bit aligned, and both line_bytes and line_stride_bytes
119 * must be multiples of 4. line_stride_bytes must be >= line_bytes.
120 * This method is used to extract a "stride" texture from vram.
122 void pvr2_vram64_read_stride( char *dest, uint32_t dest_line_bytes, sh4addr_t srcaddr,
123 uint32_t src_line_bytes, uint32_t line_count )
125 int bank_flag = (srcaddr & 0x04) >> 2;
128 uint32_t dest_line_gap;
129 uint32_t src_line_gap;
131 int src_line_gap_flag;
134 srcaddr = srcaddr & 0x7FFFF8;
135 if( src_line_bytes <= dest_line_bytes ) {
136 dest_line_gap = (dest_line_bytes - src_line_bytes) >> 2;
138 src_line_gap_flag = 0;
139 line_bytes = src_line_bytes >> 2;
141 i = (src_line_bytes - dest_line_bytes);
142 src_line_gap_flag = i & 0x04;
143 src_line_gap = i >> 3;
144 line_bytes = dest_line_bytes >> 2;
147 banks[0] = (uint32_t *)(video_base + (srcaddr>>1));
148 banks[1] = banks[0] + 0x100000;
152 dwdest = (uint32_t *)dest;
153 for( i=0; i<line_count; i++ ) {
154 for( j=0; j<line_bytes; j++ ) {
155 *dwdest++ = *banks[bank_flag]++;
156 bank_flag = !bank_flag;
158 dwdest += dest_line_gap;
159 banks[0] += src_line_gap;
160 banks[1] += src_line_gap;
161 if( src_line_gap_flag ) {
163 bank_flag = !bank_flag;
169 * @param dest Destination image buffer
170 * @param banks Source data expressed as two bank pointers
171 * @param offset Offset into banks[0] specifying where the next byte
173 * @param x1,y1 Destination coordinates
174 * @param width Width of current destination block
175 * @param image_width Total width of image (ie stride)
178 static void pvr2_vram64_detwiddle_8( uint8_t *dest, uint8_t *banks[2], int offset,
179 int x1, int y1, int width, int image_width )
182 dest[y1*image_width + x1] = *banks[0]++;
183 dest[(y1+1)*image_width + x1] = *banks[offset<3?0:1]++;
184 dest[y1*image_width + x1 + 1] = *banks[offset<2?0:1]++;
185 dest[(y1+1)*image_width + x1 + 1] = *banks[offset==0?0:1]++;
186 uint8_t *tmp = banks[0]; /* swap banks */
190 int subdivide = width >> 1;
191 pvr2_vram64_detwiddle_8( dest, banks, offset, x1, y1, subdivide, image_width );
192 pvr2_vram64_detwiddle_8( dest, banks, offset, x1, y1+subdivide, subdivide, image_width );
193 pvr2_vram64_detwiddle_8( dest, banks, offset, x1+subdivide, y1, subdivide, image_width );
194 pvr2_vram64_detwiddle_8( dest, banks, offset, x1+subdivide, y1+subdivide, subdivide, image_width );
199 * @param dest Destination image buffer
200 * @param banks Source data expressed as two bank pointers
201 * @param offset Offset into banks[0] specifying where the next word
202 * to read is (0 or 1)
203 * @param x1,y1 Destination coordinates
204 * @param width Width of current destination block
205 * @param image_width Total width of image (ie stride)
208 static void pvr2_vram64_detwiddle_16( uint16_t *dest, uint16_t *banks[2], int offset,
209 int x1, int y1, int width, int image_width )
212 dest[y1*image_width + x1] = *banks[0]++;
213 dest[(y1+1)*image_width + x1] = *banks[offset]++;
214 dest[y1*image_width + x1 + 1] = *banks[1]++;
215 dest[(y1+1)*image_width + x1 + 1] = *banks[offset^1]++;
217 int subdivide = width >> 1;
218 pvr2_vram64_detwiddle_16( dest, banks, offset, x1, y1, subdivide, image_width );
219 pvr2_vram64_detwiddle_16( dest, banks, offset, x1, y1+subdivide, subdivide, image_width );
220 pvr2_vram64_detwiddle_16( dest, banks, offset, x1+subdivide, y1, subdivide, image_width );
221 pvr2_vram64_detwiddle_16( dest, banks, offset, x1+subdivide, y1+subdivide, subdivide, image_width );
226 * Read an image from 64-bit vram stored as twiddled 8-bit pixels. The
227 * image is written out to the destination in detwiddled form.
228 * @param dest destination buffer, which must be at least width*height in length
229 * @param srcaddr source address in vram
230 * @param width image width (must be a power of 2)
231 * @param height image height (must be a power of 2)
233 void pvr2_vram64_read_twiddled_8( char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height )
235 int offset_flag = (srcaddr & 0x07);
237 uint8_t *wdest = (uint8_t*)dest;
240 srcaddr = srcaddr & 0x7FFFF8;
242 banks[0] = (uint8_t *)(video_base + (srcaddr>>1));
243 banks[1] = banks[0] + 0x400000;
244 if( offset_flag & 0x04 ) { // If source is not 64-bit aligned, swap the banks
245 uint8_t *tmp = banks[0];
250 banks[0] += offset_flag;
252 if( width > height ) {
253 for( i=0; i<width; i+=height ) {
254 pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, i, 0, height, width );
256 } else if( height > width ) {
257 for( i=0; i<height; i+=width ) {
258 pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, 0, i, width, width );
260 } else if( width == 1 ) {
263 pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, 0, 0, width, width );
268 * Read an image from 64-bit vram stored as twiddled 16-bit pixels. The
269 * image is written out to the destination in detwiddled form.
270 * @param dest destination buffer, which must be at least width*height*2 in length
271 * @param srcaddr source address in vram (must be 16-bit aligned)
272 * @param width image width (must be a power of 2)
273 * @param height image height (must be a power of 2)
275 void pvr2_vram64_read_twiddled_16( char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height ) {
276 int offset_flag = (srcaddr & 0x06) >> 1;
278 uint16_t *wdest = (uint16_t*)dest;
281 srcaddr = srcaddr & 0x7FFFF8;
283 banks[0] = (uint16_t *)(video_base + (srcaddr>>1));
284 banks[1] = banks[0] + 0x200000;
285 if( offset_flag & 0x02 ) { // If source is not 64-bit aligned, swap the banks
286 uint16_t *tmp = banks[0];
291 banks[0] += offset_flag;
294 if( width > height ) {
295 for( i=0; i<width; i+=height ) {
296 pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, i, 0, height, width );
298 } else if( height > width ) {
299 for( i=0; i<height; i+=width ) {
300 pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, 0, i, width, width );
302 } else if( width == 1 ) {
305 pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, 0, 0, width, width );
309 void pvr2_vram_write_invert( sh4addr_t destaddr, char *src, uint32_t length, uint32_t line_length )
311 char *dest = video_base + (destaddr & 0x007FFFFF);
312 char *p = src + length - line_length;
314 memcpy( dest, p, line_length );
320 void pvr2_vram64_read( char *dest, sh4addr_t srcaddr, uint32_t length )
322 int bank_flag = (srcaddr & 0x04) >> 2;
327 srcaddr = srcaddr & 0x7FFFFF;
328 if( srcaddr + length > 0x800000 )
329 length = 0x800000 - srcaddr;
331 banks[0] = ((uint32_t *)(video_base + ((srcaddr&0x007FFFF8)>>1)));
332 banks[1] = banks[0] + 0x100000;
336 /* Handle non-aligned start of source */
337 if( srcaddr & 0x03 ) {
338 char *src = ((char *)banks[bank_flag]) + (srcaddr & 0x03);
339 for( i= srcaddr & 0x03; i < 4 && length > 0; i++, length-- ) {
342 bank_flag = !bank_flag;
345 dwdest = (uint32_t *)dest;
346 while( length >= 4 ) {
347 *dwdest++ = *banks[bank_flag]++;
348 bank_flag = !bank_flag;
352 /* Handle non-aligned end of source */
354 dest = (char *)dwdest;
355 char *src = (char *)banks[bank_flag];
356 while( length-- > 0 ) {
362 void pvr2_vram64_dump_file( sh4addr_t addr, uint32_t length, gchar *filename )
364 uint32_t tmp[length>>2];
365 FILE *f = fopen(filename, "wo");
369 ERROR( "Unable to write to dump file '%s' (%s)", filename, strerror(errno) );
372 pvr2_vram64_read( tmp, addr, length );
373 fprintf( f, "%08X\n", addr );
374 for( i =0; i<length>>2; i+=8 ) {
375 for( j=i; j<i+8; j++ ) {
377 fprintf( f, " %08X", tmp[j] );
386 void pvr2_vram64_dump( sh4addr_t addr, uint32_t length, FILE *f )
389 pvr2_vram64_read( tmp, addr, length );
390 fwrite_dump( tmp, length, f );
.