Search
lxdream.org :: lxdream :: r304:2855cf8709a5
lxdream 0.9.1
released Jun 29
Download Now
changeset304:2855cf8709a5
parent303:41786e056449
child305:1191085c5988
authornkeynes
dateThu Jan 18 11:13:12 2007 +0000 (12 years ago)
Reimplement HPOSIRQ to correspond to reality
src/pvr2/pvr2.c
1.1 --- a/src/pvr2/pvr2.c Wed Jan 17 21:28:43 2007 +0000
1.2 +++ b/src/pvr2/pvr2.c Thu Jan 18 11:13:12 2007 +0000
1.3 @@ -1,5 +1,5 @@
1.4 /**
1.5 - * $Id: pvr2.c,v 1.40 2007-01-16 10:34:46 nkeynes Exp $
1.6 + * $Id: pvr2.c,v 1.41 2007-01-18 11:13:12 nkeynes Exp $
1.7 *
1.8 * PVR2 (Video) Core module implementation and MMIO registers.
1.9 *
1.10 @@ -30,14 +30,16 @@
1.11
1.12 char *video_base;
1.13
1.14 +#define HPOS_PER_FRAME 0
1.15 +#define HPOS_PER_LINECOUNT 1
1.16 +
1.17 static void pvr2_init( void );
1.18 static void pvr2_reset( void );
1.19 static uint32_t pvr2_run_slice( uint32_t );
1.20 static void pvr2_save_state( FILE *f );
1.21 static int pvr2_load_state( FILE *f );
1.22 static void pvr2_update_raster_posn( uint32_t nanosecs );
1.23 -static void pvr2_schedule_line_event( int eventid, int line );
1.24 -static void pvr2_schedule_scanline_event( int eventid, int line, int minimum_lines );
1.25 +static void pvr2_schedule_scanline_event( int eventid, int line, int minimum_lines, int line_time_ns );
1.26 uint32_t pvr2_get_sync_status();
1.27
1.28 void pvr2_display_frame( void );
1.29 @@ -66,6 +68,10 @@
1.30 uint32_t line_count;
1.31 uint32_t line_remainder;
1.32 uint32_t cycles_run; /* Cycles already executed prior to main time slice */
1.33 + uint32_t irq_hpos_line;
1.34 + uint32_t irq_hpos_line_count;
1.35 + uint32_t irq_hpos_mode;
1.36 + uint32_t irq_hpos_time_ns; /* Time within the line */
1.37 uint32_t irq_vpos1;
1.38 uint32_t irq_vpos2;
1.39 uint32_t odd_even_field; /* 1 = odd, 0 = even */
1.40 @@ -89,12 +95,19 @@
1.41 int video_buffer_idx = 0;
1.42
1.43 /**
1.44 - * Event handler for the retrace callback (fires on line 0 normally)
1.45 + * Event handler for the hpos callback
1.46 */
1.47 -static void pvr2_retrace_callback( int eventid ) {
1.48 +static void pvr2_hpos_callback( int eventid ) {
1.49 asic_event( eventid );
1.50 pvr2_update_raster_posn(sh4r.slice_cycle);
1.51 - pvr2_schedule_line_event( EVENT_RETRACE, 0 );
1.52 + if( pvr2_state.irq_hpos_mode == HPOS_PER_LINECOUNT ) {
1.53 + pvr2_state.irq_hpos_line += pvr2_state.irq_hpos_line_count;
1.54 + while( pvr2_state.irq_hpos_line > (pvr2_state.total_lines>>1) ) {
1.55 + pvr2_state.irq_hpos_line -= (pvr2_state.total_lines>>1);
1.56 + }
1.57 + }
1.58 + pvr2_schedule_scanline_event( eventid, pvr2_state.irq_hpos_line, 1,
1.59 + pvr2_state.irq_hpos_time_ns );
1.60 }
1.61
1.62 /**
1.63 @@ -105,9 +118,9 @@
1.64 asic_event( eventid );
1.65 pvr2_update_raster_posn(sh4r.slice_cycle);
1.66 if( eventid == EVENT_SCANLINE1 ) {
1.67 - pvr2_schedule_scanline_event( eventid, pvr2_state.irq_vpos1, 1 );
1.68 + pvr2_schedule_scanline_event( eventid, pvr2_state.irq_vpos1, 1, 0 );
1.69 } else {
1.70 - pvr2_schedule_scanline_event( eventid, pvr2_state.irq_vpos2, 1 );
1.71 + pvr2_schedule_scanline_event( eventid, pvr2_state.irq_vpos2, 1, 0 );
1.72 }
1.73 }
1.74
1.75 @@ -116,7 +129,7 @@
1.76 register_io_region( &mmio_region_PVR2 );
1.77 register_io_region( &mmio_region_PVR2PAL );
1.78 register_io_region( &mmio_region_PVR2TA );
1.79 - register_event_callback( EVENT_RETRACE, pvr2_retrace_callback );
1.80 + register_event_callback( EVENT_HPOS, pvr2_hpos_callback );
1.81 register_event_callback( EVENT_SCANLINE1, pvr2_scanline_callback );
1.82 register_event_callback( EVENT_SCANLINE2, pvr2_scanline_callback );
1.83 video_base = mem_get_region_by_name( MEM_REGION_VIDEO );
1.84 @@ -359,14 +372,36 @@
1.85 break;
1.86 case DISP_HPOSIRQ:
1.87 MMIO_WRITE( PVR2, reg, val&0x03FF33FF );
1.88 + pvr2_state.irq_hpos_line = val & 0x03FF;
1.89 + pvr2_state.irq_hpos_time_ns = 2000000*((val>>16)&0x03FF)/pvr2_state.dot_clock;
1.90 + pvr2_state.irq_hpos_mode = (val >> 12) & 0x03;
1.91 + switch( pvr2_state.irq_hpos_mode ) {
1.92 + case 3: /* Reserved - treat as 0 */
1.93 + case 0: /* Once per frame at specified line */
1.94 + pvr2_state.irq_hpos_mode = HPOS_PER_FRAME;
1.95 + break;
1.96 + case 2: /* Once per line - as per-line-count */
1.97 + pvr2_state.irq_hpos_line = 1;
1.98 + pvr2_state.irq_hpos_mode = 1;
1.99 + case 1: /* Once per N lines */
1.100 + pvr2_state.irq_hpos_line_count = pvr2_state.irq_hpos_line;
1.101 + pvr2_state.irq_hpos_line = (pvr2_state.line_count >> 1) +
1.102 + pvr2_state.irq_hpos_line_count;
1.103 + while( pvr2_state.irq_hpos_line > (pvr2_state.total_lines>>1) ) {
1.104 + pvr2_state.irq_hpos_line -= (pvr2_state.total_lines>>1);
1.105 + }
1.106 + pvr2_state.irq_hpos_mode = HPOS_PER_LINECOUNT;
1.107 + }
1.108 + pvr2_schedule_scanline_event( EVENT_HPOS, pvr2_state.irq_hpos_line, 0,
1.109 + pvr2_state.irq_hpos_time_ns );
1.110 break;
1.111 case DISP_VPOSIRQ:
1.112 val = val & 0x03FF03FF;
1.113 pvr2_state.irq_vpos1 = (val >> 16);
1.114 pvr2_state.irq_vpos2 = val & 0x03FF;
1.115 pvr2_update_raster_posn(sh4r.slice_cycle);
1.116 - pvr2_schedule_scanline_event( EVENT_SCANLINE1, pvr2_state.irq_vpos1, 0 );
1.117 - pvr2_schedule_scanline_event( EVENT_SCANLINE2, pvr2_state.irq_vpos2, 0 );
1.118 + pvr2_schedule_scanline_event( EVENT_SCANLINE1, pvr2_state.irq_vpos1, 0, 0 );
1.119 + pvr2_schedule_scanline_event( EVENT_SCANLINE2, pvr2_state.irq_vpos2, 0, 0 );
1.120 MMIO_WRITE( PVR2, reg, val );
1.121 break;
1.122 case RENDER_NEARCLIP:
1.123 @@ -431,9 +466,10 @@
1.124 pvr2_state.line_time_ns = 1000000 * pvr2_state.line_size / pvr2_state.dot_clock;
1.125 pvr2_state.retrace_end_line = 0x2A;
1.126 pvr2_state.retrace_start_line = pvr2_state.total_lines - 6;
1.127 - pvr2_schedule_line_event( EVENT_RETRACE, 0 );
1.128 - pvr2_schedule_scanline_event( EVENT_SCANLINE1, pvr2_state.irq_vpos1, 0 );
1.129 - pvr2_schedule_scanline_event( EVENT_SCANLINE2, pvr2_state.irq_vpos2, 0 );
1.130 + pvr2_schedule_scanline_event( EVENT_SCANLINE1, pvr2_state.irq_vpos1, 0, 0 );
1.131 + pvr2_schedule_scanline_event( EVENT_SCANLINE2, pvr2_state.irq_vpos2, 0, 0 );
1.132 + pvr2_schedule_scanline_event( EVENT_HPOS, pvr2_state.irq_hpos_line, 0,
1.133 + pvr2_state.irq_hpos_time_ns );
1.134 break;
1.135 case DISP_SYNCCFG:
1.136 MMIO_WRITE( PVR2, reg, val&0x000003FF );
1.137 @@ -571,40 +607,25 @@
1.138 }
1.139
1.140 /**
1.141 - * Schedule an event for the start of the given line. If the line is actually
1.142 - * the current line, schedules it for the next field.
1.143 - * The raster position should be updated before calling this method.
1.144 - */
1.145 -static void pvr2_schedule_line_event( int eventid, int line )
1.146 -{
1.147 - uint32_t time;
1.148 - if( line <= pvr2_state.line_count ) {
1.149 - time = (pvr2_state.total_lines - pvr2_state.line_count + line) * pvr2_state.line_time_ns
1.150 - - pvr2_state.line_remainder;
1.151 - } else {
1.152 - time = (line - pvr2_state.line_count) * pvr2_state.line_time_ns - pvr2_state.line_remainder;
1.153 - }
1.154 -
1.155 - if( line < pvr2_state.total_lines ) {
1.156 - event_schedule( eventid, time );
1.157 - } else {
1.158 - event_cancel( eventid );
1.159 - }
1.160 -}
1.161 -
1.162 -/**
1.163 * Schedule a "scanline" event. This actually goes off at
1.164 * 2 * line in even fields and 2 * line + 1 in odd fields.
1.165 * Otherwise this behaves as per pvr2_schedule_line_event().
1.166 * The raster position should be updated before calling this
1.167 * method.
1.168 + * @param eventid Event to fire at the specified time
1.169 + * @param line Line on which to fire the event (this is 2n/2n+1 for interlaced
1.170 + * displays).
1.171 + * @param hpos_ns Nanoseconds into the line at which to fire.
1.172 */
1.173 -static void pvr2_schedule_scanline_event( int eventid, int line, int minimum_lines )
1.174 +static void pvr2_schedule_scanline_event( int eventid, int line, int minimum_lines, int hpos_ns )
1.175 {
1.176 uint32_t field = pvr2_state.odd_even_field;
1.177 if( line <= pvr2_state.line_count && pvr2_state.interlaced ) {
1.178 field = !field;
1.179 }
1.180 + if( hpos_ns > pvr2_state.line_time_ns ) {
1.181 + hpos_ns = pvr2_state.line_time_ns;
1.182 + }
1.183
1.184 line <<= 1;
1.185 if( field ) {
1.186 @@ -622,7 +643,7 @@
1.187 if( lines <= minimum_lines ) {
1.188 lines += pvr2_state.total_lines;
1.189 }
1.190 - time = (lines * pvr2_state.line_time_ns) - pvr2_state.line_remainder;
1.191 + time = (lines * pvr2_state.line_time_ns) - pvr2_state.line_remainder + hpos_ns;
1.192 event_schedule( eventid, time );
1.193 } else {
1.194 event_cancel( eventid );
.