nkeynes@185 | 1 | /**
|
nkeynes@561 | 2 | * $Id$
|
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@213 | 33 | #define TA_REINIT (PVR_BASE+0x160)
|
nkeynes@185 | 34 | #define TA_PLISTSTART (PVR_BASE+0x164)
|
nkeynes@185 | 35 |
|
nkeynes@213 | 36 | #define RENDER_START (PVR_BASE+0x014)
|
nkeynes@213 | 37 | #define RENDER_POLYBASE (PVR_BASE+0x020)
|
nkeynes@213 | 38 | #define RENDER_TILEBASE (PVR_BASE+0x02C)
|
nkeynes@213 | 39 | #define RENDER_MODE (PVR_BASE+0x048)
|
nkeynes@213 | 40 | #define RENDER_SIZE (PVR_BASE+0x04C)
|
nkeynes@213 | 41 | #define RENDER_ADDR1 (PVR_BASE+0x060)
|
nkeynes@213 | 42 | #define RENDER_ADDR2 (PVR_BASE+0x064)
|
nkeynes@213 | 43 | #define RENDER_HCLIP (PVR_BASE+0x068)
|
nkeynes@213 | 44 | #define RENDER_VCLIP (PVR_BASE+0x06C)
|
nkeynes@213 | 45 | #define RENDER_NEARCLIP (PVR_BASE+0x078)
|
nkeynes@213 | 46 | #define RENDER_FARCLIP (PVR_BASE+0x088)
|
nkeynes@213 | 47 | #define RENDER_BGPLANE (PVR_BASE+0x08C)
|
nkeynes@213 | 48 |
|
nkeynes@213 | 49 | #define DISPLAY_MODE (PVR_BASE+0x044)
|
nkeynes@213 | 50 | #define DISPLAY_ADDR1 (PVR_BASE+0x050)
|
nkeynes@213 | 51 | #define DISPLAY_ADDR2 (PVR_BASE+0x054)
|
nkeynes@213 | 52 | #define DISPLAY_SIZE (PVR_BASE+0x05C
|
nkeynes@185 | 53 |
|
nkeynes@185 | 54 | void ta_dump_regs( FILE *f )
|
nkeynes@185 | 55 | {
|
nkeynes@185 | 56 | fprintf( stderr, "TA Object start[128]: %08X posn[138]: %08X end[130]: %08X\n",
|
nkeynes@185 | 57 | long_read(TA_OBJSTART), long_read(TA_OBJPOSN), long_read(TA_OBJEND) );
|
nkeynes@185 | 58 | fprintf( stderr, "TA OPB start[124]: %08X posn[134]: %08X end[12c]: %08X init: %08X\n",
|
nkeynes@185 | 59 | long_read(TA_TILESTART), long_read(TA_TILEPOSN), long_read(TA_TILEEND),
|
nkeynes@185 | 60 | long_read(TA_PLISTSTART) );
|
nkeynes@185 | 61 | fprintf( stderr, "TA Tilesize: %08X config: %08X\n", long_read(TA_SIZE), long_read(TA_TILECFG) );
|
nkeynes@185 | 62 | }
|
nkeynes@185 | 63 |
|
nkeynes@190 | 64 |
|
nkeynes@190 | 65 | void ta_init( struct ta_config *config )
|
nkeynes@190 | 66 | {
|
nkeynes@190 | 67 | long_write( PVR_RESET, 1 );
|
nkeynes@190 | 68 | long_write( PVR_RESET, 0 );
|
nkeynes@190 | 69 |
|
nkeynes@190 | 70 | long_write( TA_SIZE, config->grid_size );
|
nkeynes@190 | 71 | long_write( TA_OBJSTART, config->obj_start & 0x00FFFFFF );
|
nkeynes@190 | 72 | long_write( TA_OBJEND, config->obj_end & 0x00FFFFFF );
|
nkeynes@190 | 73 | long_write( TA_TILESTART, config->tile_start & 0x00FFFFFF );
|
nkeynes@190 | 74 | long_write( TA_TILEEND, config->tile_end & 0x00FFFFFF );
|
nkeynes@190 | 75 | long_write( TA_PLISTSTART, config->plist_start & 0x00FFFFFF );
|
nkeynes@190 | 76 | long_write( TA_TILECFG, config->ta_cfg );
|
nkeynes@190 | 77 | long_write( TA_INIT, 0x80000000 );
|
nkeynes@190 | 78 | }
|
nkeynes@190 | 79 |
|
nkeynes@213 | 80 | void ta_reinit( )
|
nkeynes@213 | 81 | {
|
nkeynes@213 | 82 | long_write( TA_REINIT, 0x80000000 );
|
nkeynes@213 | 83 | }
|
nkeynes@213 | 84 |
|
nkeynes@185 | 85 | int pvr_get_objbuf_size( )
|
nkeynes@185 | 86 | {
|
nkeynes@185 | 87 | return long_read( TA_OBJPOSN ) - long_read( TA_OBJSTART );
|
nkeynes@185 | 88 | }
|
nkeynes@185 | 89 |
|
nkeynes@213 | 90 | int pvr_get_objbuf_posn( )
|
nkeynes@213 | 91 | {
|
nkeynes@213 | 92 | return long_read( TA_OBJPOSN );
|
nkeynes@213 | 93 | }
|
nkeynes@213 | 94 |
|
nkeynes@190 | 95 | int pvr_get_plist_posn( )
|
nkeynes@190 | 96 | {
|
nkeynes@190 | 97 | unsigned int addr = long_read( TA_TILEPOSN ) << 2;
|
nkeynes@190 | 98 | return addr;
|
nkeynes@190 | 99 | }
|
nkeynes@190 | 100 |
|
nkeynes@185 | 101 | void pvr_dump_objbuf( FILE *f )
|
nkeynes@185 | 102 | {
|
nkeynes@185 | 103 | unsigned int start = long_read( TA_OBJSTART );
|
nkeynes@185 | 104 | unsigned int posn = long_read( TA_OBJPOSN );
|
nkeynes@185 | 105 | unsigned int end = long_read( TA_OBJEND );
|
nkeynes@185 | 106 | char *buf;
|
nkeynes@185 | 107 | unsigned int length;
|
nkeynes@185 | 108 | if( start < posn ) {
|
nkeynes@185 | 109 | buf = (char *)(0xA5000000+start);
|
nkeynes@185 | 110 | length = posn-start;
|
nkeynes@185 | 111 | } else {
|
nkeynes@185 | 112 | buf = (char *)(0xA5000000+end);
|
nkeynes@185 | 113 | length = start-posn;
|
nkeynes@185 | 114 | }
|
nkeynes@185 | 115 |
|
nkeynes@185 | 116 | fprintf( f, "Obj buffer: %08X - %08X - %08X\n", start, posn, end );
|
nkeynes@185 | 117 | fwrite_dump( f, buf, length );
|
nkeynes@185 | 118 | }
|
nkeynes@185 | 119 |
|
nkeynes@185 | 120 | void pvr_dump_tilebuf( FILE *f )
|
nkeynes@185 | 121 | {
|
nkeynes@185 | 122 | unsigned int start = long_read( TA_TILESTART );
|
nkeynes@185 | 123 | unsigned int posn = long_read( TA_TILEPOSN );
|
nkeynes@185 | 124 | unsigned int end = long_read( TA_TILEEND );
|
nkeynes@185 | 125 | char *buf;
|
nkeynes@185 | 126 | unsigned int length;
|
nkeynes@185 | 127 | if( start < posn ) {
|
nkeynes@185 | 128 | buf = (char *)(0xA5000000+start);
|
nkeynes@185 | 129 | length = posn-start;
|
nkeynes@185 | 130 | } else {
|
nkeynes@185 | 131 | buf = (char *)(0xA5000000+end);
|
nkeynes@185 | 132 | length = start-posn;
|
nkeynes@185 | 133 | }
|
nkeynes@185 | 134 |
|
nkeynes@185 | 135 | fprintf( f, "Tile buffer: %08X - %08X - %08X\n", start, posn, end );
|
nkeynes@185 | 136 | fwrite_dump( f, buf, length );
|
nkeynes@185 | 137 | }
|
nkeynes@185 | 138 |
|
nkeynes@213 | 139 | static int ta_tile_sizes[4] = { 0, 32, 64, 128 };
|
nkeynes@213 | 140 | #define TILE_SIZE(cfg, tile) ta_tile_sizes[((((cfg->ta_cfg) >> (4*tile))&0x03))]
|
nkeynes@213 | 141 | #define TILE_ENABLED(cfg, tile) ((((cfg->ta_cfg) >> (4*tile))&0x03) != 0)
|
nkeynes@213 | 142 | void pvr_compute_tilematrix_addr( int *tile_ptrs, struct ta_config *config ) {
|
nkeynes@213 | 143 | int tile_sizes[5], i;
|
nkeynes@213 | 144 | int hsegs = (config->grid_size & 0xFFFF)+1;
|
nkeynes@213 | 145 | int vsegs = (config->grid_size >> 16) + 1;
|
nkeynes@213 | 146 | for( i=0; i<5; i++ ) {
|
nkeynes@213 | 147 | tile_sizes[i] = TILE_SIZE(config,i);
|
nkeynes@213 | 148 | }
|
nkeynes@213 | 149 | tile_ptrs[0] = config->tile_start;
|
nkeynes@213 | 150 | tile_ptrs[1] = tile_ptrs[0] + (hsegs*vsegs*tile_sizes[0]);
|
nkeynes@213 | 151 | tile_ptrs[2] = tile_ptrs[1] + (hsegs*vsegs*tile_sizes[1]);
|
nkeynes@213 | 152 | tile_ptrs[3] = tile_ptrs[2] + (hsegs*vsegs*tile_sizes[2]);
|
nkeynes@213 | 153 | tile_ptrs[4] = tile_ptrs[3] + (hsegs*vsegs*tile_sizes[3]);
|
nkeynes@213 | 154 | }
|
nkeynes@213 | 155 |
|
nkeynes@213 | 156 | static uint32_t *pvr_compute_tile_ptrs( uint32_t *target, struct ta_config *config, int x, int y )
|
nkeynes@213 | 157 | {
|
nkeynes@213 | 158 | int i;
|
nkeynes@213 | 159 | int cfg = config->ta_cfg;
|
nkeynes@213 | 160 | int hsegs = (config->grid_size & 0xFFFF)+1;
|
nkeynes@213 | 161 | int vsegs = (config->grid_size >> 16) + 1;
|
nkeynes@213 | 162 | int tilematrix = config->tile_start;
|
nkeynes@213 | 163 | for( i=0; i<5; i++ ) {
|
nkeynes@213 | 164 | if( cfg & 0x03 ) {
|
nkeynes@213 | 165 | int tile_size = ta_tile_sizes[cfg&0x03];
|
nkeynes@213 | 166 | *target++ = tilematrix + (((y*hsegs)+x)*tile_size);
|
nkeynes@213 | 167 | tilematrix += hsegs*vsegs*tile_size;
|
nkeynes@213 | 168 | } else {
|
nkeynes@213 | 169 | *target++ = 0x80000000;
|
nkeynes@213 | 170 | }
|
nkeynes@213 | 171 | cfg = cfg >> 4;
|
nkeynes@213 | 172 | }
|
nkeynes@213 | 173 | return target;
|
nkeynes@213 | 174 | }
|
nkeynes@213 | 175 |
|
nkeynes@213 | 176 | void pvr_build_tilemap1( uint32_t addr, struct ta_config *config, uint32_t control_word )
|
nkeynes@213 | 177 | {
|
nkeynes@213 | 178 | uint32_t *dest = (uint32_t *)(PVR_VRAM_BASE+addr);
|
nkeynes@213 | 179 | int w = (config->grid_size & 0x0000FFFF) + 1;
|
nkeynes@213 | 180 | int h = (config->grid_size >> 16) + 1;
|
nkeynes@213 | 181 |
|
nkeynes@213 | 182 | int x,y;
|
nkeynes@213 | 183 | memset( (char *)(dest-18), 0, 18*4 );
|
nkeynes@213 | 184 | *dest++ = 0x10000000;
|
nkeynes@213 | 185 | *dest++ = 0x80000000;
|
nkeynes@213 | 186 | *dest++ = 0x80000000;
|
nkeynes@213 | 187 | *dest++ = 0x80000000;
|
nkeynes@213 | 188 | *dest++ = 0x80000000;
|
nkeynes@213 | 189 | *dest++ = 0x80000000;
|
nkeynes@213 | 190 | for( x=0; x<w; x++ ) {
|
nkeynes@213 | 191 | for( y=0; y<h; y++ ) {
|
nkeynes@213 | 192 | *dest++ = control_word | (y << 8) | (x << 2);
|
nkeynes@213 | 193 | dest = pvr_compute_tile_ptrs(dest, config, x, y);
|
nkeynes@213 | 194 | }
|
nkeynes@213 | 195 | }
|
nkeynes@213 | 196 | dest[-6] |= 0x80000000; /* End-of-render */
|
nkeynes@213 | 197 | }
|
nkeynes@213 | 198 |
|
nkeynes@213 | 199 | void pvr_build_tilemap2( uint32_t addr, struct ta_config *config, uint32_t control_word )
|
nkeynes@213 | 200 | {
|
nkeynes@213 | 201 | uint32_t *dest = (uint32_t *)(PVR_VRAM_BASE+addr);
|
nkeynes@213 | 202 | int w = (config->grid_size & 0x0000FFFF) + 1;
|
nkeynes@213 | 203 | int h = (config->grid_size >> 16) + 1;
|
nkeynes@213 | 204 |
|
nkeynes@213 | 205 | int x,y;
|
nkeynes@213 | 206 | *dest++ = 0x10000000;
|
nkeynes@213 | 207 | *dest++ = 0x80000000;
|
nkeynes@213 | 208 | *dest++ = 0x80000000;
|
nkeynes@213 | 209 | *dest++ = 0x80000000;
|
nkeynes@213 | 210 | *dest++ = 0x80000000;
|
nkeynes@213 | 211 | *dest++ = 0x80000000;
|
nkeynes@213 | 212 | for( x=0; x<w; x++ ) {
|
nkeynes@213 | 213 | for( y=0; y<h; y++ ) {
|
nkeynes@213 | 214 | *dest++ = 0x40000000;
|
nkeynes@213 | 215 | *dest++ = 0x80000000;
|
nkeynes@213 | 216 | *dest++ = 0x80000000;
|
nkeynes@213 | 217 | *dest++ = 0x80000000;
|
nkeynes@213 | 218 | *dest++ = 0x80000000;
|
nkeynes@213 | 219 | *dest++ = 0x80000000;
|
nkeynes@213 | 220 | *dest++ = control_word | (y << 8) | (x << 2);
|
nkeynes@213 | 221 | dest = pvr_compute_tile_ptrs(dest, config, x, y);
|
nkeynes@213 | 222 | }
|
nkeynes@213 | 223 | }
|
nkeynes@213 | 224 | dest[-6] |= 0x80000000; /* End-of-render */
|
nkeynes@213 | 225 | }
|
nkeynes@213 | 226 |
|
nkeynes@213 | 227 | void render_set_backplane( uint32_t mode )
|
nkeynes@213 | 228 | {
|
nkeynes@213 | 229 | long_write( RENDER_BGPLANE, mode );
|
nkeynes@213 | 230 | }
|
nkeynes@213 | 231 |
|
nkeynes@213 | 232 | int get_line_size( struct render_config *config )
|
nkeynes@213 | 233 | {
|
nkeynes@213 | 234 | int modulo = config->width;
|
nkeynes@213 | 235 | switch( config->mode & 0x07 ) {
|
nkeynes@213 | 236 | case 4:
|
nkeynes@213 | 237 | modulo *= 3; /* ??? */
|
nkeynes@213 | 238 | break;
|
nkeynes@213 | 239 | case 5:
|
nkeynes@213 | 240 | case 6:
|
nkeynes@213 | 241 | modulo *= 4;
|
nkeynes@213 | 242 | break;
|
nkeynes@213 | 243 | default:
|
nkeynes@213 | 244 | modulo *= 2;
|
nkeynes@213 | 245 | }
|
nkeynes@213 | 246 | return modulo;
|
nkeynes@213 | 247 | }
|
nkeynes@213 | 248 |
|
nkeynes@213 | 249 | void render_start( struct render_config *config )
|
nkeynes@213 | 250 | {
|
nkeynes@213 | 251 | int modulo = get_line_size( config );
|
nkeynes@213 | 252 | long_write( RENDER_POLYBASE, config->polybuf );
|
nkeynes@213 | 253 | long_write( RENDER_TILEBASE, config->tilemap );
|
nkeynes@213 | 254 | long_write( RENDER_ADDR1, config->render_addr );
|
nkeynes@213 | 255 | long_write( RENDER_SIZE, modulo >> 3 );
|
nkeynes@213 | 256 | long_write( RENDER_ADDR2, config->render_addr + modulo ); /* Not used? */
|
nkeynes@213 | 257 | long_write( RENDER_HCLIP, (config->width - 1) << 16 );
|
nkeynes@213 | 258 | long_write( RENDER_VCLIP, (config->height - 1) << 16 );
|
nkeynes@213 | 259 | long_write( RENDER_MODE, config->mode );
|
nkeynes@213 | 260 | float_write( RENDER_FARCLIP, config->farclip );
|
nkeynes@213 | 261 | float_write( RENDER_NEARCLIP, config->nearclip );
|
nkeynes@213 | 262 | long_write( RENDER_START, 0xFFFFFFFF );
|
nkeynes@213 | 263 | }
|
nkeynes@213 | 264 |
|
nkeynes@213 | 265 | void display_render( struct render_config *config )
|
nkeynes@213 | 266 | {
|
nkeynes@213 | 267 | long_write( DISPLAY_ADDR1, config->render_addr );
|
nkeynes@213 | 268 | long_write( DISPLAY_ADDR2, config->render_addr + get_line_size(config) );
|
nkeynes@213 | 269 | }
|
nkeynes@213 | 270 |
|
nkeynes@185 | 271 | /************** Stolen from TATEST *************/
|
nkeynes@185 | 272 |
|
nkeynes@185 | 273 | static unsigned int three_d_params[] = {
|
nkeynes@185 | 274 | 0x80a8, 0x15d1c951, /* M (Unknown magic value) */
|
nkeynes@185 | 275 | 0x80a0, 0x00000020, /* M */
|
nkeynes@185 | 276 | 0x8008, 0x00000000, /* TA out of reset */
|
nkeynes@185 | 277 | 0x8048, 0x00000009, /* alpha config */
|
nkeynes@185 | 278 | 0x8068, 0x02800000, /* pixel clipping x */
|
nkeynes@185 | 279 | 0x806c, 0x01e00000, /* pixel clipping y */
|
nkeynes@185 | 280 | 0x8110, 0x00093f39, /* M */
|
nkeynes@185 | 281 | 0x8098, 0x00800408, /* M */
|
nkeynes@185 | 282 | 0x804c, 0x000000a0, /* display align (640*2)/8 */
|
nkeynes@185 | 283 | 0x8078, 0x3f800000, /* polygon culling (1.0f) */
|
nkeynes@185 | 284 | 0x8084, 0x00000000, /* M */
|
nkeynes@185 | 285 | 0x8030, 0x00000101, /* M */
|
nkeynes@185 | 286 | 0x80b0, 0x007f7f7f, /* Fog table color */
|
nkeynes@185 | 287 | 0x80b4, 0x007f7f7f, /* Fog vertex color */
|
nkeynes@185 | 288 | 0x80c0, 0x00000000, /* color clamp min */
|
nkeynes@185 | 289 | 0x80bc, 0xffffffff, /* color clamp max */
|
nkeynes@185 | 290 | 0x8080, 0x00000007, /* M */
|
nkeynes@185 | 291 | 0x8074, 0x00000001, /* cheap shadow */
|
nkeynes@185 | 292 | 0x807c, 0x0027df77, /* M */
|
nkeynes@185 | 293 | 0x8008, 0x00000001, /* TA reset */
|
nkeynes@185 | 294 | 0x8008, 0x00000000, /* TA out of reset */
|
nkeynes@185 | 295 | 0x80e4, 0x00000000, /* stride width */
|
nkeynes@185 | 296 | 0x6884, 0x00000000, /* Disable all interrupt events */
|
nkeynes@185 | 297 | 0x6930, 0x00000000,
|
nkeynes@185 | 298 | 0x6938, 0x00000000,
|
nkeynes@185 | 299 | 0x6900, 0xffffffff, /* Clear all pending int events */
|
nkeynes@185 | 300 | 0x6908, 0xffffffff,
|
nkeynes@185 | 301 | 0x6930, 0x002807ec, /* Re-enable some events */
|
nkeynes@185 | 302 | 0x6938, 0x0000000e,
|
nkeynes@185 | 303 | 0x80b8, 0x0000ff07, /* fog density */
|
nkeynes@185 | 304 | 0x80b4, 0x007f7f7f, /* fog vertex color */
|
nkeynes@185 | 305 | 0x80b0, 0x007f7f7f, /* fog table color */
|
nkeynes@185 | 306 | 0x8108, 0x00000003 /* 32bit palette */
|
nkeynes@185 | 307 | };
|
nkeynes@185 | 308 |
|
nkeynes@185 | 309 | static unsigned int scrn_params[] = {
|
nkeynes@185 | 310 | 0x80e8, 0x00160000, /* screen control */
|
nkeynes@185 | 311 | 0x8044, 0x00800000, /* pixel mode (vb+0x11) */
|
nkeynes@185 | 312 | 0x805c, 0x00000000, /* Size modulo and display lines (vb+0x17) */
|
nkeynes@185 | 313 | 0x80d0, 0x00000100, /* interlace flags */
|
nkeynes@185 | 314 | 0x80d8, 0x020c0359, /* M */
|
nkeynes@185 | 315 | 0x80cc, 0x001501fe, /* M */
|
nkeynes@185 | 316 | 0x80d4, 0x007e0345, /* horizontal border */
|
nkeynes@185 | 317 | 0x80dc, 0x00240204, /* vertical position */
|
nkeynes@185 | 318 | 0x80e0, 0x07d6c63f, /* sync control */
|
nkeynes@185 | 319 | 0x80ec, 0x000000a4, /* horizontal position */
|
nkeynes@185 | 320 | 0x80f0, 0x00120012, /* vertical border */
|
nkeynes@185 | 321 | 0x80c8, 0x03450000, /* set to same as border H in 80d4 */
|
nkeynes@185 | 322 | 0x8068, 0x027f0000, /* (X resolution - 1) << 16 */
|
nkeynes@185 | 323 | 0x806c, 0x01df0000, /* (Y resolution - 1) << 16 */
|
nkeynes@185 | 324 | 0x804c, 0x000000a0, /* display align */
|
nkeynes@185 | 325 | 0x8118, 0x00008040, /* M */
|
nkeynes@185 | 326 | 0x80f4, 0x00000401, /* anti-aliasing */
|
nkeynes@185 | 327 | 0x8048, 0x00000009, /* alpha config */
|
nkeynes@185 | 328 | 0x7814, 0x00000000, /* More interrupt control stuff (so it seems)*/
|
nkeynes@185 | 329 | 0x7834, 0x00000000,
|
nkeynes@185 | 330 | 0x7854, 0x00000000,
|
nkeynes@185 | 331 | 0x7874, 0x00000000,
|
nkeynes@185 | 332 | 0x78bc, 0x4659404f,
|
nkeynes@185 | 333 | 0x8040, 0x00000000 /* border color */
|
nkeynes@185 | 334 | };
|
nkeynes@185 | 335 |
|
nkeynes@185 | 336 | static void set_regs(unsigned int *values, int cnt)
|
nkeynes@185 | 337 | {
|
nkeynes@185 | 338 | volatile unsigned char *regs = (volatile unsigned char *)(void *)0xa05f0000;
|
nkeynes@185 | 339 | unsigned int r, v;
|
nkeynes@185 | 340 |
|
nkeynes@185 | 341 | while(cnt--) {
|
nkeynes@185 | 342 | r = *values++;
|
nkeynes@185 | 343 | v = *values++;
|
nkeynes@185 | 344 | *(volatile unsigned int *)(regs+r) = v;
|
nkeynes@185 | 345 | }
|
nkeynes@185 | 346 | }
|
nkeynes@185 | 347 |
|
nkeynes@185 | 348 | int pvr_check_cable()
|
nkeynes@185 | 349 | {
|
nkeynes@185 | 350 | volatile unsigned int *porta = (unsigned int *)0xff80002c;
|
nkeynes@185 | 351 |
|
nkeynes@185 | 352 | /* PORT8 and PORT9 is input */
|
nkeynes@185 | 353 | *porta = (*porta & ~0xf0000) | 0xa0000;
|
nkeynes@185 | 354 |
|
nkeynes@185 | 355 | /* Return PORT8 and PORT9 */
|
nkeynes@185 | 356 | return ((*(volatile unsigned short *)(porta+1))>>8)&3;
|
nkeynes@185 | 357 | }
|
nkeynes@185 | 358 | void pvr_init_video(int cabletype, int mode, int res)
|
nkeynes@185 | 359 | {
|
nkeynes@185 | 360 | volatile unsigned int *videobase=(volatile unsigned int *)(void*)0xa05f8000;
|
nkeynes@185 | 361 | static int bppshifttab[]= { 1,1,0,2 };
|
nkeynes@185 | 362 | int shift, lines, modulo, words_per_line, vpos;
|
nkeynes@185 | 363 | int laceoffset=0, voffset=0;
|
nkeynes@185 | 364 | unsigned int videoflags, attribs;
|
nkeynes@185 | 365 | unsigned int hvcounter = (res<2? 0x01060359 : 0x020c0359);
|
nkeynes@185 | 366 |
|
nkeynes@185 | 367 | mode &= 3;
|
nkeynes@185 | 368 | shift = bppshifttab[mode];
|
nkeynes@185 | 369 |
|
nkeynes@185 | 370 | videobase[8/4]=0;
|
nkeynes@185 | 371 | videobase[0x40/4]=0;
|
nkeynes@185 | 372 |
|
nkeynes@185 | 373 | /* Select pixel clock and colour mode */
|
nkeynes@185 | 374 | mode = (mode<<2)|1;
|
nkeynes@185 | 375 | lines = 240;
|
nkeynes@185 | 376 | if(!(cabletype&2)) {
|
nkeynes@185 | 377 |
|
nkeynes@185 | 378 | /* VGA mode */
|
nkeynes@185 | 379 |
|
nkeynes@185 | 380 | if(res < 2)
|
nkeynes@185 | 381 | mode |= 2; /* doublescan */
|
nkeynes@185 | 382 |
|
nkeynes@185 | 383 | hvcounter = 0x020c0359;
|
nkeynes@185 | 384 |
|
nkeynes@185 | 385 | lines <<= 1;
|
nkeynes@185 | 386 | mode |= 0x800000; /* fast pixel clock */
|
nkeynes@185 | 387 | }
|
nkeynes@185 | 388 | videobase[0x44/4]=mode;
|
nkeynes@185 | 389 |
|
nkeynes@185 | 390 | /* Set video base address. Short fields will be offset by
|
nkeynes@185 | 391 | 640 pixels, regardless of horizontal resolution. */
|
nkeynes@185 | 392 | videobase[0x50/4]=0;
|
nkeynes@185 | 393 | videobase[0x54/4]=640<<shift;
|
nkeynes@185 | 394 |
|
nkeynes@185 | 395 | /* Set screen size, modulo, and interlace flag */
|
nkeynes@185 | 396 | videoflags = 1<<8;
|
nkeynes@185 | 397 | if(res==0)
|
nkeynes@185 | 398 | words_per_line=(320/4)<<shift;
|
nkeynes@185 | 399 | else
|
nkeynes@185 | 400 | words_per_line=(640/4)<<shift;
|
nkeynes@185 | 401 | modulo = 1;
|
nkeynes@185 | 402 |
|
nkeynes@185 | 403 | if(!(cabletype&2))
|
nkeynes@185 | 404 | {
|
nkeynes@185 | 405 | if(res==0)
|
nkeynes@185 | 406 | /* VGA lores -> skip 320 pixels to keep modulo at 640 pixels */
|
nkeynes@185 | 407 | modulo += words_per_line;
|
nkeynes@185 | 408 | } else {
|
nkeynes@185 | 409 | if(res!=1)
|
nkeynes@185 | 410 | /* NTSC lores -> skip 320 pixels to keep modulo at 640 pixels */
|
nkeynes@185 | 411 | /* _or_ NTSC hires -> skip every other line due to interlace */
|
nkeynes@185 | 412 | modulo += words_per_line;
|
nkeynes@185 | 413 |
|
nkeynes@185 | 414 | if(res==2)
|
nkeynes@185 | 415 | /* interlace mode */
|
nkeynes@185 | 416 | videoflags |= 1<<4;
|
nkeynes@185 | 417 |
|
nkeynes@185 | 418 | /* enable NTSC */
|
nkeynes@185 | 419 | videoflags |= 1<<6;
|
nkeynes@185 | 420 | }
|
nkeynes@185 | 421 |
|
nkeynes@185 | 422 | /* Write screen size and modulo */
|
nkeynes@185 | 423 | videobase[0x5c/4]=(((modulo<<10)+lines-1)<<10)+words_per_line-1;
|
nkeynes@185 | 424 |
|
nkeynes@185 | 425 | /* Enable video (lace, NTSC) */
|
nkeynes@185 | 426 | videobase[0xd0/4]=videoflags;
|
nkeynes@185 | 427 |
|
nkeynes@185 | 428 | /* Screen and border position */
|
nkeynes@185 | 429 |
|
nkeynes@185 | 430 | if(!(cabletype&2))
|
nkeynes@185 | 431 | /* VGA */
|
nkeynes@185 | 432 | voffset += 36;
|
nkeynes@185 | 433 | else
|
nkeynes@185 | 434 | voffset += 18;
|
nkeynes@185 | 435 |
|
nkeynes@185 | 436 | vpos=(voffset<<16)|(voffset+laceoffset);
|
nkeynes@185 | 437 |
|
nkeynes@185 | 438 | videobase[0xf0/4]=vpos; /* V start */
|
nkeynes@185 | 439 | videobase[0xdc/4]=vpos+lines; /* start and end border */
|
nkeynes@185 | 440 | videobase[0xec/4]=0xa4; /* Horizontal pos */
|
nkeynes@185 | 441 | videobase[0xd8/4]=hvcounter; /* HV counter */
|
nkeynes@185 | 442 | videobase[0xd4/4]=0x007e0345; /* Horizontal border */
|
nkeynes@185 | 443 |
|
nkeynes@185 | 444 | /* Select horizontal pixel doubling for lowres */
|
nkeynes@185 | 445 | if(res==0)
|
nkeynes@185 | 446 | attribs=((22<<8)+1)<<8;
|
nkeynes@185 | 447 | else
|
nkeynes@185 | 448 | attribs=22<<16;
|
nkeynes@185 | 449 | videobase[0xe8/4]=attribs;
|
nkeynes@185 | 450 |
|
nkeynes@185 | 451 | /* Set up vertical blank event */
|
nkeynes@185 | 452 | vpos = 260;
|
nkeynes@185 | 453 | if(!(cabletype&2))
|
nkeynes@185 | 454 | vpos = 510;
|
nkeynes@185 | 455 | videobase[0xcc/4]=(0x21<<16)|vpos;
|
nkeynes@185 | 456 |
|
nkeynes@185 | 457 | /* Select RGB/CVBS */
|
nkeynes@185 | 458 | if(cabletype&1)
|
nkeynes@185 | 459 | mode = 3;
|
nkeynes@185 | 460 | else
|
nkeynes@185 | 461 | mode = 0;
|
nkeynes@185 | 462 | *(volatile unsigned int *)(void*)0xa0702c00 = mode << 8;
|
nkeynes@185 | 463 |
|
nkeynes@185 | 464 | return;
|
nkeynes@185 | 465 | }
|
nkeynes@185 | 466 |
|
nkeynes@185 | 467 | void pvr_init()
|
nkeynes@185 | 468 | {
|
nkeynes@185 | 469 | volatile unsigned int *vbl = (volatile unsigned int *)(void *)0xa05f810c;
|
nkeynes@185 | 470 |
|
nkeynes@185 | 471 | set_regs(three_d_params, sizeof(three_d_params)/sizeof(three_d_params[0])/2);
|
nkeynes@185 | 472 | while (!(*vbl & 0x01ff));
|
nkeynes@185 | 473 | while (*vbl & 0x01ff);
|
nkeynes@185 | 474 | set_regs(scrn_params, sizeof(scrn_params)/sizeof(scrn_params[0])/2);
|
nkeynes@185 | 475 | pvr_init_video(pvr_check_cable(), 1, 2);
|
nkeynes@185 | 476 | }
|
nkeynes@185 | 477 |
|
nkeynes@306 | 478 | void draw_grid( unsigned short *addr, unsigned short colour )
|
nkeynes@306 | 479 | {
|
nkeynes@306 | 480 | int x,y;
|
nkeynes@306 | 481 | unsigned int linesize = 640;
|
nkeynes@306 | 482 | for( x=0; x<640; x+=32 ) {
|
nkeynes@306 | 483 | for( y=0; y<480; y++ ) {
|
nkeynes@306 | 484 | addr[(linesize*y) + x] = colour;
|
nkeynes@306 | 485 | }
|
nkeynes@306 | 486 | }
|
nkeynes@306 | 487 | for( y=0; y<480; y+=32 ) {
|
nkeynes@306 | 488 | for( x=0; x<640; x++ ) {
|
nkeynes@306 | 489 | addr[(linesize*y) + x] = colour;
|
nkeynes@306 | 490 | }
|
nkeynes@306 | 491 | }
|
nkeynes@320 | 492 | }
|
nkeynes@306 | 493 |
|
nkeynes@320 | 494 | void draw_grid_24( unsigned char *addr, unsigned int colour )
|
nkeynes@320 | 495 | {
|
nkeynes@320 | 496 | int x,y;
|
nkeynes@320 | 497 | char r = (colour >> 16) & 0xFF;
|
nkeynes@320 | 498 | char g = (colour >> 8) & 0xFF;
|
nkeynes@320 | 499 | char b = (colour & 0xFF);
|
nkeynes@320 | 500 | unsigned int linesize = 640*3;
|
nkeynes@320 | 501 | for( x=0; x<640; x+=32 ) {
|
nkeynes@320 | 502 | for( y=0; y<480; y++ ) {
|
nkeynes@320 | 503 | int a = (linesize*y)+x * 3;
|
nkeynes@320 | 504 | addr[a++] = r;
|
nkeynes@320 | 505 | addr[a++] = g;
|
nkeynes@320 | 506 | addr[a++] = b;
|
nkeynes@320 | 507 | }
|
nkeynes@320 | 508 | }
|
nkeynes@320 | 509 | for( y=0; y<480; y+=32 ) {
|
nkeynes@320 | 510 | for( x=0; x<640; x++ ) {
|
nkeynes@320 | 511 | int a = (linesize*y)+x * 3;
|
nkeynes@320 | 512 | addr[a++] = r;
|
nkeynes@320 | 513 | addr[a++] = g;
|
nkeynes@320 | 514 | addr[a++] = b;
|
nkeynes@320 | 515 | }
|
nkeynes@320 | 516 | }
|
nkeynes@306 | 517 | }
|