Search
lxdream.org :: lxdream/src/pvr2/pvr2mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/pvr2mem.c
changeset 929:fd8cb0c82f5f
prev869:b6f38c7ee7a3
next931:430048ea8b71
author nkeynes
date Sat Dec 20 03:01:40 2008 +0000 (12 years ago)
branchlxdream-mem
permissions -rw-r--r--
last change First pass experiment using cached decoding.
view annotate diff log raw
     1 /**
     2  * $Id$
     3  *
     4  * PVR2 (Video) VRAM handling routines (mainly for the 64-bit region)
     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 #include <string.h>
    19 #include <stdio.h>
    20 #include <errno.h>
    21 #include "sh4/sh4core.h"
    22 #include "pvr2.h"
    23 #include "asic.h"
    24 #include "dream.h"
    26 extern unsigned char *video_base;
    28 /************************* VRAM32 address space ***************************/
    30 static int32_t FASTCALL pvr2_vram32_read_long( sh4addr_t addr )
    31 {
    32     pvr2_render_buffer_invalidate(addr, FALSE);
    33     return *((int32_t *)(video_base+(addr&0x007FFFFF)));
    34 }
    35 static int32_t FASTCALL pvr2_vram32_read_word( sh4addr_t addr )
    36 {
    37     pvr2_render_buffer_invalidate(addr, FALSE);
    38     return SIGNEXT16(*((int16_t *)(video_base+(addr&0x007FFFFF))));
    39 }
    40 static int32_t FASTCALL pvr2_vram32_read_byte( sh4addr_t addr )
    41 {
    42     pvr2_render_buffer_invalidate(addr, FALSE);
    43     return SIGNEXT8(*((int8_t *)(video_base+(addr&0x007FFFFF))));
    44 }
    45 static void FASTCALL pvr2_vram32_write_long( sh4addr_t addr, uint32_t val )
    46 {
    47     pvr2_render_buffer_invalidate(addr, TRUE);
    48     *(uint32_t *)(video_base + (addr&0x007FFFFF)) = val;
    49 }
    50 static void FASTCALL pvr2_vram32_write_word( sh4addr_t addr, uint32_t val )
    51 {
    52     pvr2_render_buffer_invalidate(addr, TRUE);
    53     *(uint16_t *)(video_base + (addr&0x007FFFFF)) = (uint16_t)val;
    54 }
    55 static void FASTCALL pvr2_vram32_write_byte( sh4addr_t addr, uint32_t val )
    56 {
    57     pvr2_render_buffer_invalidate(addr, TRUE);
    58     *(uint8_t *)(video_base + (addr&0x007FFFFF)) = (uint8_t)val;
    59 }
    60 static void FASTCALL pvr2_vram32_read_burst( unsigned char *dest, sh4addr_t addr )
    61 {
    62     // Render buffers pretty much have to be (at least) 32-byte aligned
    63     pvr2_render_buffer_invalidate(addr, FALSE);
    64     memcpy( dest, (video_base + (addr&0x007FFFFF)), 32 );
    65 }
    66 static void FASTCALL pvr2_vram32_write_burst( sh4addr_t addr, unsigned char *src )
    67 {
    68     // Render buffers pretty much have to be (at least) 32-byte aligned
    69     pvr2_render_buffer_invalidate(addr, TRUE);
    70     memcpy( (video_base + (addr&0x007FFFFF)), src, 32 );    
    71 }
    73 struct mem_region_fn mem_region_vram32 = { pvr2_vram32_read_long, pvr2_vram32_write_long, 
    74         pvr2_vram32_read_word, pvr2_vram32_write_word, 
    75         pvr2_vram32_read_byte, pvr2_vram32_write_byte, 
    76         pvr2_vram32_read_burst, pvr2_vram32_write_burst }; 
    78 /************************* VRAM64 address space ***************************/
    80 #define TRANSLATE_VIDEO_64BIT_ADDRESS(a)  ( (((a)&0x00FFFFF8)>>1)|(((a)&0x00000004)<<20)|((a)&0x03) )
    82 static int32_t FASTCALL pvr2_vram64_read_long( sh4addr_t addr )
    83 {
    84     addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
    85     pvr2_render_buffer_invalidate(addr, FALSE);
    86     return *((int32_t *)(video_base+(addr&0x007FFFFF)));
    87 }
    88 static int32_t FASTCALL pvr2_vram64_read_word( sh4addr_t addr )
    89 {
    90     addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
    91     pvr2_render_buffer_invalidate(addr, FALSE);
    92     return SIGNEXT16(*((int16_t *)(video_base+(addr&0x007FFFFF))));
    93 }
    94 static int32_t FASTCALL pvr2_vram64_read_byte( sh4addr_t addr )
    95 {
    96     addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
    97     pvr2_render_buffer_invalidate(addr, FALSE);
    98     return SIGNEXT8(*((int8_t *)(video_base+(addr&0x007FFFFF))));
    99 }
   100 static void FASTCALL pvr2_vram64_write_long( sh4addr_t addr, uint32_t val )
   101 {
   102     texcache_invalidate_page(addr& 0x007FFFFF);
   103     addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   104     pvr2_render_buffer_invalidate(addr, TRUE);
   105     *(uint32_t *)(video_base + (addr&0x007FFFFF)) = val;
   106 }
   107 static void FASTCALL pvr2_vram64_write_word( sh4addr_t addr, uint32_t val )
   108 {
   109     texcache_invalidate_page(addr& 0x007FFFFF);
   110     addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   111     pvr2_render_buffer_invalidate(addr, TRUE);
   112     *(uint16_t *)(video_base + (addr&0x007FFFFF)) = (uint16_t)val;
   113 }
   114 static void FASTCALL pvr2_vram64_write_byte( sh4addr_t addr, uint32_t val )
   115 {
   116     texcache_invalidate_page(addr& 0x007FFFFF);
   117     addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   118     pvr2_render_buffer_invalidate(addr, TRUE);
   119     *(uint8_t *)(video_base + (addr&0x007FFFFF)) = (uint8_t)val;
   120 }
   121 static void FASTCALL pvr2_vram64_read_burst( unsigned char *dest, sh4addr_t addr )
   122 {
   123     pvr2_vram64_read( dest, addr, 32 );
   124 }
   125 static void FASTCALL pvr2_vram64_write_burst( sh4addr_t addr, unsigned char *src )
   126 {
   127     pvr2_vram64_write( addr, src, 32 );
   128 }
   130 struct mem_region_fn mem_region_vram64 = { pvr2_vram64_read_long, pvr2_vram64_write_long, 
   131         pvr2_vram64_read_word, pvr2_vram64_write_word, 
   132         pvr2_vram64_read_byte, pvr2_vram64_write_byte, 
   133         pvr2_vram64_read_burst, pvr2_vram64_write_burst }; 
   137 void pvr2_dma_write( sh4addr_t destaddr, unsigned char *src, uint32_t count )
   138 {
   139     int region;
   141     switch( destaddr & 0x13800000 ) {
   142     case 0x10000000:
   143     case 0x12000000:
   144         pvr2_ta_write( src, count );
   145         break;
   146     case 0x11000000:
   147     case 0x11800000:
   148         region = MMIO_READ( ASIC, PVRDMARGN1 );
   149         if( region == 0 ) {
   150             pvr2_vram64_write( destaddr, src, count );
   151         } else {
   152             destaddr &= PVR2_RAM_MASK;
   153             unsigned char *dest = video_base + destaddr;
   154             if( PVR2_RAM_SIZE - destaddr < count ) {
   155                 count = PVR2_RAM_SIZE - destaddr;
   156             }
   157             memcpy( dest, src, count );
   158         }
   159         break;
   160     case 0x10800000:
   161     case 0x12800000:
   162         pvr2_yuv_write( src, count );
   163         break;
   164     case 0x13000000:
   165     case 0x13800000:
   166         region = MMIO_READ( ASIC, PVRDMARGN2 );
   167         if( region == 0 ) {
   168             pvr2_vram64_write( destaddr, src, count );
   169         } else {
   170             destaddr &= PVR2_RAM_MASK;
   171             unsigned char *dest = video_base + destaddr;
   172             if( PVR2_RAM_SIZE - destaddr < count ) {
   173                 count = PVR2_RAM_SIZE - destaddr;
   174             }
   175             memcpy( dest, src, count );
   176         }
   177     }
   178 }
   180 void pvr2_vram64_write( sh4addr_t destaddr, unsigned char *src, uint32_t length )
   181 {
   182     int bank_flag = (destaddr & 0x04) >> 2;
   183     uint32_t *banks[2];
   184     uint32_t *dwsrc;
   185     int i;
   187     destaddr = destaddr & 0x7FFFFF;
   188     if( destaddr + length > 0x800000 ) {
   189         length = 0x800000 - destaddr;
   190     }
   192     for( i=destaddr & 0xFFFFF000; i < destaddr + length; i+= LXDREAM_PAGE_SIZE ) {
   193         texcache_invalidate_page( i );
   194     }
   196     banks[0] = ((uint32_t *)(video_base + ((destaddr & 0x007FFFF8) >>1)));
   197     banks[1] = banks[0] + 0x100000;
   198     if( bank_flag )
   199         banks[0]++;
   201     /* Handle non-aligned start of source */
   202     if( destaddr & 0x03 ) {
   203         unsigned char *dest = ((unsigned char *)banks[bank_flag]) + (destaddr & 0x03);
   204         for( i= destaddr & 0x03; i < 4 && length > 0; i++, length-- ) {
   205             *dest++ = *src++;
   206         }
   207         bank_flag = !bank_flag;
   208     }
   210     dwsrc = (uint32_t *)src;
   211     while( length >= 4 ) {
   212         *banks[bank_flag]++ = *dwsrc++;
   213         bank_flag = !bank_flag;
   214         length -= 4;
   215     }
   217     /* Handle non-aligned end of source */
   218     if( length ) {
   219         src = (unsigned char *)dwsrc;
   220         unsigned char *dest = (unsigned char *)banks[bank_flag];
   221         while( length-- > 0 ) {
   222             *dest++ = *src++;
   223         }
   224     }
   225 }
   227 /**
   228  * Write an image to 64-bit vram, with a line-stride different from the line-size.
   229  * The destaddr must be 64-bit aligned, and both line_bytes and line_stride_bytes
   230  * must be multiples of 8.
   231  */
   232 void pvr2_vram64_write_stride( sh4addr_t destaddr, unsigned char *src, uint32_t line_bytes,
   233                                uint32_t line_stride_bytes, uint32_t line_count )
   234 {
   235     int i,j;
   236     uint32_t *banks[2];
   237     uint32_t *dwsrc = (uint32_t *)src;
   238     uint32_t line_gap = (line_stride_bytes - line_bytes) >> 3;
   240     destaddr = destaddr & 0x7FFFF8;
   241     line_bytes >>= 3;
   243     for( i=destaddr; i < destaddr + line_stride_bytes*line_count; i+= LXDREAM_PAGE_SIZE ) {
   244         texcache_invalidate_page( i );
   245     }
   247     banks[0] = (uint32_t *)(video_base + (destaddr >>1));
   248     banks[1] = banks[0] + 0x100000;
   250     for( i=0; i<line_count; i++ ) {
   251         for( j=0; j<line_bytes; j++ ) {
   252             *banks[0]++ = *dwsrc++;
   253             *banks[1]++ = *dwsrc++;
   254         }
   255         banks[0] += line_gap;
   256         banks[1] += line_gap;
   257     }
   258 }
   260 /**
   261  * Read an image from 64-bit vram, with a destination line-stride different from the line-size.
   262  * The srcaddr must be 32-bit aligned, and both line_bytes and line_stride_bytes
   263  * must be multiples of 4. line_stride_bytes must be >= line_bytes.
   264  * This method is used to extract a "stride" texture from vram.
   265  */
   266 void pvr2_vram64_read_stride( unsigned char *dest, uint32_t dest_line_bytes, sh4addr_t srcaddr,
   267                               uint32_t src_line_bytes, uint32_t line_count )
   268 {
   269     int bank_flag = (srcaddr & 0x04) >> 2;
   270     uint32_t *banks[2];
   271     uint32_t *dwdest;
   272     uint32_t dest_line_gap = 0;
   273     uint32_t src_line_gap = 0;
   274     uint32_t line_bytes;
   275     int src_line_gap_flag;
   276     int i,j;
   278     srcaddr = srcaddr & 0x7FFFF8;
   279     if( src_line_bytes <= dest_line_bytes ) {
   280         dest_line_gap = (dest_line_bytes - src_line_bytes) >> 2;
   281         src_line_gap = 0;
   282         src_line_gap_flag = 0;
   283         line_bytes = src_line_bytes >> 2;
   284     } else {
   285         i = (src_line_bytes - dest_line_bytes);
   286         src_line_gap_flag = i & 0x04;
   287         src_line_gap = i >> 3;
   288         line_bytes = dest_line_bytes >> 2;
   289     }
   291     banks[0] = (uint32_t *)(video_base + (srcaddr>>1));
   292     banks[1] = banks[0] + 0x100000;
   293     if( bank_flag )
   294         banks[0]++;
   296     dwdest = (uint32_t *)dest;
   297     for( i=0; i<line_count; i++ ) {
   298         for( j=0; j<line_bytes; j++ ) {
   299             *dwdest++ = *banks[bank_flag]++;
   300             bank_flag = !bank_flag;
   301         }
   302         dwdest += dest_line_gap;
   303         banks[0] += src_line_gap;
   304         banks[1] += src_line_gap;
   305         if( src_line_gap_flag ) {
   306             banks[bank_flag]++;
   307             bank_flag = !bank_flag;
   308         }
   309     }
   310 }
   313 /**
   314  * @param dest Destination image buffer
   315  * @param banks Source data expressed as two bank pointers
   316  * @param offset Offset into banks[0] specifying where the next byte
   317  *  to read is (0..3)
   318  * @param x1,y1 Destination coordinates
   319  * @param width Width of current destination block
   320  * @param stride Total width of image (ie stride) in bytes
   321  */
   323 static void pvr2_vram64_detwiddle_4( uint8_t *dest, uint8_t *banks[2], int offset,
   324                                      int x1, int y1, int width, int stride )
   325 {
   326     if( width == 2 ) {
   327         x1 = x1 >> 1;
   328         uint8_t t1 = *banks[offset<4?0:1]++;
   329         uint8_t t2 = *banks[offset<3?0:1]++;
   330         dest[y1*stride + x1] = (t1 & 0x0F) | (t2<<4);
   331         dest[(y1+1)*stride + x1] = (t1>>4) | (t2&0xF0);
   332     } else if( width == 4 ) {
   333         pvr2_vram64_detwiddle_4( dest, banks, offset, x1, y1, 2, stride );
   334         pvr2_vram64_detwiddle_4( dest, banks, offset+2, x1, y1+2, 2, stride );
   335         pvr2_vram64_detwiddle_4( dest, banks, offset+4, x1+2, y1, 2, stride );
   336         pvr2_vram64_detwiddle_4( dest, banks, offset+6, x1+2, y1+2, 2, stride );
   338     } else {
   339         int subdivide = width >> 1;
   340         pvr2_vram64_detwiddle_4( dest, banks, offset, x1, y1, subdivide, stride );
   341         pvr2_vram64_detwiddle_4( dest, banks, offset, x1, y1+subdivide, subdivide, stride );
   342         pvr2_vram64_detwiddle_4( dest, banks, offset, x1+subdivide, y1, subdivide, stride );
   343         pvr2_vram64_detwiddle_4( dest, banks, offset, x1+subdivide, y1+subdivide, subdivide, stride );
   344     }
   345 }
   347 /**
   348  * @param dest Destination image buffer
   349  * @param banks Source data expressed as two bank pointers
   350  * @param offset Offset into banks[0] specifying where the next byte
   351  *  to read is (0..3)
   352  * @param x1,y1 Destination coordinates
   353  * @param width Width of current destination block
   354  * @param stride Total width of image (ie stride)
   355  */
   357 static void pvr2_vram64_detwiddle_8( uint8_t *dest, uint8_t *banks[2], int offset,
   358                                      int x1, int y1, int width, int stride )
   359 {
   360     if( width == 2 ) {
   361         dest[y1*stride + x1] = *banks[0]++;
   362         dest[(y1+1)*stride + x1] = *banks[offset<3?0:1]++;
   363         dest[y1*stride + x1 + 1] = *banks[offset<2?0:1]++;
   364         dest[(y1+1)*stride + x1 + 1] = *banks[offset==0?0:1]++;
   365         uint8_t *tmp = banks[0]; /* swap banks */
   366         banks[0] = banks[1];
   367         banks[1] = tmp;
   368     } else {
   369         int subdivide = width >> 1;
   370         pvr2_vram64_detwiddle_8( dest, banks, offset, x1, y1, subdivide, stride );
   371         pvr2_vram64_detwiddle_8( dest, banks, offset, x1, y1+subdivide, subdivide, stride );
   372         pvr2_vram64_detwiddle_8( dest, banks, offset, x1+subdivide, y1, subdivide, stride );
   373         pvr2_vram64_detwiddle_8( dest, banks, offset, x1+subdivide, y1+subdivide, subdivide, stride );
   374     }
   375 }
   377 /**
   378  * @param dest Destination image buffer
   379  * @param banks Source data expressed as two bank pointers
   380  * @param offset Offset into banks[0] specifying where the next word
   381  *  to read is (0 or 1)
   382  * @param x1,y1 Destination coordinates
   383  * @param width Width of current destination block
   384  * @param stride Total width of image (ie stride)
   385  */
   387 static void pvr2_vram64_detwiddle_16( uint16_t *dest, uint16_t *banks[2], int offset,
   388                                       int x1, int y1, int width, int stride )
   389 {
   390     if( width == 2 ) {
   391         dest[y1*stride + x1] = *banks[0]++;
   392         dest[(y1+1)*stride + x1] = *banks[offset]++;
   393         dest[y1*stride + x1 + 1] = *banks[1]++;
   394         dest[(y1+1)*stride + x1 + 1] = *banks[offset^1]++;
   395     } else {
   396         int subdivide = width >> 1;
   397         pvr2_vram64_detwiddle_16( dest, banks, offset, x1, y1, subdivide, stride );
   398         pvr2_vram64_detwiddle_16( dest, banks, offset, x1, y1+subdivide, subdivide, stride );
   399         pvr2_vram64_detwiddle_16( dest, banks, offset, x1+subdivide, y1, subdivide, stride );
   400         pvr2_vram64_detwiddle_16( dest, banks, offset, x1+subdivide, y1+subdivide, subdivide, stride );
   401     }
   402 }
   404 /**
   405  * Read an image from 64-bit vram stored as twiddled 4-bit pixels. The
   406  * image is written out to the destination in detwiddled form.
   407  * @param dest destination buffer, which must be at least width*height/2 in length
   408  * @param srcaddr source address in vram
   409  * @param width image width (must be a power of 2)
   410  * @param height image height (must be a power of 2)
   411  */
   412 void pvr2_vram64_read_twiddled_4( unsigned char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height )
   413 {
   414     int offset_flag = (srcaddr & 0x07);
   415     uint8_t *banks[2];
   416     uint8_t *wdest = (uint8_t*)dest;
   417     uint32_t stride = width >> 1;
   418     int i;
   420     srcaddr = srcaddr & 0x7FFFF8;
   422     banks[0] = (uint8_t *)(video_base + (srcaddr>>1));
   423     banks[1] = banks[0] + 0x400000;
   424     if( offset_flag & 0x04 ) { // If source is not 64-bit aligned, swap the banks
   425         uint8_t *tmp = banks[0];
   426         banks[0] = banks[1];
   427         banks[1] = tmp + 4;
   428         offset_flag &= 0x03;
   429     }
   430     banks[0] += offset_flag;
   432     if( width > height ) {
   433         for( i=0; i<width; i+=height ) {
   434             pvr2_vram64_detwiddle_4( wdest, banks, offset_flag, i, 0, height, stride );
   435         }
   436     } else if( height > width ) {
   437         for( i=0; i<height; i+=width ) {
   438             pvr2_vram64_detwiddle_4( wdest, banks, offset_flag, 0, i, width, stride );
   439         }
   440     } else if( width == 1 ) {
   441         *wdest = *banks[0];
   442     } else {
   443         pvr2_vram64_detwiddle_4( wdest, banks, offset_flag, 0, 0, width, stride );
   444     }
   445 }
   447 /**
   448  * Read an image from 64-bit vram stored as twiddled 8-bit pixels. The
   449  * image is written out to the destination in detwiddled form.
   450  * @param dest destination buffer, which must be at least width*height in length
   451  * @param srcaddr source address in vram
   452  * @param width image width (must be a power of 2)
   453  * @param height image height (must be a power of 2)
   454  */
   455 void pvr2_vram64_read_twiddled_8( unsigned char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height )
   456 {
   457     int offset_flag = (srcaddr & 0x07);
   458     uint8_t *banks[2];
   459     uint8_t *wdest = (uint8_t*)dest;
   460     int i;
   462     srcaddr = srcaddr & 0x7FFFF8;
   464     banks[0] = (uint8_t *)(video_base + (srcaddr>>1));
   465     banks[1] = banks[0] + 0x400000;
   466     if( offset_flag & 0x04 ) { // If source is not 64-bit aligned, swap the banks
   467         uint8_t *tmp = banks[0];
   468         banks[0] = banks[1];
   469         banks[1] = tmp + 4;
   470         offset_flag &= 0x03;
   471     }
   472     banks[0] += offset_flag;
   474     if( width > height ) {
   475         for( i=0; i<width; i+=height ) {
   476             pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, i, 0, height, width );
   477         }
   478     } else if( height > width ) {
   479         for( i=0; i<height; i+=width ) {
   480             pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, 0, i, width, width );
   481         }
   482     } else if( width == 1 ) {
   483         *wdest = *banks[0];
   484     } else {
   485         pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, 0, 0, width, width );
   486     }
   487 }
   489 /**
   490  * Read an image from 64-bit vram stored as twiddled 16-bit pixels. The
   491  * image is written out to the destination in detwiddled form.
   492  * @param dest destination buffer, which must be at least width*height*2 in length
   493  * @param srcaddr source address in vram (must be 16-bit aligned)
   494  * @param width image width (must be a power of 2)
   495  * @param height image height (must be a power of 2)
   496  */
   497 void pvr2_vram64_read_twiddled_16( unsigned char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height ) {
   498     int offset_flag = (srcaddr & 0x06) >> 1;
   499     uint16_t *banks[2];
   500     uint16_t *wdest = (uint16_t*)dest;
   501     int i;
   503     srcaddr = srcaddr & 0x7FFFF8;
   505     banks[0] = (uint16_t *)(video_base + (srcaddr>>1));
   506     banks[1] = banks[0] + 0x200000;
   507     if( offset_flag & 0x02 ) { // If source is not 64-bit aligned, swap the banks
   508         uint16_t *tmp = banks[0];
   509         banks[0] = banks[1];
   510         banks[1] = tmp + 2;
   511         offset_flag &= 0x01;
   512     }
   513     banks[0] += offset_flag;
   516     if( width > height ) {
   517         for( i=0; i<width; i+=height ) {
   518             pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, i, 0, height, width );
   519         }
   520     } else if( height > width ) {
   521         for( i=0; i<height; i+=width ) {
   522             pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, 0, i, width, width );
   523         }
   524     } else if( width == 1 ) {
   525         *wdest = *banks[0];
   526     } else {
   527         pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, 0, 0, width, width );
   528     }
   529 }
   531 static void pvr2_vram_write_invert( sh4addr_t destaddr, unsigned char *src, uint32_t src_size, 
   532                              uint32_t line_size, uint32_t dest_stride,
   533                              uint32_t src_stride )
   534 {
   535     unsigned char *dest = video_base + (destaddr & 0x007FFFFF);
   536     unsigned char *p = src + src_size - src_stride;
   537     while( p >= src ) {
   538         memcpy( dest, p, line_size );
   539         p -= src_stride;
   540         dest += dest_stride;
   541     }
   542 }
   544 static void pvr2_vram64_write_invert( sh4addr_t destaddr, unsigned char *src, 
   545                                       uint32_t src_size, uint32_t line_size, 
   546                                       uint32_t dest_stride, uint32_t src_stride )
   547 {
   548     int i,j;
   549     uint32_t *banks[2];
   550     uint32_t *dwsrc = (uint32_t *)(src + src_size - src_stride);
   551     int32_t src_line_gap = ((int32_t)src_stride + line_size) >> 2; 
   552     int32_t dest_line_gap = ((int32_t)dest_stride - (int32_t)line_size) >> 3;
   554     destaddr = destaddr & 0x7FFFF8;
   556     for( i=destaddr; i < destaddr + dest_stride*(src_size/src_stride); i+= LXDREAM_PAGE_SIZE ) {
   557         texcache_invalidate_page( i );
   558     }
   560     banks[0] = (uint32_t *)(video_base + (destaddr >>1));
   561     banks[1] = banks[0] + 0x100000;
   563     while( dwsrc >= (uint32_t *)src ) { 
   564         for( j=0; j<line_size; j+=8 ) {
   565             *banks[0]++ = *dwsrc++;
   566             *banks[1]++ = *dwsrc++;
   567         }
   568         banks[0] += dest_line_gap;
   569         banks[1] += dest_line_gap;
   570         dwsrc -= src_line_gap;
   571     }    
   572 }
   574 /**
   575  * Copy a pixel buffer to vram, flipping and scaling at the same time. This
   576  * is not massively efficient, but it's used pretty rarely.
   577  */
   578 static void pvr2_vram_write_invert_hscale( sh4addr_t destaddr, unsigned char *src, uint32_t src_size, 
   579                              uint32_t line_size, uint32_t dest_stride,
   580                              uint32_t src_stride, int bpp )
   581 {
   582     unsigned char *dest = video_base + (destaddr & 0x007FFFFF);
   583     unsigned char *p = src + src_size - src_stride;
   584     while( p >= src ) {
   585         unsigned char *s = p, *d = dest;
   586         int i;
   587         while( s < p+line_size ) {
   588             for( i=0; i<bpp; i++ ) {
   589                 *d++ = *s++;
   590             }
   591             s+= bpp;
   592         }
   593         p -= src_stride;
   594         dest += dest_stride;
   595     }
   596 }
   598 void pvr2_vram64_read( unsigned char *dest, sh4addr_t srcaddr, uint32_t length )
   599 {
   600     int bank_flag = (srcaddr & 0x04) >> 2;
   601     uint32_t *banks[2];
   602     uint32_t *dwdest;
   603     int i;
   605     srcaddr = srcaddr & 0x7FFFFF;
   606     if( srcaddr + length > 0x800000 )
   607         length = 0x800000 - srcaddr;
   609     banks[0] = ((uint32_t *)(video_base + ((srcaddr&0x007FFFF8)>>1)));
   610     banks[1] = banks[0] + 0x100000;
   611     if( bank_flag )
   612         banks[0]++;
   614     /* Handle non-aligned start of source */
   615     if( srcaddr & 0x03 ) {
   616         char *src = ((char *)banks[bank_flag]) + (srcaddr & 0x03);
   617         for( i= srcaddr & 0x03; i < 4 && length > 0; i++, length-- ) {
   618             *dest++ = *src++;
   619         }
   620         bank_flag = !bank_flag;
   621     }
   623     dwdest = (uint32_t *)dest;
   624     while( length >= 4 ) {
   625         *dwdest++ = *banks[bank_flag]++;
   626         bank_flag = !bank_flag;
   627         length -= 4;
   628     }
   630     /* Handle non-aligned end of source */
   631     if( length ) {
   632         dest = (unsigned char *)dwdest;
   633         unsigned char *src = (unsigned char *)banks[bank_flag];
   634         while( length-- > 0 ) {
   635             *dest++ = *src++;
   636         }
   637     }
   638 }
   640 void pvr2_vram64_dump_file( sh4addr_t addr, uint32_t length, gchar *filename )
   641 {
   642     uint32_t tmp[length>>2];
   643     FILE *f = fopen(filename, "wo");
   644     unsigned int i, j;
   646     if( f == NULL ) {
   647         ERROR( "Unable to write to dump file '%s' (%s)", filename, strerror(errno) );
   648         return;
   649     }
   650     pvr2_vram64_read( (unsigned char *)tmp, addr, length );
   651     fprintf( f, "%08X\n", addr );
   652     for( i =0; i<length>>2; i+=8 ) {
   653         for( j=i; j<i+8; j++ ) {
   654             if( j < length )
   655                 fprintf( f, " %08X", tmp[j] );
   656             else
   657                 fprintf( f, "         " );
   658         }
   659         fprintf( f, "\n" );
   660     }
   661     fclose(f);
   662 }
   664 void pvr2_vram64_dump( sh4addr_t addr, uint32_t length, FILE *f )
   665 {
   666     unsigned char tmp[length];
   667     pvr2_vram64_read( tmp, addr, length );
   668     fwrite_dump( tmp, length, f );
   669 }
   673 /**
   674  * Flush the indicated render buffer back to PVR. Caller is responsible for
   675  * tracking whether there is actually anything in the buffer.
   676  *
   677  * FIXME: Handle horizontal scaler 
   678  *
   679  * @param buffer A render buffer indicating the address to store to, and the
   680  * format the data needs to be in.
   681  */
   682 void pvr2_render_buffer_copy_to_sh4( render_buffer_t buffer )
   683 {
   684     int line_size = buffer->width * colour_formats[buffer->colour_format].bpp;
   685     int src_stride = line_size;
   686     unsigned char target[buffer->size];
   688     display_driver->read_render_buffer( target, buffer, line_size, buffer->colour_format );
   690     if( (buffer->scale & 0xFFFF) == 0x0800 )
   691         src_stride <<= 1;
   693     if( (buffer->address & 0xFF000000) == 0x04000000 ) {
   694         pvr2_vram64_write_invert( buffer->address, target, buffer->size, line_size, 
   695                                   buffer->rowstride, src_stride );
   696     } else {
   697         /* Regular buffer */
   698         if( buffer->scale & SCALER_HSCALE ) {
   699             pvr2_vram_write_invert_hscale( buffer->address, target, buffer->size, line_size, buffer->rowstride,
   700                                            src_stride, colour_formats[buffer->colour_format].bpp );
   701         } else {
   702             pvr2_vram_write_invert( buffer->address, target, buffer->size, line_size, buffer->rowstride,
   703                                     src_stride );
   704         }
   705     }
   706     buffer->flushed = TRUE;
   707 }
.