Search
lxdream.org :: lxdream/src/pvr2/pvr2.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/pvr2.c
changeset 261:93fdb2a70e18
prev218:cbad5a3f8387
next265:5daf59b7f31b
author nkeynes
date Wed Jan 03 09:01:51 2007 +0000 (13 years ago)
permissions -rw-r--r--
last change Implement the main CRTC registers, along with the sync status register.
Timings are now pretty close to the real thing.
file annotate diff log raw
1.1 --- a/src/pvr2/pvr2.c Tue Aug 29 08:11:56 2006 +0000
1.2 +++ b/src/pvr2/pvr2.c Wed Jan 03 09:01:51 2007 +0000
1.3 @@ -1,5 +1,5 @@
1.4 /**
1.5 - * $Id: pvr2.c,v 1.33 2006-08-29 08:11:56 nkeynes Exp $
1.6 + * $Id: pvr2.c,v 1.34 2007-01-03 09:01:51 nkeynes Exp $
1.7 *
1.8 * PVR2 (Video) Core module implementation and MMIO registers.
1.9 *
1.10 @@ -21,6 +21,7 @@
1.11 #include "display.h"
1.12 #include "mem.h"
1.13 #include "asic.h"
1.14 +#include "clock.h"
1.15 #include "pvr2/pvr2.h"
1.16 #include "sh4/sh4core.h"
1.17 #define MMIO_IMPL
1.18 @@ -52,7 +53,7 @@
1.19 int line_time_ns;
1.20 };
1.21
1.22 -struct video_timing pal_timing = { 50, 625, 65, 32000 };
1.23 +struct video_timing pal_timing = { 50, 625, 65, 31945 };
1.24 struct video_timing ntsc_timing= { 60, 525, 65, 31746 };
1.25
1.26 struct pvr2_state {
1.27 @@ -61,7 +62,19 @@
1.28 uint32_t line_remainder;
1.29 uint32_t irq_vpos1;
1.30 uint32_t irq_vpos2;
1.31 + uint32_t odd_even_field; /* 1 = odd, 0 = even */
1.32 gboolean retrace;
1.33 +
1.34 + /* timing */
1.35 + uint32_t dot_clock;
1.36 + uint32_t total_lines;
1.37 + uint32_t line_size;
1.38 + uint32_t line_time_ns;
1.39 + uint32_t vsync_lines;
1.40 + uint32_t hsync_width_ns;
1.41 + uint32_t front_porch_ns;
1.42 + uint32_t back_porch_ns;
1.43 + gboolean interlaced;
1.44 struct video_timing timing;
1.45 } pvr2_state;
1.46
1.47 @@ -75,6 +88,13 @@
1.48 register_io_region( &mmio_region_PVR2TA );
1.49 video_base = mem_get_region_by_name( MEM_REGION_VIDEO );
1.50 texcache_init();
1.51 + pvr2_state.dot_clock = 27069;
1.52 + pvr2_state.total_lines = pal_timing.total_lines;
1.53 + pvr2_state.line_time_ns = pal_timing.line_time_ns;
1.54 + pvr2_state.front_porch_ns = 12000;
1.55 + pvr2_state.back_porch_ns = 4000;
1.56 + pvr2_state.hsync_width_ns = 4000;
1.57 + pvr2_state.vsync_lines = 5;
1.58 pvr2_reset();
1.59 pvr2_ta_reset();
1.60 }
1.61 @@ -110,11 +130,11 @@
1.62 static uint32_t pvr2_run_slice( uint32_t nanosecs )
1.63 {
1.64 pvr2_state.line_remainder += nanosecs;
1.65 - while( pvr2_state.line_remainder >= pvr2_state.timing.line_time_ns ) {
1.66 - pvr2_state.line_remainder -= pvr2_state.timing.line_time_ns;
1.67 + while( pvr2_state.line_remainder >= pvr2_state.line_time_ns ) {
1.68 + pvr2_state.line_remainder -= pvr2_state.line_time_ns;
1.69
1.70 pvr2_state.line_count++;
1.71 - if( pvr2_state.line_count == pvr2_state.timing.total_lines ) {
1.72 + if( pvr2_state.line_count == pvr2_state.total_lines ) {
1.73 asic_event( EVENT_RETRACE );
1.74 pvr2_state.line_count = 0;
1.75 pvr2_state.retrace = TRUE;
1.76 @@ -153,7 +173,7 @@
1.77
1.78 int dispsize = MMIO_READ( PVR2, DISP_SIZE );
1.79 int dispmode = MMIO_READ( PVR2, DISP_MODE );
1.80 - int vidcfg = MMIO_READ( PVR2, DISP_CFG );
1.81 + int vidcfg = MMIO_READ( PVR2, DISP_SYNCCFG );
1.82 int vid_stride = ((dispsize & DISPSIZE_MODULO) >> 20) - 1;
1.83 int vid_lpf = ((dispsize & DISPSIZE_LPF) >> 10) + 1;
1.84 int vid_ppl = ((dispsize & DISPSIZE_PPL)) + 1;
1.85 @@ -222,22 +242,16 @@
1.86 switch(reg) {
1.87 case PVRID:
1.88 case PVRVER:
1.89 - case GUNPOS:
1.90 - case TA_POLYPOS:
1.91 - case TA_LISTPOS:
1.92 - /* Readonly registers */
1.93 + case GUNPOS: /* Read only registers */
1.94 break;
1.95 case PVRRESET:
1.96 val &= 0x00000007; /* Do stuff? */
1.97 MMIO_WRITE( PVR2, reg, val );
1.98 break;
1.99 case RENDER_START:
1.100 - if( val == 0xFFFFFFFF )
1.101 + if( val == 0xFFFFFFFF || val == 0x00000001 )
1.102 pvr2_render_scene();
1.103 break;
1.104 - case PVRUNK1:
1.105 - MMIO_WRITE( PVR2, reg, val&0x000007FF );
1.106 - break;
1.107 case RENDER_POLYBASE:
1.108 MMIO_WRITE( PVR2, reg, val&0x00F00000 );
1.109 break;
1.110 @@ -298,9 +312,6 @@
1.111 case RENDER_OBJCFG:
1.112 MMIO_WRITE( PVR2, reg, val&0x003FFFFF );
1.113 break;
1.114 - case PVRUNK2:
1.115 - MMIO_WRITE( PVR2, reg, val&0x00000007 );
1.116 - break;
1.117 case RENDER_TSPCLIP:
1.118 MMIO_WRITE( PVR2, reg, val&0x7FFFFFFF );
1.119 break;
1.120 @@ -333,43 +344,50 @@
1.121 case RENDER_CLAMPLO:
1.122 MMIO_WRITE( PVR2, reg, val );
1.123 break;
1.124 - case DISP_CFG:
1.125 - MMIO_WRITE( PVR2, reg, val&0x000003FF );
1.126 + case RENDER_TEXSIZE:
1.127 + MMIO_WRITE( PVR2, reg, val&0x00031F1F );
1.128 break;
1.129 + case RENDER_PALETTE:
1.130 + MMIO_WRITE( PVR2, reg, val&0x00000003 );
1.131 + break;
1.132 +
1.133 + /********** CRTC registers *************/
1.134 case DISP_HBORDER:
1.135 - case DISP_SYNC:
1.136 case DISP_VBORDER:
1.137 MMIO_WRITE( PVR2, reg, val&0x03FF03FF );
1.138 break;
1.139 - case DISP_SYNC2:
1.140 + case DISP_TOTAL:
1.141 + val = val & 0x03FF03FF;
1.142 + MMIO_WRITE( PVR2, reg, val );
1.143 + pvr2_state.total_lines = (val >> 16) + 1;
1.144 + pvr2_state.line_size = (val & 0x03FF) + 1;
1.145 + pvr2_state.line_time_ns = 1000000 * pvr2_state.line_size / pvr2_state.dot_clock;
1.146 + break;
1.147 + case DISP_SYNCCFG:
1.148 + MMIO_WRITE( PVR2, reg, val&0x000003FF );
1.149 + pvr2_state.interlaced = (val & 0x0010) ? TRUE : FALSE;
1.150 + break;
1.151 + case DISP_SYNCTIME:
1.152 + pvr2_state.vsync_lines = (val >> 8) & 0x0F;
1.153 + pvr2_state.hsync_width_ns = ((val & 0x7F) + 1) * 1000000 / pvr2_state.dot_clock;
1.154 MMIO_WRITE( PVR2, reg, val&0xFFFFFF7F );
1.155 break;
1.156 - case RENDER_TEXSIZE:
1.157 - MMIO_WRITE( PVR2, reg, val&0x00031F1F );
1.158 - break;
1.159 case DISP_CFG2:
1.160 MMIO_WRITE( PVR2, reg, val&0x003F01FF );
1.161 break;
1.162 case DISP_HPOS:
1.163 - MMIO_WRITE( PVR2, reg, val&0x000003FF );
1.164 + val = val & 0x03FF;
1.165 + pvr2_state.front_porch_ns = (val + 1) * 1000000 / pvr2_state.dot_clock;
1.166 + MMIO_WRITE( PVR2, reg, val );
1.167 break;
1.168 case DISP_VPOS:
1.169 MMIO_WRITE( PVR2, reg, val&0x03FF03FF );
1.170 break;
1.171 - case SCALERCFG:
1.172 - MMIO_WRITE( PVR2, reg, val&0x0007FFFF );
1.173 - break;
1.174 - case RENDER_PALETTE:
1.175 - MMIO_WRITE( PVR2, reg, val&0x00000003 );
1.176 - break;
1.177 - case PVRUNK3:
1.178 - MMIO_WRITE( PVR2, reg, val&0x000FFF3F );
1.179 - break;
1.180 - case PVRUNK5:
1.181 - MMIO_WRITE( PVR2, reg, val&0x0000FFFF );
1.182 - break;
1.183 - case PVRUNK6:
1.184 - MMIO_WRITE( PVR2, reg, val&0x000000FF );
1.185 +
1.186 + /*********** Tile accelerator registers ***********/
1.187 + case TA_POLYPOS:
1.188 + case TA_LISTPOS:
1.189 + /* Readonly registers */
1.190 break;
1.191 case TA_TILEBASE:
1.192 case TA_LISTEND:
1.193 @@ -387,17 +405,40 @@
1.194 case TA_TILECFG:
1.195 MMIO_WRITE( PVR2, reg, val&0x00133333 );
1.196 break;
1.197 + case TA_INIT:
1.198 + if( val & 0x80000000 )
1.199 + pvr2_ta_init();
1.200 + break;
1.201 + case TA_REINIT:
1.202 + break;
1.203 + /**************** Scaler registers? ****************/
1.204 + case SCALERCFG:
1.205 + MMIO_WRITE( PVR2, reg, val&0x0007FFFF );
1.206 + break;
1.207 +
1.208 case YUV_ADDR:
1.209 MMIO_WRITE( PVR2, reg, val&0x00FFFFF8 );
1.210 break;
1.211 case YUV_CFG:
1.212 MMIO_WRITE( PVR2, reg, val&0x01013F3F );
1.213 break;
1.214 - case TA_INIT:
1.215 - if( val & 0x80000000 )
1.216 - pvr2_ta_init();
1.217 +
1.218 +
1.219 + /**************** Unknowns ***************/
1.220 + case PVRUNK1:
1.221 + MMIO_WRITE( PVR2, reg, val&0x000007FF );
1.222 + break;
1.223 + case PVRUNK2:
1.224 + MMIO_WRITE( PVR2, reg, val&0x00000007 );
1.225 break;
1.226 - case TA_REINIT:
1.227 + case PVRUNK3:
1.228 + MMIO_WRITE( PVR2, reg, val&0x000FFF3F );
1.229 + break;
1.230 + case PVRUNK5:
1.231 + MMIO_WRITE( PVR2, reg, val&0x0000FFFF );
1.232 + break;
1.233 + case PVRUNK6:
1.234 + MMIO_WRITE( PVR2, reg, val&0x000000FF );
1.235 break;
1.236 case PVRUNK7:
1.237 MMIO_WRITE( PVR2, reg, val&0x00000001 );
1.238 @@ -405,11 +446,65 @@
1.239 }
1.240 }
1.241
1.242 +/**
1.243 + * Calculate the current read value of the syncstat register, using
1.244 + * the current SH4 clock time as an offset from the last timeslice.
1.245 + * The register reads (LSB to MSB) as:
1.246 + * 0..9 Current scan line
1.247 + * 10 Odd/even field (1 = odd, 0 = even)
1.248 + * 11 Display active (including border and overscan)
1.249 + * 12 Horizontal sync off
1.250 + * 13 Vertical sync off
1.251 + * Note this method is probably incorrect for anything other than straight
1.252 + * interlaced PAL, and needs further testing.
1.253 + */
1.254 +uint32_t pvr2_get_sync_status()
1.255 +{
1.256 + uint32_t tmp = pvr2_state.line_remainder + sh4r.slice_cycle;
1.257 + uint32_t line = pvr2_state.line_count + (tmp / pvr2_state.line_time_ns);
1.258 + uint32_t remainder = tmp % pvr2_state.line_time_ns;
1.259 + uint32_t field = pvr2_state.odd_even_field;
1.260 + uint32_t result;
1.261 +
1.262 + if( line >= pvr2_state.total_lines ) {
1.263 + line -= pvr2_state.total_lines;
1.264 + if( pvr2_state.interlaced ) {
1.265 + field == 1 ? 0 : 1;
1.266 + }
1.267 + }
1.268 +
1.269 + result = line;
1.270 +
1.271 + if( field ) {
1.272 + result |= 0x0400;
1.273 + }
1.274 + if( (line & 0x01) == field ) {
1.275 + if( remainder > pvr2_state.hsync_width_ns ) {
1.276 + result |= 0x1000; /* !HSYNC */
1.277 + }
1.278 + if( line >= pvr2_state.vsync_lines ) {
1.279 + if( remainder > pvr2_state.front_porch_ns ) {
1.280 + result |= 0x2800; /* Display active */
1.281 + } else {
1.282 + result |= 0x2000; /* Front porch */
1.283 + }
1.284 + }
1.285 + } else {
1.286 + if( remainder < (pvr2_state.line_time_ns - pvr2_state.back_porch_ns) &&
1.287 + line >= pvr2_state.vsync_lines ) {
1.288 + result |= 0x3800; /* Display active */
1.289 + } else {
1.290 + result |= 0x1000; /* Back porch */
1.291 + }
1.292 + }
1.293 + return result;
1.294 +}
1.295 +
1.296 MMIO_REGION_READ_FN( PVR2, reg )
1.297 {
1.298 switch( reg ) {
1.299 - case DISP_BEAMPOS:
1.300 - return sh4r.icount&0x20 ? 0x2000 : 1;
1.301 + case DISP_SYNCSTAT:
1.302 + return pvr2_get_sync_status();
1.303 default:
1.304 return MMIO_READ( PVR2, reg );
1.305 }
.