revision 261:93fdb2a70e18
summary |
tree |
shortlog |
changelog |
graph |
changeset |
raw | bz2 | zip | gz changeset | 261:93fdb2a70e18 |
parent | 260:c82e26ec0cac |
child | 262:bc96e0b79308 |
author | nkeynes |
date | Wed Jan 03 09:01:51 2007 +0000 (16 years ago) |
Implement the main CRTC registers, along with the sync status register.
Timings are now pretty close to the real thing.
Timings are now pretty close to the real thing.
![]() | src/clock.h | view | annotate | diff | log | |
![]() | src/pvr2/pvr2.c | view | annotate | diff | log | |
![]() | src/pvr2/pvr2mmio.h | view | annotate | diff | log |
1.1 --- a/src/clock.h Wed Jan 03 09:00:17 2007 +00001.2 +++ b/src/clock.h Wed Jan 03 09:01:51 2007 +00001.3 @@ -1,5 +1,5 @@1.4 /**1.5 - * $Id: clock.h,v 1.3 2005-12-25 05:56:55 nkeynes Exp $1.6 + * $Id: clock.h,v 1.4 2007-01-03 09:01:51 nkeynes Exp $1.7 * External interface to the dreamcast serial port, implemented by1.8 * sh4/scif.c1.9 *1.10 @@ -27,6 +27,7 @@1.11 #define MHZ1.12 #define SH4_BASE_RATE 200 MHZ1.13 #define ARM_BASE_RATE 33 MHZ1.14 +#define PVR2_DOT_CLOCK 27 MHZ1.16 extern uint32_t sh4_freq;1.17 extern uint32_t sh4_peripheral_freq;
2.1 --- a/src/pvr2/pvr2.c Wed Jan 03 09:00:17 2007 +00002.2 +++ b/src/pvr2/pvr2.c Wed Jan 03 09:01:51 2007 +00002.3 @@ -1,5 +1,5 @@2.4 /**2.5 - * $Id: pvr2.c,v 1.33 2006-08-29 08:11:56 nkeynes Exp $2.6 + * $Id: pvr2.c,v 1.34 2007-01-03 09:01:51 nkeynes Exp $2.7 *2.8 * PVR2 (Video) Core module implementation and MMIO registers.2.9 *2.10 @@ -21,6 +21,7 @@2.11 #include "display.h"2.12 #include "mem.h"2.13 #include "asic.h"2.14 +#include "clock.h"2.15 #include "pvr2/pvr2.h"2.16 #include "sh4/sh4core.h"2.17 #define MMIO_IMPL2.18 @@ -52,7 +53,7 @@2.19 int line_time_ns;2.20 };2.22 -struct video_timing pal_timing = { 50, 625, 65, 32000 };2.23 +struct video_timing pal_timing = { 50, 625, 65, 31945 };2.24 struct video_timing ntsc_timing= { 60, 525, 65, 31746 };2.26 struct pvr2_state {2.27 @@ -61,7 +62,19 @@2.28 uint32_t line_remainder;2.29 uint32_t irq_vpos1;2.30 uint32_t irq_vpos2;2.31 + uint32_t odd_even_field; /* 1 = odd, 0 = even */2.32 gboolean retrace;2.33 +2.34 + /* timing */2.35 + uint32_t dot_clock;2.36 + uint32_t total_lines;2.37 + uint32_t line_size;2.38 + uint32_t line_time_ns;2.39 + uint32_t vsync_lines;2.40 + uint32_t hsync_width_ns;2.41 + uint32_t front_porch_ns;2.42 + uint32_t back_porch_ns;2.43 + gboolean interlaced;2.44 struct video_timing timing;2.45 } pvr2_state;2.47 @@ -75,6 +88,13 @@2.48 register_io_region( &mmio_region_PVR2TA );2.49 video_base = mem_get_region_by_name( MEM_REGION_VIDEO );2.50 texcache_init();2.51 + pvr2_state.dot_clock = 27069;2.52 + pvr2_state.total_lines = pal_timing.total_lines;2.53 + pvr2_state.line_time_ns = pal_timing.line_time_ns;2.54 + pvr2_state.front_porch_ns = 12000;2.55 + pvr2_state.back_porch_ns = 4000;2.56 + pvr2_state.hsync_width_ns = 4000;2.57 + pvr2_state.vsync_lines = 5;2.58 pvr2_reset();2.59 pvr2_ta_reset();2.60 }2.61 @@ -110,11 +130,11 @@2.62 static uint32_t pvr2_run_slice( uint32_t nanosecs )2.63 {2.64 pvr2_state.line_remainder += nanosecs;2.65 - while( pvr2_state.line_remainder >= pvr2_state.timing.line_time_ns ) {2.66 - pvr2_state.line_remainder -= pvr2_state.timing.line_time_ns;2.67 + while( pvr2_state.line_remainder >= pvr2_state.line_time_ns ) {2.68 + pvr2_state.line_remainder -= pvr2_state.line_time_ns;2.70 pvr2_state.line_count++;2.71 - if( pvr2_state.line_count == pvr2_state.timing.total_lines ) {2.72 + if( pvr2_state.line_count == pvr2_state.total_lines ) {2.73 asic_event( EVENT_RETRACE );2.74 pvr2_state.line_count = 0;2.75 pvr2_state.retrace = TRUE;2.76 @@ -153,7 +173,7 @@2.78 int dispsize = MMIO_READ( PVR2, DISP_SIZE );2.79 int dispmode = MMIO_READ( PVR2, DISP_MODE );2.80 - int vidcfg = MMIO_READ( PVR2, DISP_CFG );2.81 + int vidcfg = MMIO_READ( PVR2, DISP_SYNCCFG );2.82 int vid_stride = ((dispsize & DISPSIZE_MODULO) >> 20) - 1;2.83 int vid_lpf = ((dispsize & DISPSIZE_LPF) >> 10) + 1;2.84 int vid_ppl = ((dispsize & DISPSIZE_PPL)) + 1;2.85 @@ -222,22 +242,16 @@2.86 switch(reg) {2.87 case PVRID:2.88 case PVRVER:2.89 - case GUNPOS:2.90 - case TA_POLYPOS:2.91 - case TA_LISTPOS:2.92 - /* Readonly registers */2.93 + case GUNPOS: /* Read only registers */2.94 break;2.95 case PVRRESET:2.96 val &= 0x00000007; /* Do stuff? */2.97 MMIO_WRITE( PVR2, reg, val );2.98 break;2.99 case RENDER_START:2.100 - if( val == 0xFFFFFFFF )2.101 + if( val == 0xFFFFFFFF || val == 0x00000001 )2.102 pvr2_render_scene();2.103 break;2.104 - case PVRUNK1:2.105 - MMIO_WRITE( PVR2, reg, val&0x000007FF );2.106 - break;2.107 case RENDER_POLYBASE:2.108 MMIO_WRITE( PVR2, reg, val&0x00F00000 );2.109 break;2.110 @@ -298,9 +312,6 @@2.111 case RENDER_OBJCFG:2.112 MMIO_WRITE( PVR2, reg, val&0x003FFFFF );2.113 break;2.114 - case PVRUNK2:2.115 - MMIO_WRITE( PVR2, reg, val&0x00000007 );2.116 - break;2.117 case RENDER_TSPCLIP:2.118 MMIO_WRITE( PVR2, reg, val&0x7FFFFFFF );2.119 break;2.120 @@ -333,43 +344,50 @@2.121 case RENDER_CLAMPLO:2.122 MMIO_WRITE( PVR2, reg, val );2.123 break;2.124 - case DISP_CFG:2.125 - MMIO_WRITE( PVR2, reg, val&0x000003FF );2.126 + case RENDER_TEXSIZE:2.127 + MMIO_WRITE( PVR2, reg, val&0x00031F1F );2.128 break;2.129 + case RENDER_PALETTE:2.130 + MMIO_WRITE( PVR2, reg, val&0x00000003 );2.131 + break;2.132 +2.133 + /********** CRTC registers *************/2.134 case DISP_HBORDER:2.135 - case DISP_SYNC:2.136 case DISP_VBORDER:2.137 MMIO_WRITE( PVR2, reg, val&0x03FF03FF );2.138 break;2.139 - case DISP_SYNC2:2.140 + case DISP_TOTAL:2.141 + val = val & 0x03FF03FF;2.142 + MMIO_WRITE( PVR2, reg, val );2.143 + pvr2_state.total_lines = (val >> 16) + 1;2.144 + pvr2_state.line_size = (val & 0x03FF) + 1;2.145 + pvr2_state.line_time_ns = 1000000 * pvr2_state.line_size / pvr2_state.dot_clock;2.146 + break;2.147 + case DISP_SYNCCFG:2.148 + MMIO_WRITE( PVR2, reg, val&0x000003FF );2.149 + pvr2_state.interlaced = (val & 0x0010) ? TRUE : FALSE;2.150 + break;2.151 + case DISP_SYNCTIME:2.152 + pvr2_state.vsync_lines = (val >> 8) & 0x0F;2.153 + pvr2_state.hsync_width_ns = ((val & 0x7F) + 1) * 1000000 / pvr2_state.dot_clock;2.154 MMIO_WRITE( PVR2, reg, val&0xFFFFFF7F );2.155 break;2.156 - case RENDER_TEXSIZE:2.157 - MMIO_WRITE( PVR2, reg, val&0x00031F1F );2.158 - break;2.159 case DISP_CFG2:2.160 MMIO_WRITE( PVR2, reg, val&0x003F01FF );2.161 break;2.162 case DISP_HPOS:2.163 - MMIO_WRITE( PVR2, reg, val&0x000003FF );2.164 + val = val & 0x03FF;2.165 + pvr2_state.front_porch_ns = (val + 1) * 1000000 / pvr2_state.dot_clock;2.166 + MMIO_WRITE( PVR2, reg, val );2.167 break;2.168 case DISP_VPOS:2.169 MMIO_WRITE( PVR2, reg, val&0x03FF03FF );2.170 break;2.171 - case SCALERCFG:2.172 - MMIO_WRITE( PVR2, reg, val&0x0007FFFF );2.173 - break;2.174 - case RENDER_PALETTE:2.175 - MMIO_WRITE( PVR2, reg, val&0x00000003 );2.176 - break;2.177 - case PVRUNK3:2.178 - MMIO_WRITE( PVR2, reg, val&0x000FFF3F );2.179 - break;2.180 - case PVRUNK5:2.181 - MMIO_WRITE( PVR2, reg, val&0x0000FFFF );2.182 - break;2.183 - case PVRUNK6:2.184 - MMIO_WRITE( PVR2, reg, val&0x000000FF );2.185 +2.186 + /*********** Tile accelerator registers ***********/2.187 + case TA_POLYPOS:2.188 + case TA_LISTPOS:2.189 + /* Readonly registers */2.190 break;2.191 case TA_TILEBASE:2.192 case TA_LISTEND:2.193 @@ -387,17 +405,40 @@2.194 case TA_TILECFG:2.195 MMIO_WRITE( PVR2, reg, val&0x00133333 );2.196 break;2.197 + case TA_INIT:2.198 + if( val & 0x80000000 )2.199 + pvr2_ta_init();2.200 + break;2.201 + case TA_REINIT:2.202 + break;2.203 + /**************** Scaler registers? ****************/2.204 + case SCALERCFG:2.205 + MMIO_WRITE( PVR2, reg, val&0x0007FFFF );2.206 + break;2.207 +2.208 case YUV_ADDR:2.209 MMIO_WRITE( PVR2, reg, val&0x00FFFFF8 );2.210 break;2.211 case YUV_CFG:2.212 MMIO_WRITE( PVR2, reg, val&0x01013F3F );2.213 break;2.214 - case TA_INIT:2.215 - if( val & 0x80000000 )2.216 - pvr2_ta_init();2.217 +2.218 +2.219 + /**************** Unknowns ***************/2.220 + case PVRUNK1:2.221 + MMIO_WRITE( PVR2, reg, val&0x000007FF );2.222 + break;2.223 + case PVRUNK2:2.224 + MMIO_WRITE( PVR2, reg, val&0x00000007 );2.225 break;2.226 - case TA_REINIT:2.227 + case PVRUNK3:2.228 + MMIO_WRITE( PVR2, reg, val&0x000FFF3F );2.229 + break;2.230 + case PVRUNK5:2.231 + MMIO_WRITE( PVR2, reg, val&0x0000FFFF );2.232 + break;2.233 + case PVRUNK6:2.234 + MMIO_WRITE( PVR2, reg, val&0x000000FF );2.235 break;2.236 case PVRUNK7:2.237 MMIO_WRITE( PVR2, reg, val&0x00000001 );2.238 @@ -405,11 +446,65 @@2.239 }2.240 }2.242 +/**2.243 + * Calculate the current read value of the syncstat register, using2.244 + * the current SH4 clock time as an offset from the last timeslice.2.245 + * The register reads (LSB to MSB) as:2.246 + * 0..9 Current scan line2.247 + * 10 Odd/even field (1 = odd, 0 = even)2.248 + * 11 Display active (including border and overscan)2.249 + * 12 Horizontal sync off2.250 + * 13 Vertical sync off2.251 + * Note this method is probably incorrect for anything other than straight2.252 + * interlaced PAL, and needs further testing.2.253 + */2.254 +uint32_t pvr2_get_sync_status()2.255 +{2.256 + uint32_t tmp = pvr2_state.line_remainder + sh4r.slice_cycle;2.257 + uint32_t line = pvr2_state.line_count + (tmp / pvr2_state.line_time_ns);2.258 + uint32_t remainder = tmp % pvr2_state.line_time_ns;2.259 + uint32_t field = pvr2_state.odd_even_field;2.260 + uint32_t result;2.261 +2.262 + if( line >= pvr2_state.total_lines ) {2.263 + line -= pvr2_state.total_lines;2.264 + if( pvr2_state.interlaced ) {2.265 + field == 1 ? 0 : 1;2.266 + }2.267 + }2.268 +2.269 + result = line;2.270 +2.271 + if( field ) {2.272 + result |= 0x0400;2.273 + }2.274 + if( (line & 0x01) == field ) {2.275 + if( remainder > pvr2_state.hsync_width_ns ) {2.276 + result |= 0x1000; /* !HSYNC */2.277 + }2.278 + if( line >= pvr2_state.vsync_lines ) {2.279 + if( remainder > pvr2_state.front_porch_ns ) {2.280 + result |= 0x2800; /* Display active */2.281 + } else {2.282 + result |= 0x2000; /* Front porch */2.283 + }2.284 + }2.285 + } else {2.286 + if( remainder < (pvr2_state.line_time_ns - pvr2_state.back_porch_ns) &&2.287 + line >= pvr2_state.vsync_lines ) {2.288 + result |= 0x3800; /* Display active */2.289 + } else {2.290 + result |= 0x1000; /* Back porch */2.291 + }2.292 + }2.293 + return result;2.294 +}2.295 +2.296 MMIO_REGION_READ_FN( PVR2, reg )2.297 {2.298 switch( reg ) {2.299 - case DISP_BEAMPOS:2.300 - return sh4r.icount&0x20 ? 0x2000 : 1;2.301 + case DISP_SYNCSTAT:2.302 + return pvr2_get_sync_status();2.303 default:2.304 return MMIO_READ( PVR2, reg );2.305 }
3.1 --- a/src/pvr2/pvr2mmio.h Wed Jan 03 09:00:17 2007 +00003.2 +++ b/src/pvr2/pvr2mmio.h Wed Jan 03 09:01:51 2007 +00003.3 @@ -1,5 +1,5 @@3.4 /**3.5 - * $Id: pvr2mmio.h,v 1.7 2006-08-06 02:47:08 nkeynes Exp $3.6 + * $Id: pvr2mmio.h,v 1.8 2007-01-03 09:01:51 nkeynes Exp $3.7 *3.8 * PVR2 (video chip) MMIO register definitions.3.9 *3.10 @@ -57,18 +57,18 @@3.11 LONG_PORT( 0x0C4, GUNPOS, PORT_MRW, 0, "Lightgun position" )3.12 LONG_PORT( 0x0C8, DISP_HPOSIRQ, PORT_MRW, 0, "Raster horizontal event position" )3.13 LONG_PORT( 0x0CC, DISP_VPOSIRQ, PORT_MRW, 0, "Raster event position" )3.14 - LONG_PORT( 0x0D0, DISP_CFG, PORT_MRW, 0, "Sync configuration & enable" )3.15 + LONG_PORT( 0x0D0, DISP_SYNCCFG, PORT_MRW, 0, "Sync configuration & enable" )3.16 LONG_PORT( 0x0D4, DISP_HBORDER, PORT_MRW, 0, "Horizontal border area" )3.17 - LONG_PORT( 0x0D8, DISP_SYNC, PORT_MRW, 0, "Sync pulse timing" )3.18 + LONG_PORT( 0x0D8, DISP_TOTAL, PORT_MRW, 0, "Total display area" )3.19 LONG_PORT( 0x0DC, DISP_VBORDER, PORT_MRW, 0, "Vertical border area" )3.20 - LONG_PORT( 0x0E0, DISP_SYNC2, PORT_MRW, 0, "Sync pulse widths" )3.21 + LONG_PORT( 0x0E0, DISP_SYNCTIME, PORT_MRW, 0, "Horizontal sync pulse timing" )3.22 LONG_PORT( 0x0E4, RENDER_TEXSIZE, PORT_MRW, 0, "Texture modulo width" )3.23 LONG_PORT( 0x0E8, DISP_CFG2, PORT_MRW, 0, "Video configuration 2" )3.24 LONG_PORT( 0x0EC, DISP_HPOS, PORT_MRW, 0, "Horizontal display position" )3.25 LONG_PORT( 0x0F0, DISP_VPOS, PORT_MRW, 0, "Vertical display position" )3.26 LONG_PORT( 0x0F4, SCALERCFG, PORT_MRW, 0, "Scaler configuration (?)" )3.27 LONG_PORT( 0x108, RENDER_PALETTE, PORT_MRW, 0, "Palette configuration" )3.28 - LONG_PORT( 0x10C, DISP_BEAMPOS, PORT_R, 0, "Raster beam position" )3.29 + LONG_PORT( 0x10C, DISP_SYNCSTAT, PORT_R, 0, "Raster beam position" )3.30 LONG_PORT( 0x110, PVRUNK3, PORT_MRW, 0, "PVR2 unknown register 3" )3.31 LONG_PORT( 0x114, PVRUNK4, PORT_MRW, 0, "PVR2 unknown register 4" )3.32 LONG_PORT( 0x118, PVRUNK5, PORT_MRW, 0, "PVR2 unkown register 5" )
.