filename | src/pvr2/pvr2.c |
changeset | 337:cdd757aa8e8c |
prev | 335:fb890e1814c0 |
next | 352:f0df7a6d4703 |
author | nkeynes |
date | Mon Jan 29 11:24:44 2007 +0000 (17 years ago) |
permissions | -rw-r--r-- |
last change | Get render size from the tile segment array Set near clip to just 0 rather than scanning the scene Fixup modulate RGB to force fragment alpha to 1.0 Add some debugging fprintfs |
file | annotate | diff | log | raw |
nkeynes@31 | 1 | /** |
nkeynes@337 | 2 | * $Id: pvr2.c,v 1.43 2007-01-28 11:36:00 nkeynes Exp $ |
nkeynes@31 | 3 | * |
nkeynes@133 | 4 | * PVR2 (Video) Core module implementation and MMIO registers. |
nkeynes@31 | 5 | * |
nkeynes@31 | 6 | * Copyright (c) 2005 Nathan Keynes. |
nkeynes@31 | 7 | * |
nkeynes@31 | 8 | * This program is free software; you can redistribute it and/or modify |
nkeynes@31 | 9 | * it under the terms of the GNU General Public License as published by |
nkeynes@31 | 10 | * the Free Software Foundation; either version 2 of the License, or |
nkeynes@31 | 11 | * (at your option) any later version. |
nkeynes@31 | 12 | * |
nkeynes@31 | 13 | * This program is distributed in the hope that it will be useful, |
nkeynes@31 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
nkeynes@31 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
nkeynes@31 | 16 | * GNU General Public License for more details. |
nkeynes@31 | 17 | */ |
nkeynes@35 | 18 | #define MODULE pvr2_module |
nkeynes@31 | 19 | |
nkeynes@1 | 20 | #include "dream.h" |
nkeynes@265 | 21 | #include "eventq.h" |
nkeynes@144 | 22 | #include "display.h" |
nkeynes@1 | 23 | #include "mem.h" |
nkeynes@1 | 24 | #include "asic.h" |
nkeynes@261 | 25 | #include "clock.h" |
nkeynes@103 | 26 | #include "pvr2/pvr2.h" |
nkeynes@56 | 27 | #include "sh4/sh4core.h" |
nkeynes@1 | 28 | #define MMIO_IMPL |
nkeynes@103 | 29 | #include "pvr2/pvr2mmio.h" |
nkeynes@1 | 30 | |
nkeynes@1 | 31 | char *video_base; |
nkeynes@1 | 32 | |
nkeynes@304 | 33 | #define HPOS_PER_FRAME 0 |
nkeynes@304 | 34 | #define HPOS_PER_LINECOUNT 1 |
nkeynes@304 | 35 | |
nkeynes@133 | 36 | static void pvr2_init( void ); |
nkeynes@133 | 37 | static void pvr2_reset( void ); |
nkeynes@133 | 38 | static uint32_t pvr2_run_slice( uint32_t ); |
nkeynes@133 | 39 | static void pvr2_save_state( FILE *f ); |
nkeynes@133 | 40 | static int pvr2_load_state( FILE *f ); |
nkeynes@265 | 41 | static void pvr2_update_raster_posn( uint32_t nanosecs ); |
nkeynes@304 | 42 | static void pvr2_schedule_scanline_event( int eventid, int line, int minimum_lines, int line_time_ns ); |
nkeynes@265 | 43 | uint32_t pvr2_get_sync_status(); |
nkeynes@133 | 44 | |
nkeynes@94 | 45 | void pvr2_display_frame( void ); |
nkeynes@94 | 46 | |
nkeynes@161 | 47 | int colour_format_bytes[] = { 2, 2, 2, 1, 3, 4, 1, 1 }; |
nkeynes@161 | 48 | |
nkeynes@133 | 49 | struct dreamcast_module pvr2_module = { "PVR2", pvr2_init, pvr2_reset, NULL, |
nkeynes@133 | 50 | pvr2_run_slice, NULL, |
nkeynes@133 | 51 | pvr2_save_state, pvr2_load_state }; |
nkeynes@133 | 52 | |
nkeynes@103 | 53 | |
nkeynes@144 | 54 | display_driver_t display_driver = NULL; |
nkeynes@15 | 55 | |
nkeynes@103 | 56 | struct video_timing { |
nkeynes@103 | 57 | int fields_per_second; |
nkeynes@103 | 58 | int total_lines; |
nkeynes@108 | 59 | int retrace_lines; |
nkeynes@103 | 60 | int line_time_ns; |
nkeynes@103 | 61 | }; |
nkeynes@103 | 62 | |
nkeynes@261 | 63 | struct video_timing pal_timing = { 50, 625, 65, 31945 }; |
nkeynes@108 | 64 | struct video_timing ntsc_timing= { 60, 525, 65, 31746 }; |
nkeynes@103 | 65 | |
nkeynes@133 | 66 | struct pvr2_state { |
nkeynes@133 | 67 | uint32_t frame_count; |
nkeynes@133 | 68 | uint32_t line_count; |
nkeynes@133 | 69 | uint32_t line_remainder; |
nkeynes@265 | 70 | uint32_t cycles_run; /* Cycles already executed prior to main time slice */ |
nkeynes@304 | 71 | uint32_t irq_hpos_line; |
nkeynes@304 | 72 | uint32_t irq_hpos_line_count; |
nkeynes@304 | 73 | uint32_t irq_hpos_mode; |
nkeynes@304 | 74 | uint32_t irq_hpos_time_ns; /* Time within the line */ |
nkeynes@133 | 75 | uint32_t irq_vpos1; |
nkeynes@133 | 76 | uint32_t irq_vpos2; |
nkeynes@261 | 77 | uint32_t odd_even_field; /* 1 = odd, 0 = even */ |
nkeynes@337 | 78 | gboolean palette_changed; /* TRUE if palette has changed since last render */ |
nkeynes@295 | 79 | gchar *save_next_render_filename; |
nkeynes@261 | 80 | /* timing */ |
nkeynes@261 | 81 | uint32_t dot_clock; |
nkeynes@261 | 82 | uint32_t total_lines; |
nkeynes@261 | 83 | uint32_t line_size; |
nkeynes@261 | 84 | uint32_t line_time_ns; |
nkeynes@261 | 85 | uint32_t vsync_lines; |
nkeynes@261 | 86 | uint32_t hsync_width_ns; |
nkeynes@261 | 87 | uint32_t front_porch_ns; |
nkeynes@261 | 88 | uint32_t back_porch_ns; |
nkeynes@265 | 89 | uint32_t retrace_start_line; |
nkeynes@265 | 90 | uint32_t retrace_end_line; |
nkeynes@261 | 91 | gboolean interlaced; |
nkeynes@133 | 92 | struct video_timing timing; |
nkeynes@133 | 93 | } pvr2_state; |
nkeynes@15 | 94 | |
nkeynes@133 | 95 | struct video_buffer video_buffer[2]; |
nkeynes@133 | 96 | int video_buffer_idx = 0; |
nkeynes@133 | 97 | |
nkeynes@265 | 98 | /** |
nkeynes@304 | 99 | * Event handler for the hpos callback |
nkeynes@265 | 100 | */ |
nkeynes@304 | 101 | static void pvr2_hpos_callback( int eventid ) { |
nkeynes@265 | 102 | asic_event( eventid ); |
nkeynes@265 | 103 | pvr2_update_raster_posn(sh4r.slice_cycle); |
nkeynes@304 | 104 | if( pvr2_state.irq_hpos_mode == HPOS_PER_LINECOUNT ) { |
nkeynes@304 | 105 | pvr2_state.irq_hpos_line += pvr2_state.irq_hpos_line_count; |
nkeynes@304 | 106 | while( pvr2_state.irq_hpos_line > (pvr2_state.total_lines>>1) ) { |
nkeynes@304 | 107 | pvr2_state.irq_hpos_line -= (pvr2_state.total_lines>>1); |
nkeynes@304 | 108 | } |
nkeynes@304 | 109 | } |
nkeynes@304 | 110 | pvr2_schedule_scanline_event( eventid, pvr2_state.irq_hpos_line, 1, |
nkeynes@304 | 111 | pvr2_state.irq_hpos_time_ns ); |
nkeynes@265 | 112 | } |
nkeynes@265 | 113 | |
nkeynes@265 | 114 | /** |
nkeynes@265 | 115 | * Event handler for the scanline callbacks. Fires the corresponding |
nkeynes@265 | 116 | * ASIC event, and resets the timer for the next field. |
nkeynes@265 | 117 | */ |
nkeynes@265 | 118 | static void pvr2_scanline_callback( int eventid ) { |
nkeynes@265 | 119 | asic_event( eventid ); |
nkeynes@265 | 120 | pvr2_update_raster_posn(sh4r.slice_cycle); |
nkeynes@265 | 121 | if( eventid == EVENT_SCANLINE1 ) { |
nkeynes@304 | 122 | pvr2_schedule_scanline_event( eventid, pvr2_state.irq_vpos1, 1, 0 ); |
nkeynes@265 | 123 | } else { |
nkeynes@304 | 124 | pvr2_schedule_scanline_event( eventid, pvr2_state.irq_vpos2, 1, 0 ); |
nkeynes@265 | 125 | } |
nkeynes@265 | 126 | } |
nkeynes@265 | 127 | |
nkeynes@133 | 128 | static void pvr2_init( void ) |
nkeynes@1 | 129 | { |
nkeynes@1 | 130 | register_io_region( &mmio_region_PVR2 ); |
nkeynes@85 | 131 | register_io_region( &mmio_region_PVR2PAL ); |
nkeynes@56 | 132 | register_io_region( &mmio_region_PVR2TA ); |
nkeynes@304 | 133 | register_event_callback( EVENT_HPOS, pvr2_hpos_callback ); |
nkeynes@265 | 134 | register_event_callback( EVENT_SCANLINE1, pvr2_scanline_callback ); |
nkeynes@265 | 135 | register_event_callback( EVENT_SCANLINE2, pvr2_scanline_callback ); |
nkeynes@1 | 136 | video_base = mem_get_region_by_name( MEM_REGION_VIDEO ); |
nkeynes@133 | 137 | texcache_init(); |
nkeynes@133 | 138 | pvr2_reset(); |
nkeynes@214 | 139 | pvr2_ta_reset(); |
nkeynes@295 | 140 | pvr2_state.save_next_render_filename = NULL; |
nkeynes@133 | 141 | } |
nkeynes@133 | 142 | |
nkeynes@133 | 143 | static void pvr2_reset( void ) |
nkeynes@133 | 144 | { |
nkeynes@133 | 145 | pvr2_state.line_count = 0; |
nkeynes@133 | 146 | pvr2_state.line_remainder = 0; |
nkeynes@265 | 147 | pvr2_state.cycles_run = 0; |
nkeynes@133 | 148 | pvr2_state.irq_vpos1 = 0; |
nkeynes@133 | 149 | pvr2_state.irq_vpos2 = 0; |
nkeynes@133 | 150 | pvr2_state.timing = ntsc_timing; |
nkeynes@265 | 151 | pvr2_state.dot_clock = PVR2_DOT_CLOCK; |
nkeynes@265 | 152 | pvr2_state.back_porch_ns = 4000; |
nkeynes@337 | 153 | pvr2_state.palette_changed = FALSE; |
nkeynes@265 | 154 | mmio_region_PVR2_write( DISP_TOTAL, 0x0270035F ); |
nkeynes@265 | 155 | mmio_region_PVR2_write( DISP_SYNCTIME, 0x07D6A53F ); |
nkeynes@284 | 156 | mmio_region_PVR2_write( YUV_ADDR, 0 ); |
nkeynes@284 | 157 | mmio_region_PVR2_write( YUV_CFG, 0 ); |
nkeynes@133 | 158 | video_buffer_idx = 0; |
nkeynes@133 | 159 | |
nkeynes@133 | 160 | pvr2_ta_init(); |
nkeynes@107 | 161 | pvr2_render_init(); |
nkeynes@133 | 162 | texcache_flush(); |
nkeynes@133 | 163 | } |
nkeynes@133 | 164 | |
nkeynes@133 | 165 | static void pvr2_save_state( FILE *f ) |
nkeynes@133 | 166 | { |
nkeynes@133 | 167 | fwrite( &pvr2_state, sizeof(pvr2_state), 1, f ); |
nkeynes@193 | 168 | pvr2_ta_save_state( f ); |
nkeynes@295 | 169 | pvr2_yuv_save_state( f ); |
nkeynes@133 | 170 | } |
nkeynes@133 | 171 | |
nkeynes@133 | 172 | static int pvr2_load_state( FILE *f ) |
nkeynes@133 | 173 | { |
nkeynes@153 | 174 | if( fread( &pvr2_state, sizeof(pvr2_state), 1, f ) != 1 ) |
nkeynes@153 | 175 | return 1; |
nkeynes@295 | 176 | if( pvr2_ta_load_state(f) ) { |
nkeynes@295 | 177 | return 1; |
nkeynes@295 | 178 | } |
nkeynes@295 | 179 | return pvr2_yuv_load_state(f); |
nkeynes@133 | 180 | } |
nkeynes@133 | 181 | |
nkeynes@265 | 182 | /** |
nkeynes@265 | 183 | * Update the current raster position to the given number of nanoseconds, |
nkeynes@265 | 184 | * relative to the last time slice. (ie the raster will be adjusted forward |
nkeynes@265 | 185 | * by nanosecs - nanosecs_already_run_this_timeslice) |
nkeynes@265 | 186 | */ |
nkeynes@265 | 187 | static void pvr2_update_raster_posn( uint32_t nanosecs ) |
nkeynes@265 | 188 | { |
nkeynes@265 | 189 | uint32_t old_line_count = pvr2_state.line_count; |
nkeynes@265 | 190 | if( pvr2_state.line_time_ns == 0 ) { |
nkeynes@265 | 191 | return; /* do nothing */ |
nkeynes@265 | 192 | } |
nkeynes@265 | 193 | pvr2_state.line_remainder += (nanosecs - pvr2_state.cycles_run); |
nkeynes@265 | 194 | pvr2_state.cycles_run = nanosecs; |
nkeynes@265 | 195 | while( pvr2_state.line_remainder >= pvr2_state.line_time_ns ) { |
nkeynes@265 | 196 | pvr2_state.line_count ++; |
nkeynes@265 | 197 | pvr2_state.line_remainder -= pvr2_state.line_time_ns; |
nkeynes@265 | 198 | } |
nkeynes@265 | 199 | |
nkeynes@265 | 200 | if( pvr2_state.line_count >= pvr2_state.total_lines ) { |
nkeynes@265 | 201 | pvr2_state.line_count -= pvr2_state.total_lines; |
nkeynes@265 | 202 | if( pvr2_state.interlaced ) { |
nkeynes@265 | 203 | pvr2_state.odd_even_field = !pvr2_state.odd_even_field; |
nkeynes@265 | 204 | } |
nkeynes@265 | 205 | } |
nkeynes@265 | 206 | if( pvr2_state.line_count >= pvr2_state.retrace_end_line && |
nkeynes@265 | 207 | (old_line_count < pvr2_state.retrace_end_line || |
nkeynes@265 | 208 | old_line_count > pvr2_state.line_count) ) { |
nkeynes@337 | 209 | pvr2_state.frame_count++; |
nkeynes@265 | 210 | pvr2_display_frame(); |
nkeynes@265 | 211 | } |
nkeynes@265 | 212 | } |
nkeynes@265 | 213 | |
nkeynes@133 | 214 | static uint32_t pvr2_run_slice( uint32_t nanosecs ) |
nkeynes@133 | 215 | { |
nkeynes@265 | 216 | pvr2_update_raster_posn( nanosecs ); |
nkeynes@265 | 217 | pvr2_state.cycles_run = 0; |
nkeynes@133 | 218 | return nanosecs; |
nkeynes@133 | 219 | } |
nkeynes@133 | 220 | |
nkeynes@133 | 221 | int pvr2_get_frame_count() |
nkeynes@133 | 222 | { |
nkeynes@133 | 223 | return pvr2_state.frame_count; |
nkeynes@106 | 224 | } |
nkeynes@106 | 225 | |
nkeynes@295 | 226 | gboolean pvr2_save_next_scene( const gchar *filename ) |
nkeynes@295 | 227 | { |
nkeynes@295 | 228 | if( pvr2_state.save_next_render_filename != NULL ) { |
nkeynes@295 | 229 | g_free( pvr2_state.save_next_render_filename ); |
nkeynes@295 | 230 | } |
nkeynes@295 | 231 | pvr2_state.save_next_render_filename = g_strdup(filename); |
nkeynes@295 | 232 | return TRUE; |
nkeynes@295 | 233 | } |
nkeynes@295 | 234 | |
nkeynes@295 | 235 | |
nkeynes@295 | 236 | |
nkeynes@103 | 237 | /** |
nkeynes@1 | 238 | * Display the next frame, copying the current contents of video ram to |
nkeynes@1 | 239 | * the window. If the video configuration has changed, first recompute the |
nkeynes@1 | 240 | * new frame size/depth. |
nkeynes@1 | 241 | */ |
nkeynes@94 | 242 | void pvr2_display_frame( void ) |
nkeynes@1 | 243 | { |
nkeynes@335 | 244 | uint32_t display_addr; |
nkeynes@197 | 245 | int dispsize = MMIO_READ( PVR2, DISP_SIZE ); |
nkeynes@197 | 246 | int dispmode = MMIO_READ( PVR2, DISP_MODE ); |
nkeynes@261 | 247 | int vidcfg = MMIO_READ( PVR2, DISP_SYNCCFG ); |
nkeynes@335 | 248 | int vid_stride = (((dispsize & DISPSIZE_MODULO) >> 20) - 1); |
nkeynes@94 | 249 | int vid_lpf = ((dispsize & DISPSIZE_LPF) >> 10) + 1; |
nkeynes@94 | 250 | int vid_ppl = ((dispsize & DISPSIZE_PPL)) + 1; |
nkeynes@335 | 251 | gboolean bEnabled = (dispmode & DISPMODE_ENABLE) && (vidcfg & DISPCFG_VO ) ? TRUE : FALSE; |
nkeynes@103 | 252 | gboolean interlaced = (vidcfg & DISPCFG_I ? TRUE : FALSE); |
nkeynes@161 | 253 | video_buffer_t buffer = &video_buffer[video_buffer_idx]; |
nkeynes@161 | 254 | video_buffer_idx = !video_buffer_idx; |
nkeynes@161 | 255 | video_buffer_t last = &video_buffer[video_buffer_idx]; |
nkeynes@161 | 256 | buffer->rowstride = (vid_ppl + vid_stride) << 2; |
nkeynes@197 | 257 | buffer->data = video_base + MMIO_READ( PVR2, DISP_ADDR1 ); |
nkeynes@335 | 258 | buffer->line_double = (dispmode & DISPMODE_LINEDOUBLE) ? TRUE : FALSE; |
nkeynes@161 | 259 | buffer->vres = vid_lpf; |
nkeynes@335 | 260 | if( interlaced ) { |
nkeynes@335 | 261 | if( vid_ppl == vid_stride ) { /* Magic deinterlace */ |
nkeynes@335 | 262 | buffer->vres <<= 1; |
nkeynes@335 | 263 | buffer->rowstride = vid_ppl << 2; |
nkeynes@335 | 264 | display_addr = MMIO_READ( PVR2, DISP_ADDR1 ); |
nkeynes@337 | 265 | } else { |
nkeynes@337 | 266 | /* Just display the field as is, folks. This is slightly tricky - |
nkeynes@337 | 267 | * we pick the field based on which frame is about to come through, |
nkeynes@337 | 268 | * which may not be the same as the odd_even_field. |
nkeynes@337 | 269 | */ |
nkeynes@337 | 270 | gboolean oddfield = pvr2_state.odd_even_field; |
nkeynes@337 | 271 | if( pvr2_state.line_count >= pvr2_state.retrace_start_line ) { |
nkeynes@337 | 272 | oddfield = !oddfield; |
nkeynes@337 | 273 | } |
nkeynes@337 | 274 | if( oddfield ) { |
nkeynes@335 | 275 | display_addr = MMIO_READ( PVR2, DISP_ADDR1 ); |
nkeynes@335 | 276 | } else { |
nkeynes@335 | 277 | display_addr = MMIO_READ( PVR2, DISP_ADDR2 ); |
nkeynes@335 | 278 | } |
nkeynes@335 | 279 | } |
nkeynes@335 | 280 | } else { |
nkeynes@335 | 281 | display_addr = MMIO_READ( PVR2, DISP_ADDR1 ); |
nkeynes@335 | 282 | } |
nkeynes@335 | 283 | switch( (dispmode & DISPMODE_COLFMT) >> 2 ) { |
nkeynes@161 | 284 | case 0: |
nkeynes@161 | 285 | buffer->colour_format = COLFMT_ARGB1555; |
nkeynes@161 | 286 | buffer->hres = vid_ppl << 1; |
nkeynes@161 | 287 | break; |
nkeynes@161 | 288 | case 1: |
nkeynes@161 | 289 | buffer->colour_format = COLFMT_RGB565; |
nkeynes@161 | 290 | buffer->hres = vid_ppl << 1; |
nkeynes@161 | 291 | break; |
nkeynes@161 | 292 | case 2: |
nkeynes@161 | 293 | buffer->colour_format = COLFMT_RGB888; |
nkeynes@161 | 294 | buffer->hres = (vid_ppl << 2) / 3; |
nkeynes@161 | 295 | break; |
nkeynes@161 | 296 | case 3: |
nkeynes@161 | 297 | buffer->colour_format = COLFMT_ARGB8888; |
nkeynes@161 | 298 | buffer->hres = vid_ppl; |
nkeynes@161 | 299 | break; |
nkeynes@161 | 300 | } |
nkeynes@161 | 301 | |
nkeynes@161 | 302 | if( buffer->hres <=8 ) |
nkeynes@161 | 303 | buffer->hres = 640; |
nkeynes@161 | 304 | if( buffer->vres <=8 ) |
nkeynes@161 | 305 | buffer->vres = 480; |
nkeynes@161 | 306 | if( display_driver != NULL ) { |
nkeynes@161 | 307 | if( buffer->hres != last->hres || |
nkeynes@161 | 308 | buffer->vres != last->vres || |
nkeynes@161 | 309 | buffer->colour_format != last->colour_format) { |
nkeynes@161 | 310 | display_driver->set_display_format( buffer->hres, buffer->vres, |
nkeynes@161 | 311 | buffer->colour_format ); |
nkeynes@94 | 312 | } |
nkeynes@161 | 313 | if( !bEnabled ) { |
nkeynes@161 | 314 | display_driver->display_blank_frame( 0 ); |
nkeynes@197 | 315 | } else if( MMIO_READ( PVR2, DISP_CFG2 ) & 0x08 ) { /* Blanked */ |
nkeynes@197 | 316 | uint32_t colour = MMIO_READ( PVR2, DISP_BORDER ); |
nkeynes@161 | 317 | display_driver->display_blank_frame( colour ); |
nkeynes@161 | 318 | } else if( !pvr2_render_display_frame( PVR2_RAM_BASE + display_addr ) ) { |
nkeynes@161 | 319 | display_driver->display_frame( buffer ); |
nkeynes@65 | 320 | } |
nkeynes@1 | 321 | } |
nkeynes@1 | 322 | } |
nkeynes@1 | 323 | |
nkeynes@197 | 324 | /** |
nkeynes@197 | 325 | * This has to handle every single register individually as they all get masked |
nkeynes@197 | 326 | * off differently (and its easier to do it at write time) |
nkeynes@197 | 327 | */ |
nkeynes@1 | 328 | void mmio_region_PVR2_write( uint32_t reg, uint32_t val ) |
nkeynes@1 | 329 | { |
nkeynes@1 | 330 | if( reg >= 0x200 && reg < 0x600 ) { /* Fog table */ |
nkeynes@1 | 331 | MMIO_WRITE( PVR2, reg, val ); |
nkeynes@1 | 332 | return; |
nkeynes@1 | 333 | } |
nkeynes@1 | 334 | |
nkeynes@1 | 335 | switch(reg) { |
nkeynes@189 | 336 | case PVRID: |
nkeynes@189 | 337 | case PVRVER: |
nkeynes@261 | 338 | case GUNPOS: /* Read only registers */ |
nkeynes@189 | 339 | break; |
nkeynes@197 | 340 | case PVRRESET: |
nkeynes@197 | 341 | val &= 0x00000007; /* Do stuff? */ |
nkeynes@197 | 342 | MMIO_WRITE( PVR2, reg, val ); |
nkeynes@197 | 343 | break; |
nkeynes@295 | 344 | case RENDER_START: /* Don't really care what value */ |
nkeynes@295 | 345 | if( pvr2_state.save_next_render_filename != NULL ) { |
nkeynes@295 | 346 | if( pvr2_render_save_scene(pvr2_state.save_next_render_filename) == 0 ) { |
nkeynes@295 | 347 | INFO( "Saved scene to %s", pvr2_state.save_next_render_filename); |
nkeynes@295 | 348 | } |
nkeynes@295 | 349 | g_free( pvr2_state.save_next_render_filename ); |
nkeynes@295 | 350 | pvr2_state.save_next_render_filename = NULL; |
nkeynes@295 | 351 | } |
nkeynes@295 | 352 | pvr2_render_scene(); |
nkeynes@189 | 353 | break; |
nkeynes@191 | 354 | case RENDER_POLYBASE: |
nkeynes@191 | 355 | MMIO_WRITE( PVR2, reg, val&0x00F00000 ); |
nkeynes@191 | 356 | break; |
nkeynes@191 | 357 | case RENDER_TSPCFG: |
nkeynes@191 | 358 | MMIO_WRITE( PVR2, reg, val&0x00010101 ); |
nkeynes@191 | 359 | break; |
nkeynes@197 | 360 | case DISP_BORDER: |
nkeynes@191 | 361 | MMIO_WRITE( PVR2, reg, val&0x01FFFFFF ); |
nkeynes@191 | 362 | break; |
nkeynes@197 | 363 | case DISP_MODE: |
nkeynes@191 | 364 | MMIO_WRITE( PVR2, reg, val&0x00FFFF7F ); |
nkeynes@191 | 365 | break; |
nkeynes@191 | 366 | case RENDER_MODE: |
nkeynes@191 | 367 | MMIO_WRITE( PVR2, reg, val&0x00FFFF0F ); |
nkeynes@191 | 368 | break; |
nkeynes@191 | 369 | case RENDER_SIZE: |
nkeynes@191 | 370 | MMIO_WRITE( PVR2, reg, val&0x000001FF ); |
nkeynes@191 | 371 | break; |
nkeynes@197 | 372 | case DISP_ADDR1: |
nkeynes@189 | 373 | val &= 0x00FFFFFC; |
nkeynes@189 | 374 | MMIO_WRITE( PVR2, reg, val ); |
nkeynes@337 | 375 | /* |
nkeynes@265 | 376 | pvr2_update_raster_posn(sh4r.slice_cycle); |
nkeynes@337 | 377 | fprintf( stderr, "Set Field 1 addr: %08X\n", val ); |
nkeynes@337 | 378 | if( (pvr2_state.line_count >= pvr2_state.retrace_start_line && !pvr2_state.odd_even_field) || |
nkeynes@337 | 379 | (pvr2_state.line_count < pvr2_state.retrace_end_line && pvr2_state.odd_even_field) ) { |
nkeynes@108 | 380 | pvr2_display_frame(); |
nkeynes@108 | 381 | } |
nkeynes@337 | 382 | */ |
nkeynes@108 | 383 | break; |
nkeynes@197 | 384 | case DISP_ADDR2: |
nkeynes@191 | 385 | MMIO_WRITE( PVR2, reg, val&0x00FFFFFC ); |
nkeynes@337 | 386 | pvr2_update_raster_posn(sh4r.slice_cycle); |
nkeynes@337 | 387 | /* |
nkeynes@337 | 388 | if( (pvr2_state.line_count >= pvr2_state.retrace_start_line && pvr2_state.odd_even_field) || |
nkeynes@337 | 389 | (pvr2_state.line_count < pvr2_state.retrace_end_line && !pvr2_state.odd_even_field) ) { |
nkeynes@337 | 390 | pvr2_display_frame(); |
nkeynes@337 | 391 | }*/ |
nkeynes@191 | 392 | break; |
nkeynes@197 | 393 | case DISP_SIZE: |
nkeynes@191 | 394 | MMIO_WRITE( PVR2, reg, val&0x3FFFFFFF ); |
nkeynes@191 | 395 | break; |
nkeynes@191 | 396 | case RENDER_ADDR1: |
nkeynes@191 | 397 | case RENDER_ADDR2: |
nkeynes@191 | 398 | MMIO_WRITE( PVR2, reg, val&0x01FFFFFC ); |
nkeynes@191 | 399 | break; |
nkeynes@191 | 400 | case RENDER_HCLIP: |
nkeynes@191 | 401 | MMIO_WRITE( PVR2, reg, val&0x07FF07FF ); |
nkeynes@189 | 402 | break; |
nkeynes@191 | 403 | case RENDER_VCLIP: |
nkeynes@191 | 404 | MMIO_WRITE( PVR2, reg, val&0x03FF03FF ); |
nkeynes@189 | 405 | break; |
nkeynes@197 | 406 | case DISP_HPOSIRQ: |
nkeynes@191 | 407 | MMIO_WRITE( PVR2, reg, val&0x03FF33FF ); |
nkeynes@304 | 408 | pvr2_state.irq_hpos_line = val & 0x03FF; |
nkeynes@304 | 409 | pvr2_state.irq_hpos_time_ns = 2000000*((val>>16)&0x03FF)/pvr2_state.dot_clock; |
nkeynes@304 | 410 | pvr2_state.irq_hpos_mode = (val >> 12) & 0x03; |
nkeynes@304 | 411 | switch( pvr2_state.irq_hpos_mode ) { |
nkeynes@304 | 412 | case 3: /* Reserved - treat as 0 */ |
nkeynes@304 | 413 | case 0: /* Once per frame at specified line */ |
nkeynes@304 | 414 | pvr2_state.irq_hpos_mode = HPOS_PER_FRAME; |
nkeynes@304 | 415 | break; |
nkeynes@304 | 416 | case 2: /* Once per line - as per-line-count */ |
nkeynes@304 | 417 | pvr2_state.irq_hpos_line = 1; |
nkeynes@304 | 418 | pvr2_state.irq_hpos_mode = 1; |
nkeynes@304 | 419 | case 1: /* Once per N lines */ |
nkeynes@304 | 420 | pvr2_state.irq_hpos_line_count = pvr2_state.irq_hpos_line; |
nkeynes@304 | 421 | pvr2_state.irq_hpos_line = (pvr2_state.line_count >> 1) + |
nkeynes@304 | 422 | pvr2_state.irq_hpos_line_count; |
nkeynes@304 | 423 | while( pvr2_state.irq_hpos_line > (pvr2_state.total_lines>>1) ) { |
nkeynes@304 | 424 | pvr2_state.irq_hpos_line -= (pvr2_state.total_lines>>1); |
nkeynes@304 | 425 | } |
nkeynes@304 | 426 | pvr2_state.irq_hpos_mode = HPOS_PER_LINECOUNT; |
nkeynes@304 | 427 | } |
nkeynes@304 | 428 | pvr2_schedule_scanline_event( EVENT_HPOS, pvr2_state.irq_hpos_line, 0, |
nkeynes@304 | 429 | pvr2_state.irq_hpos_time_ns ); |
nkeynes@189 | 430 | break; |
nkeynes@197 | 431 | case DISP_VPOSIRQ: |
nkeynes@189 | 432 | val = val & 0x03FF03FF; |
nkeynes@189 | 433 | pvr2_state.irq_vpos1 = (val >> 16); |
nkeynes@133 | 434 | pvr2_state.irq_vpos2 = val & 0x03FF; |
nkeynes@265 | 435 | pvr2_update_raster_posn(sh4r.slice_cycle); |
nkeynes@304 | 436 | pvr2_schedule_scanline_event( EVENT_SCANLINE1, pvr2_state.irq_vpos1, 0, 0 ); |
nkeynes@304 | 437 | pvr2_schedule_scanline_event( EVENT_SCANLINE2, pvr2_state.irq_vpos2, 0, 0 ); |
nkeynes@189 | 438 | MMIO_WRITE( PVR2, reg, val ); |
nkeynes@103 | 439 | break; |
nkeynes@197 | 440 | case RENDER_NEARCLIP: |
nkeynes@197 | 441 | MMIO_WRITE( PVR2, reg, val & 0x7FFFFFFF ); |
nkeynes@197 | 442 | break; |
nkeynes@191 | 443 | case RENDER_SHADOW: |
nkeynes@191 | 444 | MMIO_WRITE( PVR2, reg, val&0x000001FF ); |
nkeynes@191 | 445 | break; |
nkeynes@191 | 446 | case RENDER_OBJCFG: |
nkeynes@191 | 447 | MMIO_WRITE( PVR2, reg, val&0x003FFFFF ); |
nkeynes@191 | 448 | break; |
nkeynes@191 | 449 | case RENDER_TSPCLIP: |
nkeynes@191 | 450 | MMIO_WRITE( PVR2, reg, val&0x7FFFFFFF ); |
nkeynes@191 | 451 | break; |
nkeynes@197 | 452 | case RENDER_FARCLIP: |
nkeynes@197 | 453 | MMIO_WRITE( PVR2, reg, val&0xFFFFFFF0 ); |
nkeynes@197 | 454 | break; |
nkeynes@191 | 455 | case RENDER_BGPLANE: |
nkeynes@191 | 456 | MMIO_WRITE( PVR2, reg, val&0x1FFFFFFF ); |
nkeynes@191 | 457 | break; |
nkeynes@191 | 458 | case RENDER_ISPCFG: |
nkeynes@191 | 459 | MMIO_WRITE( PVR2, reg, val&0x00FFFFF9 ); |
nkeynes@191 | 460 | break; |
nkeynes@197 | 461 | case VRAM_CFG1: |
nkeynes@197 | 462 | MMIO_WRITE( PVR2, reg, val&0x000000FF ); |
nkeynes@197 | 463 | break; |
nkeynes@197 | 464 | case VRAM_CFG2: |
nkeynes@197 | 465 | MMIO_WRITE( PVR2, reg, val&0x003FFFFF ); |
nkeynes@197 | 466 | break; |
nkeynes@197 | 467 | case VRAM_CFG3: |
nkeynes@197 | 468 | MMIO_WRITE( PVR2, reg, val&0x1FFFFFFF ); |
nkeynes@197 | 469 | break; |
nkeynes@197 | 470 | case RENDER_FOGTBLCOL: |
nkeynes@197 | 471 | case RENDER_FOGVRTCOL: |
nkeynes@197 | 472 | MMIO_WRITE( PVR2, reg, val&0x00FFFFFF ); |
nkeynes@197 | 473 | break; |
nkeynes@197 | 474 | case RENDER_FOGCOEFF: |
nkeynes@197 | 475 | MMIO_WRITE( PVR2, reg, val&0x0000FFFF ); |
nkeynes@197 | 476 | break; |
nkeynes@197 | 477 | case RENDER_CLAMPHI: |
nkeynes@197 | 478 | case RENDER_CLAMPLO: |
nkeynes@197 | 479 | MMIO_WRITE( PVR2, reg, val ); |
nkeynes@197 | 480 | break; |
nkeynes@261 | 481 | case RENDER_TEXSIZE: |
nkeynes@261 | 482 | MMIO_WRITE( PVR2, reg, val&0x00031F1F ); |
nkeynes@197 | 483 | break; |
nkeynes@261 | 484 | case RENDER_PALETTE: |
nkeynes@261 | 485 | MMIO_WRITE( PVR2, reg, val&0x00000003 ); |
nkeynes@261 | 486 | break; |
nkeynes@261 | 487 | |
nkeynes@261 | 488 | /********** CRTC registers *************/ |
nkeynes@197 | 489 | case DISP_HBORDER: |
nkeynes@197 | 490 | case DISP_VBORDER: |
nkeynes@197 | 491 | MMIO_WRITE( PVR2, reg, val&0x03FF03FF ); |
nkeynes@197 | 492 | break; |
nkeynes@261 | 493 | case DISP_TOTAL: |
nkeynes@261 | 494 | val = val & 0x03FF03FF; |
nkeynes@261 | 495 | MMIO_WRITE( PVR2, reg, val ); |
nkeynes@265 | 496 | pvr2_update_raster_posn(sh4r.slice_cycle); |
nkeynes@261 | 497 | pvr2_state.total_lines = (val >> 16) + 1; |
nkeynes@261 | 498 | pvr2_state.line_size = (val & 0x03FF) + 1; |
nkeynes@261 | 499 | pvr2_state.line_time_ns = 1000000 * pvr2_state.line_size / pvr2_state.dot_clock; |
nkeynes@265 | 500 | pvr2_state.retrace_end_line = 0x2A; |
nkeynes@265 | 501 | pvr2_state.retrace_start_line = pvr2_state.total_lines - 6; |
nkeynes@304 | 502 | pvr2_schedule_scanline_event( EVENT_SCANLINE1, pvr2_state.irq_vpos1, 0, 0 ); |
nkeynes@304 | 503 | pvr2_schedule_scanline_event( EVENT_SCANLINE2, pvr2_state.irq_vpos2, 0, 0 ); |
nkeynes@304 | 504 | pvr2_schedule_scanline_event( EVENT_HPOS, pvr2_state.irq_hpos_line, 0, |
nkeynes@304 | 505 | pvr2_state.irq_hpos_time_ns ); |
nkeynes@261 | 506 | break; |
nkeynes@261 | 507 | case DISP_SYNCCFG: |
nkeynes@261 | 508 | MMIO_WRITE( PVR2, reg, val&0x000003FF ); |
nkeynes@261 | 509 | pvr2_state.interlaced = (val & 0x0010) ? TRUE : FALSE; |
nkeynes@261 | 510 | break; |
nkeynes@261 | 511 | case DISP_SYNCTIME: |
nkeynes@261 | 512 | pvr2_state.vsync_lines = (val >> 8) & 0x0F; |
nkeynes@269 | 513 | pvr2_state.hsync_width_ns = ((val & 0x7F) + 1) * 2000000 / pvr2_state.dot_clock; |
nkeynes@197 | 514 | MMIO_WRITE( PVR2, reg, val&0xFFFFFF7F ); |
nkeynes@197 | 515 | break; |
nkeynes@197 | 516 | case DISP_CFG2: |
nkeynes@197 | 517 | MMIO_WRITE( PVR2, reg, val&0x003F01FF ); |
nkeynes@197 | 518 | break; |
nkeynes@197 | 519 | case DISP_HPOS: |
nkeynes@261 | 520 | val = val & 0x03FF; |
nkeynes@261 | 521 | pvr2_state.front_porch_ns = (val + 1) * 1000000 / pvr2_state.dot_clock; |
nkeynes@261 | 522 | MMIO_WRITE( PVR2, reg, val ); |
nkeynes@197 | 523 | break; |
nkeynes@197 | 524 | case DISP_VPOS: |
nkeynes@197 | 525 | MMIO_WRITE( PVR2, reg, val&0x03FF03FF ); |
nkeynes@197 | 526 | break; |
nkeynes@261 | 527 | |
nkeynes@261 | 528 | /*********** Tile accelerator registers ***********/ |
nkeynes@261 | 529 | case TA_POLYPOS: |
nkeynes@261 | 530 | case TA_LISTPOS: |
nkeynes@261 | 531 | /* Readonly registers */ |
nkeynes@197 | 532 | break; |
nkeynes@189 | 533 | case TA_TILEBASE: |
nkeynes@193 | 534 | case TA_LISTEND: |
nkeynes@189 | 535 | case TA_LISTBASE: |
nkeynes@191 | 536 | MMIO_WRITE( PVR2, reg, val&0x00FFFFE0 ); |
nkeynes@189 | 537 | break; |
nkeynes@191 | 538 | case RENDER_TILEBASE: |
nkeynes@189 | 539 | case TA_POLYBASE: |
nkeynes@189 | 540 | case TA_POLYEND: |
nkeynes@191 | 541 | MMIO_WRITE( PVR2, reg, val&0x00FFFFFC ); |
nkeynes@189 | 542 | break; |
nkeynes@189 | 543 | case TA_TILESIZE: |
nkeynes@191 | 544 | MMIO_WRITE( PVR2, reg, val&0x000F003F ); |
nkeynes@189 | 545 | break; |
nkeynes@189 | 546 | case TA_TILECFG: |
nkeynes@191 | 547 | MMIO_WRITE( PVR2, reg, val&0x00133333 ); |
nkeynes@189 | 548 | break; |
nkeynes@261 | 549 | case TA_INIT: |
nkeynes@261 | 550 | if( val & 0x80000000 ) |
nkeynes@261 | 551 | pvr2_ta_init(); |
nkeynes@261 | 552 | break; |
nkeynes@261 | 553 | case TA_REINIT: |
nkeynes@261 | 554 | break; |
nkeynes@261 | 555 | /**************** Scaler registers? ****************/ |
nkeynes@335 | 556 | case RENDER_SCALER: |
nkeynes@261 | 557 | MMIO_WRITE( PVR2, reg, val&0x0007FFFF ); |
nkeynes@261 | 558 | break; |
nkeynes@261 | 559 | |
nkeynes@197 | 560 | case YUV_ADDR: |
nkeynes@284 | 561 | val = val & 0x00FFFFF8; |
nkeynes@284 | 562 | MMIO_WRITE( PVR2, reg, val ); |
nkeynes@284 | 563 | pvr2_yuv_init( val ); |
nkeynes@197 | 564 | break; |
nkeynes@197 | 565 | case YUV_CFG: |
nkeynes@197 | 566 | MMIO_WRITE( PVR2, reg, val&0x01013F3F ); |
nkeynes@284 | 567 | pvr2_yuv_set_config(val); |
nkeynes@197 | 568 | break; |
nkeynes@261 | 569 | |
nkeynes@261 | 570 | /**************** Unknowns ***************/ |
nkeynes@261 | 571 | case PVRUNK1: |
nkeynes@261 | 572 | MMIO_WRITE( PVR2, reg, val&0x000007FF ); |
nkeynes@261 | 573 | break; |
nkeynes@261 | 574 | case PVRUNK2: |
nkeynes@261 | 575 | MMIO_WRITE( PVR2, reg, val&0x00000007 ); |
nkeynes@100 | 576 | break; |
nkeynes@261 | 577 | case PVRUNK3: |
nkeynes@261 | 578 | MMIO_WRITE( PVR2, reg, val&0x000FFF3F ); |
nkeynes@261 | 579 | break; |
nkeynes@261 | 580 | case PVRUNK5: |
nkeynes@261 | 581 | MMIO_WRITE( PVR2, reg, val&0x0000FFFF ); |
nkeynes@261 | 582 | break; |
nkeynes@261 | 583 | case PVRUNK6: |
nkeynes@261 | 584 | MMIO_WRITE( PVR2, reg, val&0x000000FF ); |
nkeynes@197 | 585 | break; |
nkeynes@197 | 586 | case PVRUNK7: |
nkeynes@197 | 587 | MMIO_WRITE( PVR2, reg, val&0x00000001 ); |
nkeynes@197 | 588 | break; |
nkeynes@1 | 589 | } |
nkeynes@1 | 590 | } |
nkeynes@1 | 591 | |
nkeynes@261 | 592 | /** |
nkeynes@261 | 593 | * Calculate the current read value of the syncstat register, using |
nkeynes@261 | 594 | * the current SH4 clock time as an offset from the last timeslice. |
nkeynes@261 | 595 | * The register reads (LSB to MSB) as: |
nkeynes@261 | 596 | * 0..9 Current scan line |
nkeynes@261 | 597 | * 10 Odd/even field (1 = odd, 0 = even) |
nkeynes@261 | 598 | * 11 Display active (including border and overscan) |
nkeynes@261 | 599 | * 12 Horizontal sync off |
nkeynes@261 | 600 | * 13 Vertical sync off |
nkeynes@261 | 601 | * Note this method is probably incorrect for anything other than straight |
nkeynes@265 | 602 | * interlaced PAL/NTSC, and needs further testing. |
nkeynes@261 | 603 | */ |
nkeynes@261 | 604 | uint32_t pvr2_get_sync_status() |
nkeynes@261 | 605 | { |
nkeynes@265 | 606 | pvr2_update_raster_posn(sh4r.slice_cycle); |
nkeynes@265 | 607 | uint32_t result = pvr2_state.line_count; |
nkeynes@261 | 608 | |
nkeynes@265 | 609 | if( pvr2_state.odd_even_field ) { |
nkeynes@261 | 610 | result |= 0x0400; |
nkeynes@261 | 611 | } |
nkeynes@265 | 612 | if( (pvr2_state.line_count & 0x01) == pvr2_state.odd_even_field ) { |
nkeynes@265 | 613 | if( pvr2_state.line_remainder > pvr2_state.hsync_width_ns ) { |
nkeynes@261 | 614 | result |= 0x1000; /* !HSYNC */ |
nkeynes@261 | 615 | } |
nkeynes@265 | 616 | if( pvr2_state.line_count >= pvr2_state.vsync_lines ) { |
nkeynes@265 | 617 | if( pvr2_state.line_remainder > pvr2_state.front_porch_ns ) { |
nkeynes@261 | 618 | result |= 0x2800; /* Display active */ |
nkeynes@261 | 619 | } else { |
nkeynes@261 | 620 | result |= 0x2000; /* Front porch */ |
nkeynes@261 | 621 | } |
nkeynes@261 | 622 | } |
nkeynes@261 | 623 | } else { |
nkeynes@269 | 624 | if( pvr2_state.line_count >= pvr2_state.vsync_lines ) { |
nkeynes@269 | 625 | if( pvr2_state.line_remainder < (pvr2_state.line_time_ns - pvr2_state.back_porch_ns)) { |
nkeynes@269 | 626 | result |= 0x3800; /* Display active */ |
nkeynes@269 | 627 | } else { |
nkeynes@269 | 628 | result |= 0x3000; |
nkeynes@269 | 629 | } |
nkeynes@261 | 630 | } else { |
nkeynes@261 | 631 | result |= 0x1000; /* Back porch */ |
nkeynes@261 | 632 | } |
nkeynes@261 | 633 | } |
nkeynes@261 | 634 | return result; |
nkeynes@261 | 635 | } |
nkeynes@261 | 636 | |
nkeynes@265 | 637 | /** |
nkeynes@265 | 638 | * Schedule a "scanline" event. This actually goes off at |
nkeynes@265 | 639 | * 2 * line in even fields and 2 * line + 1 in odd fields. |
nkeynes@265 | 640 | * Otherwise this behaves as per pvr2_schedule_line_event(). |
nkeynes@265 | 641 | * The raster position should be updated before calling this |
nkeynes@265 | 642 | * method. |
nkeynes@304 | 643 | * @param eventid Event to fire at the specified time |
nkeynes@304 | 644 | * @param line Line on which to fire the event (this is 2n/2n+1 for interlaced |
nkeynes@304 | 645 | * displays). |
nkeynes@304 | 646 | * @param hpos_ns Nanoseconds into the line at which to fire. |
nkeynes@265 | 647 | */ |
nkeynes@304 | 648 | static void pvr2_schedule_scanline_event( int eventid, int line, int minimum_lines, int hpos_ns ) |
nkeynes@265 | 649 | { |
nkeynes@265 | 650 | uint32_t field = pvr2_state.odd_even_field; |
nkeynes@265 | 651 | if( line <= pvr2_state.line_count && pvr2_state.interlaced ) { |
nkeynes@265 | 652 | field = !field; |
nkeynes@265 | 653 | } |
nkeynes@304 | 654 | if( hpos_ns > pvr2_state.line_time_ns ) { |
nkeynes@304 | 655 | hpos_ns = pvr2_state.line_time_ns; |
nkeynes@304 | 656 | } |
nkeynes@265 | 657 | |
nkeynes@265 | 658 | line <<= 1; |
nkeynes@265 | 659 | if( field ) { |
nkeynes@265 | 660 | line += 1; |
nkeynes@265 | 661 | } |
nkeynes@274 | 662 | |
nkeynes@274 | 663 | if( line < pvr2_state.total_lines ) { |
nkeynes@274 | 664 | uint32_t lines; |
nkeynes@274 | 665 | uint32_t time; |
nkeynes@274 | 666 | if( line <= pvr2_state.line_count ) { |
nkeynes@274 | 667 | lines = (pvr2_state.total_lines - pvr2_state.line_count + line); |
nkeynes@274 | 668 | } else { |
nkeynes@274 | 669 | lines = (line - pvr2_state.line_count); |
nkeynes@274 | 670 | } |
nkeynes@274 | 671 | if( lines <= minimum_lines ) { |
nkeynes@274 | 672 | lines += pvr2_state.total_lines; |
nkeynes@274 | 673 | } |
nkeynes@304 | 674 | time = (lines * pvr2_state.line_time_ns) - pvr2_state.line_remainder + hpos_ns; |
nkeynes@274 | 675 | event_schedule( eventid, time ); |
nkeynes@274 | 676 | } else { |
nkeynes@274 | 677 | event_cancel( eventid ); |
nkeynes@274 | 678 | } |
nkeynes@265 | 679 | } |
nkeynes@265 | 680 | |
nkeynes@1 | 681 | MMIO_REGION_READ_FN( PVR2, reg ) |
nkeynes@1 | 682 | { |
nkeynes@1 | 683 | switch( reg ) { |
nkeynes@261 | 684 | case DISP_SYNCSTAT: |
nkeynes@261 | 685 | return pvr2_get_sync_status(); |
nkeynes@1 | 686 | default: |
nkeynes@1 | 687 | return MMIO_READ( PVR2, reg ); |
nkeynes@1 | 688 | } |
nkeynes@1 | 689 | } |
nkeynes@19 | 690 | |
nkeynes@337 | 691 | MMIO_REGION_WRITE_FN( PVR2PAL, reg, val ) |
nkeynes@337 | 692 | { |
nkeynes@337 | 693 | MMIO_WRITE( PVR2PAL, reg, val ); |
nkeynes@337 | 694 | pvr2_state.palette_changed = TRUE; |
nkeynes@337 | 695 | } |
nkeynes@337 | 696 | |
nkeynes@337 | 697 | void pvr2_check_palette_changed() |
nkeynes@337 | 698 | { |
nkeynes@337 | 699 | if( pvr2_state.palette_changed ) { |
nkeynes@337 | 700 | texcache_invalidate_palette(); |
nkeynes@337 | 701 | pvr2_state.palette_changed = FALSE; |
nkeynes@337 | 702 | } |
nkeynes@337 | 703 | } |
nkeynes@337 | 704 | |
nkeynes@337 | 705 | MMIO_REGION_READ_DEFFN( PVR2PAL ); |
nkeynes@85 | 706 | |
nkeynes@19 | 707 | void pvr2_set_base_address( uint32_t base ) |
nkeynes@19 | 708 | { |
nkeynes@197 | 709 | mmio_region_PVR2_write( DISP_ADDR1, base ); |
nkeynes@19 | 710 | } |
nkeynes@56 | 711 | |
nkeynes@56 | 712 | |
nkeynes@65 | 713 | |
nkeynes@98 | 714 | |
nkeynes@56 | 715 | int32_t mmio_region_PVR2TA_read( uint32_t reg ) |
nkeynes@56 | 716 | { |
nkeynes@56 | 717 | return 0xFFFFFFFF; |
nkeynes@56 | 718 | } |
nkeynes@56 | 719 | |
nkeynes@56 | 720 | void mmio_region_PVR2TA_write( uint32_t reg, uint32_t val ) |
nkeynes@56 | 721 | { |
nkeynes@189 | 722 | pvr2_ta_write( (char *)&val, sizeof(uint32_t) ); |
nkeynes@56 | 723 | } |
nkeynes@56 | 724 |
.