Search
lxdream.org :: lxdream :: r261:93fdb2a70e18
lxdream 0.9.1
released Jun 29
Download Now
changeset261:93fdb2a70e18
parent260:c82e26ec0cac
child262:bc96e0b79308
authornkeynes
dateWed 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.
src/clock.h
src/pvr2/pvr2.c
src/pvr2/pvr2mmio.h
1.1 --- a/src/clock.h Wed Jan 03 09:00:17 2007 +0000
1.2 +++ b/src/clock.h Wed Jan 03 09:01:51 2007 +0000
1.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 by
1.8 * sh4/scif.c
1.9 *
1.10 @@ -27,6 +27,7 @@
1.11 #define MHZ
1.12 #define SH4_BASE_RATE 200 MHZ
1.13 #define ARM_BASE_RATE 33 MHZ
1.14 +#define PVR2_DOT_CLOCK 27 MHZ
1.15
1.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 +0000
2.2 +++ b/src/pvr2/pvr2.c Wed Jan 03 09:01:51 2007 +0000
2.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_IMPL
2.18 @@ -52,7 +53,7 @@
2.19 int line_time_ns;
2.20 };
2.21
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.25
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.46
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.69
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.77
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.241
2.242 +/**
2.243 + * Calculate the current read value of the syncstat register, using
2.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 line
2.247 + * 10 Odd/even field (1 = odd, 0 = even)
2.248 + * 11 Display active (including border and overscan)
2.249 + * 12 Horizontal sync off
2.250 + * 13 Vertical sync off
2.251 + * Note this method is probably incorrect for anything other than straight
2.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 +0000
3.2 +++ b/src/pvr2/pvr2mmio.h Wed Jan 03 09:01:51 2007 +0000
3.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" )
.