filename | test/pvr.c |
changeset | 190:f7653df5e832 |
prev | 185:6755a04c447f |
next | 213:da6b1904f67b |
author | nkeynes |
date | Sun Aug 06 06:13:51 2006 +0000 (17 years ago) |
permissions | -rw-r--r-- |
last change | First pass at implementing the tile clip. Reasonably accurate wrt basic understanding of how its supposed to work, not so accurate wrt actual hardware behaviour |
file | annotate | diff | log | raw |
nkeynes@185 | 1 | /** |
nkeynes@190 | 2 | * $Id: pvr.c,v 1.2 2006-08-02 04:13:15 nkeynes Exp $ |
nkeynes@185 | 3 | * |
nkeynes@185 | 4 | * PVR support code |
nkeynes@185 | 5 | * |
nkeynes@185 | 6 | * Copyright (c) 2006 Nathan Keynes. |
nkeynes@185 | 7 | * |
nkeynes@185 | 8 | * This program is free software; you can redistribute it and/or modify |
nkeynes@185 | 9 | * it under the terms of the GNU General Public License as published by |
nkeynes@185 | 10 | * the Free Software Foundation; either version 2 of the License, or |
nkeynes@185 | 11 | * (at your option) any later version. |
nkeynes@185 | 12 | * |
nkeynes@185 | 13 | * This program is distributed in the hope that it will be useful, |
nkeynes@185 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
nkeynes@185 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
nkeynes@185 | 16 | * GNU General Public License for more details. |
nkeynes@185 | 17 | */ |
nkeynes@185 | 18 | |
nkeynes@185 | 19 | #include "lib.h" |
nkeynes@185 | 20 | #include "pvr.h" |
nkeynes@185 | 21 | |
nkeynes@185 | 22 | #define PVR_BASE 0xA05F8000 |
nkeynes@185 | 23 | #define PVR_RESET (PVR_BASE+0x008) |
nkeynes@185 | 24 | #define TA_INIT (PVR_BASE+0x144) |
nkeynes@185 | 25 | #define TA_TILESTART (PVR_BASE+0x124) |
nkeynes@185 | 26 | #define TA_OBJSTART (PVR_BASE+0x128) |
nkeynes@185 | 27 | #define TA_TILEEND (PVR_BASE+0x12C) |
nkeynes@185 | 28 | #define TA_OBJEND (PVR_BASE+0x130) |
nkeynes@185 | 29 | #define TA_TILEPOSN (PVR_BASE+0x134) |
nkeynes@185 | 30 | #define TA_OBJPOSN (PVR_BASE+0x138) |
nkeynes@185 | 31 | #define TA_SIZE (PVR_BASE+0x13C) |
nkeynes@185 | 32 | #define TA_TILECFG (PVR_BASE+0x140) |
nkeynes@185 | 33 | #define TA_PLISTSTART (PVR_BASE+0x164) |
nkeynes@185 | 34 | |
nkeynes@185 | 35 | |
nkeynes@185 | 36 | void ta_dump_regs( FILE *f ) |
nkeynes@185 | 37 | { |
nkeynes@185 | 38 | fprintf( stderr, "TA Object start[128]: %08X posn[138]: %08X end[130]: %08X\n", |
nkeynes@185 | 39 | long_read(TA_OBJSTART), long_read(TA_OBJPOSN), long_read(TA_OBJEND) ); |
nkeynes@185 | 40 | fprintf( stderr, "TA OPB start[124]: %08X posn[134]: %08X end[12c]: %08X init: %08X\n", |
nkeynes@185 | 41 | long_read(TA_TILESTART), long_read(TA_TILEPOSN), long_read(TA_TILEEND), |
nkeynes@185 | 42 | long_read(TA_PLISTSTART) ); |
nkeynes@185 | 43 | fprintf( stderr, "TA Tilesize: %08X config: %08X\n", long_read(TA_SIZE), long_read(TA_TILECFG) ); |
nkeynes@185 | 44 | } |
nkeynes@185 | 45 | |
nkeynes@190 | 46 | |
nkeynes@190 | 47 | void ta_init( struct ta_config *config ) |
nkeynes@190 | 48 | { |
nkeynes@190 | 49 | long_write( PVR_RESET, 1 ); |
nkeynes@190 | 50 | long_write( PVR_RESET, 0 ); |
nkeynes@190 | 51 | |
nkeynes@190 | 52 | long_write( TA_SIZE, config->grid_size ); |
nkeynes@190 | 53 | long_write( TA_OBJSTART, config->obj_start & 0x00FFFFFF ); |
nkeynes@190 | 54 | long_write( TA_OBJEND, config->obj_end & 0x00FFFFFF ); |
nkeynes@190 | 55 | long_write( TA_TILESTART, config->tile_start & 0x00FFFFFF ); |
nkeynes@190 | 56 | long_write( TA_TILEEND, config->tile_end & 0x00FFFFFF ); |
nkeynes@190 | 57 | long_write( TA_PLISTSTART, config->plist_start & 0x00FFFFFF ); |
nkeynes@190 | 58 | long_write( TA_TILECFG, config->ta_cfg ); |
nkeynes@190 | 59 | long_write( TA_INIT, 0x80000000 ); |
nkeynes@190 | 60 | } |
nkeynes@190 | 61 | |
nkeynes@185 | 62 | int pvr_get_objbuf_size( ) |
nkeynes@185 | 63 | { |
nkeynes@185 | 64 | return long_read( TA_OBJPOSN ) - long_read( TA_OBJSTART ); |
nkeynes@185 | 65 | } |
nkeynes@185 | 66 | |
nkeynes@190 | 67 | int pvr_get_plist_posn( ) |
nkeynes@190 | 68 | { |
nkeynes@190 | 69 | unsigned int addr = long_read( TA_TILEPOSN ) << 2; |
nkeynes@190 | 70 | return addr; |
nkeynes@190 | 71 | } |
nkeynes@190 | 72 | |
nkeynes@185 | 73 | void pvr_dump_objbuf( FILE *f ) |
nkeynes@185 | 74 | { |
nkeynes@185 | 75 | unsigned int start = long_read( TA_OBJSTART ); |
nkeynes@185 | 76 | unsigned int posn = long_read( TA_OBJPOSN ); |
nkeynes@185 | 77 | unsigned int end = long_read( TA_OBJEND ); |
nkeynes@185 | 78 | char *buf; |
nkeynes@185 | 79 | unsigned int length; |
nkeynes@185 | 80 | if( start < posn ) { |
nkeynes@185 | 81 | buf = (char *)(0xA5000000+start); |
nkeynes@185 | 82 | length = posn-start; |
nkeynes@185 | 83 | } else { |
nkeynes@185 | 84 | buf = (char *)(0xA5000000+end); |
nkeynes@185 | 85 | length = start-posn; |
nkeynes@185 | 86 | } |
nkeynes@185 | 87 | |
nkeynes@185 | 88 | fprintf( f, "Obj buffer: %08X - %08X - %08X\n", start, posn, end ); |
nkeynes@185 | 89 | fwrite_dump( f, buf, length ); |
nkeynes@185 | 90 | } |
nkeynes@185 | 91 | |
nkeynes@185 | 92 | void pvr_dump_tilebuf( FILE *f ) |
nkeynes@185 | 93 | { |
nkeynes@185 | 94 | unsigned int start = long_read( TA_TILESTART ); |
nkeynes@185 | 95 | unsigned int posn = long_read( TA_TILEPOSN ); |
nkeynes@185 | 96 | unsigned int end = long_read( TA_TILEEND ); |
nkeynes@185 | 97 | char *buf; |
nkeynes@185 | 98 | unsigned int length; |
nkeynes@185 | 99 | if( start < posn ) { |
nkeynes@185 | 100 | buf = (char *)(0xA5000000+start); |
nkeynes@185 | 101 | length = posn-start; |
nkeynes@185 | 102 | } else { |
nkeynes@185 | 103 | buf = (char *)(0xA5000000+end); |
nkeynes@185 | 104 | length = start-posn; |
nkeynes@185 | 105 | } |
nkeynes@185 | 106 | |
nkeynes@185 | 107 | fprintf( f, "Tile buffer: %08X - %08X - %08X\n", start, posn, end ); |
nkeynes@185 | 108 | fwrite_dump( f, buf, length ); |
nkeynes@185 | 109 | } |
nkeynes@185 | 110 | |
nkeynes@185 | 111 | /************** Stolen from TATEST *************/ |
nkeynes@185 | 112 | |
nkeynes@185 | 113 | static unsigned int three_d_params[] = { |
nkeynes@185 | 114 | 0x80a8, 0x15d1c951, /* M (Unknown magic value) */ |
nkeynes@185 | 115 | 0x80a0, 0x00000020, /* M */ |
nkeynes@185 | 116 | 0x8008, 0x00000000, /* TA out of reset */ |
nkeynes@185 | 117 | 0x8048, 0x00000009, /* alpha config */ |
nkeynes@185 | 118 | 0x8068, 0x02800000, /* pixel clipping x */ |
nkeynes@185 | 119 | 0x806c, 0x01e00000, /* pixel clipping y */ |
nkeynes@185 | 120 | 0x8110, 0x00093f39, /* M */ |
nkeynes@185 | 121 | 0x8098, 0x00800408, /* M */ |
nkeynes@185 | 122 | 0x804c, 0x000000a0, /* display align (640*2)/8 */ |
nkeynes@185 | 123 | 0x8078, 0x3f800000, /* polygon culling (1.0f) */ |
nkeynes@185 | 124 | 0x8084, 0x00000000, /* M */ |
nkeynes@185 | 125 | 0x8030, 0x00000101, /* M */ |
nkeynes@185 | 126 | 0x80b0, 0x007f7f7f, /* Fog table color */ |
nkeynes@185 | 127 | 0x80b4, 0x007f7f7f, /* Fog vertex color */ |
nkeynes@185 | 128 | 0x80c0, 0x00000000, /* color clamp min */ |
nkeynes@185 | 129 | 0x80bc, 0xffffffff, /* color clamp max */ |
nkeynes@185 | 130 | 0x8080, 0x00000007, /* M */ |
nkeynes@185 | 131 | 0x8074, 0x00000001, /* cheap shadow */ |
nkeynes@185 | 132 | 0x807c, 0x0027df77, /* M */ |
nkeynes@185 | 133 | 0x8008, 0x00000001, /* TA reset */ |
nkeynes@185 | 134 | 0x8008, 0x00000000, /* TA out of reset */ |
nkeynes@185 | 135 | 0x80e4, 0x00000000, /* stride width */ |
nkeynes@185 | 136 | 0x6884, 0x00000000, /* Disable all interrupt events */ |
nkeynes@185 | 137 | 0x6930, 0x00000000, |
nkeynes@185 | 138 | 0x6938, 0x00000000, |
nkeynes@185 | 139 | 0x6900, 0xffffffff, /* Clear all pending int events */ |
nkeynes@185 | 140 | 0x6908, 0xffffffff, |
nkeynes@185 | 141 | 0x6930, 0x002807ec, /* Re-enable some events */ |
nkeynes@185 | 142 | 0x6938, 0x0000000e, |
nkeynes@185 | 143 | 0x80b8, 0x0000ff07, /* fog density */ |
nkeynes@185 | 144 | 0x80b4, 0x007f7f7f, /* fog vertex color */ |
nkeynes@185 | 145 | 0x80b0, 0x007f7f7f, /* fog table color */ |
nkeynes@185 | 146 | 0x8108, 0x00000003 /* 32bit palette */ |
nkeynes@185 | 147 | }; |
nkeynes@185 | 148 | |
nkeynes@185 | 149 | static unsigned int scrn_params[] = { |
nkeynes@185 | 150 | 0x80e8, 0x00160000, /* screen control */ |
nkeynes@185 | 151 | 0x8044, 0x00800000, /* pixel mode (vb+0x11) */ |
nkeynes@185 | 152 | 0x805c, 0x00000000, /* Size modulo and display lines (vb+0x17) */ |
nkeynes@185 | 153 | 0x80d0, 0x00000100, /* interlace flags */ |
nkeynes@185 | 154 | 0x80d8, 0x020c0359, /* M */ |
nkeynes@185 | 155 | 0x80cc, 0x001501fe, /* M */ |
nkeynes@185 | 156 | 0x80d4, 0x007e0345, /* horizontal border */ |
nkeynes@185 | 157 | 0x80dc, 0x00240204, /* vertical position */ |
nkeynes@185 | 158 | 0x80e0, 0x07d6c63f, /* sync control */ |
nkeynes@185 | 159 | 0x80ec, 0x000000a4, /* horizontal position */ |
nkeynes@185 | 160 | 0x80f0, 0x00120012, /* vertical border */ |
nkeynes@185 | 161 | 0x80c8, 0x03450000, /* set to same as border H in 80d4 */ |
nkeynes@185 | 162 | 0x8068, 0x027f0000, /* (X resolution - 1) << 16 */ |
nkeynes@185 | 163 | 0x806c, 0x01df0000, /* (Y resolution - 1) << 16 */ |
nkeynes@185 | 164 | 0x804c, 0x000000a0, /* display align */ |
nkeynes@185 | 165 | 0x8118, 0x00008040, /* M */ |
nkeynes@185 | 166 | 0x80f4, 0x00000401, /* anti-aliasing */ |
nkeynes@185 | 167 | 0x8048, 0x00000009, /* alpha config */ |
nkeynes@185 | 168 | 0x7814, 0x00000000, /* More interrupt control stuff (so it seems)*/ |
nkeynes@185 | 169 | 0x7834, 0x00000000, |
nkeynes@185 | 170 | 0x7854, 0x00000000, |
nkeynes@185 | 171 | 0x7874, 0x00000000, |
nkeynes@185 | 172 | 0x78bc, 0x4659404f, |
nkeynes@185 | 173 | 0x8040, 0x00000000 /* border color */ |
nkeynes@185 | 174 | }; |
nkeynes@185 | 175 | |
nkeynes@185 | 176 | static void set_regs(unsigned int *values, int cnt) |
nkeynes@185 | 177 | { |
nkeynes@185 | 178 | volatile unsigned char *regs = (volatile unsigned char *)(void *)0xa05f0000; |
nkeynes@185 | 179 | unsigned int r, v; |
nkeynes@185 | 180 | |
nkeynes@185 | 181 | while(cnt--) { |
nkeynes@185 | 182 | r = *values++; |
nkeynes@185 | 183 | v = *values++; |
nkeynes@185 | 184 | *(volatile unsigned int *)(regs+r) = v; |
nkeynes@185 | 185 | } |
nkeynes@185 | 186 | } |
nkeynes@185 | 187 | |
nkeynes@185 | 188 | int pvr_check_cable() |
nkeynes@185 | 189 | { |
nkeynes@185 | 190 | volatile unsigned int *porta = (unsigned int *)0xff80002c; |
nkeynes@185 | 191 | |
nkeynes@185 | 192 | /* PORT8 and PORT9 is input */ |
nkeynes@185 | 193 | *porta = (*porta & ~0xf0000) | 0xa0000; |
nkeynes@185 | 194 | |
nkeynes@185 | 195 | /* Return PORT8 and PORT9 */ |
nkeynes@185 | 196 | return ((*(volatile unsigned short *)(porta+1))>>8)&3; |
nkeynes@185 | 197 | } |
nkeynes@185 | 198 | void pvr_init_video(int cabletype, int mode, int res) |
nkeynes@185 | 199 | { |
nkeynes@185 | 200 | volatile unsigned int *videobase=(volatile unsigned int *)(void*)0xa05f8000; |
nkeynes@185 | 201 | static int bppshifttab[]= { 1,1,0,2 }; |
nkeynes@185 | 202 | int shift, lines, modulo, words_per_line, vpos; |
nkeynes@185 | 203 | int laceoffset=0, voffset=0; |
nkeynes@185 | 204 | unsigned int videoflags, attribs; |
nkeynes@185 | 205 | unsigned int hvcounter = (res<2? 0x01060359 : 0x020c0359); |
nkeynes@185 | 206 | |
nkeynes@185 | 207 | mode &= 3; |
nkeynes@185 | 208 | shift = bppshifttab[mode]; |
nkeynes@185 | 209 | |
nkeynes@185 | 210 | videobase[8/4]=0; |
nkeynes@185 | 211 | videobase[0x40/4]=0; |
nkeynes@185 | 212 | |
nkeynes@185 | 213 | /* Select pixel clock and colour mode */ |
nkeynes@185 | 214 | mode = (mode<<2)|1; |
nkeynes@185 | 215 | lines = 240; |
nkeynes@185 | 216 | if(!(cabletype&2)) { |
nkeynes@185 | 217 | |
nkeynes@185 | 218 | /* VGA mode */ |
nkeynes@185 | 219 | |
nkeynes@185 | 220 | if(res < 2) |
nkeynes@185 | 221 | mode |= 2; /* doublescan */ |
nkeynes@185 | 222 | |
nkeynes@185 | 223 | hvcounter = 0x020c0359; |
nkeynes@185 | 224 | |
nkeynes@185 | 225 | lines <<= 1; |
nkeynes@185 | 226 | mode |= 0x800000; /* fast pixel clock */ |
nkeynes@185 | 227 | } |
nkeynes@185 | 228 | videobase[0x44/4]=mode; |
nkeynes@185 | 229 | |
nkeynes@185 | 230 | /* Set video base address. Short fields will be offset by |
nkeynes@185 | 231 | 640 pixels, regardless of horizontal resolution. */ |
nkeynes@185 | 232 | videobase[0x50/4]=0; |
nkeynes@185 | 233 | videobase[0x54/4]=640<<shift; |
nkeynes@185 | 234 | |
nkeynes@185 | 235 | /* Set screen size, modulo, and interlace flag */ |
nkeynes@185 | 236 | videoflags = 1<<8; |
nkeynes@185 | 237 | if(res==0) |
nkeynes@185 | 238 | words_per_line=(320/4)<<shift; |
nkeynes@185 | 239 | else |
nkeynes@185 | 240 | words_per_line=(640/4)<<shift; |
nkeynes@185 | 241 | modulo = 1; |
nkeynes@185 | 242 | |
nkeynes@185 | 243 | if(!(cabletype&2)) |
nkeynes@185 | 244 | { |
nkeynes@185 | 245 | if(res==0) |
nkeynes@185 | 246 | /* VGA lores -> skip 320 pixels to keep modulo at 640 pixels */ |
nkeynes@185 | 247 | modulo += words_per_line; |
nkeynes@185 | 248 | } else { |
nkeynes@185 | 249 | if(res!=1) |
nkeynes@185 | 250 | /* NTSC lores -> skip 320 pixels to keep modulo at 640 pixels */ |
nkeynes@185 | 251 | /* _or_ NTSC hires -> skip every other line due to interlace */ |
nkeynes@185 | 252 | modulo += words_per_line; |
nkeynes@185 | 253 | |
nkeynes@185 | 254 | if(res==2) |
nkeynes@185 | 255 | /* interlace mode */ |
nkeynes@185 | 256 | videoflags |= 1<<4; |
nkeynes@185 | 257 | |
nkeynes@185 | 258 | /* enable NTSC */ |
nkeynes@185 | 259 | videoflags |= 1<<6; |
nkeynes@185 | 260 | } |
nkeynes@185 | 261 | |
nkeynes@185 | 262 | /* Write screen size and modulo */ |
nkeynes@185 | 263 | videobase[0x5c/4]=(((modulo<<10)+lines-1)<<10)+words_per_line-1; |
nkeynes@185 | 264 | |
nkeynes@185 | 265 | /* Enable video (lace, NTSC) */ |
nkeynes@185 | 266 | videobase[0xd0/4]=videoflags; |
nkeynes@185 | 267 | |
nkeynes@185 | 268 | /* Screen and border position */ |
nkeynes@185 | 269 | |
nkeynes@185 | 270 | if(!(cabletype&2)) |
nkeynes@185 | 271 | /* VGA */ |
nkeynes@185 | 272 | voffset += 36; |
nkeynes@185 | 273 | else |
nkeynes@185 | 274 | voffset += 18; |
nkeynes@185 | 275 | |
nkeynes@185 | 276 | vpos=(voffset<<16)|(voffset+laceoffset); |
nkeynes@185 | 277 | |
nkeynes@185 | 278 | videobase[0xf0/4]=vpos; /* V start */ |
nkeynes@185 | 279 | videobase[0xdc/4]=vpos+lines; /* start and end border */ |
nkeynes@185 | 280 | videobase[0xec/4]=0xa4; /* Horizontal pos */ |
nkeynes@185 | 281 | videobase[0xd8/4]=hvcounter; /* HV counter */ |
nkeynes@185 | 282 | videobase[0xd4/4]=0x007e0345; /* Horizontal border */ |
nkeynes@185 | 283 | |
nkeynes@185 | 284 | /* Select horizontal pixel doubling for lowres */ |
nkeynes@185 | 285 | if(res==0) |
nkeynes@185 | 286 | attribs=((22<<8)+1)<<8; |
nkeynes@185 | 287 | else |
nkeynes@185 | 288 | attribs=22<<16; |
nkeynes@185 | 289 | videobase[0xe8/4]=attribs; |
nkeynes@185 | 290 | |
nkeynes@185 | 291 | /* Set up vertical blank event */ |
nkeynes@185 | 292 | vpos = 260; |
nkeynes@185 | 293 | if(!(cabletype&2)) |
nkeynes@185 | 294 | vpos = 510; |
nkeynes@185 | 295 | videobase[0xcc/4]=(0x21<<16)|vpos; |
nkeynes@185 | 296 | |
nkeynes@185 | 297 | /* Select RGB/CVBS */ |
nkeynes@185 | 298 | if(cabletype&1) |
nkeynes@185 | 299 | mode = 3; |
nkeynes@185 | 300 | else |
nkeynes@185 | 301 | mode = 0; |
nkeynes@185 | 302 | *(volatile unsigned int *)(void*)0xa0702c00 = mode << 8; |
nkeynes@185 | 303 | |
nkeynes@185 | 304 | return; |
nkeynes@185 | 305 | } |
nkeynes@185 | 306 | |
nkeynes@185 | 307 | void pvr_init() |
nkeynes@185 | 308 | { |
nkeynes@185 | 309 | volatile unsigned int *vbl = (volatile unsigned int *)(void *)0xa05f810c; |
nkeynes@185 | 310 | |
nkeynes@185 | 311 | set_regs(three_d_params, sizeof(three_d_params)/sizeof(three_d_params[0])/2); |
nkeynes@185 | 312 | while (!(*vbl & 0x01ff)); |
nkeynes@185 | 313 | while (*vbl & 0x01ff); |
nkeynes@185 | 314 | set_regs(scrn_params, sizeof(scrn_params)/sizeof(scrn_params[0])/2); |
nkeynes@185 | 315 | pvr_init_video(pvr_check_cable(), 1, 2); |
nkeynes@185 | 316 | } |
nkeynes@185 | 317 |
.