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