nkeynes@31 | 1 | /**
|
nkeynes@56 | 2 | * $Id: pvr2.c,v 1.11 2006-01-01 08:09:42 nkeynes Exp $
|
nkeynes@31 | 3 | *
|
nkeynes@31 | 4 | * PVR2 (Video) MMIO and supporting functions.
|
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@1 | 21 | #include "video.h"
|
nkeynes@1 | 22 | #include "mem.h"
|
nkeynes@1 | 23 | #include "asic.h"
|
nkeynes@1 | 24 | #include "pvr2.h"
|
nkeynes@56 | 25 | #include "sh4/sh4core.h"
|
nkeynes@1 | 26 | #define MMIO_IMPL
|
nkeynes@1 | 27 | #include "pvr2.h"
|
nkeynes@1 | 28 |
|
nkeynes@1 | 29 | char *video_base;
|
nkeynes@1 | 30 |
|
nkeynes@15 | 31 | void pvr2_init( void );
|
nkeynes@30 | 32 | uint32_t pvr2_run_slice( uint32_t );
|
nkeynes@23 | 33 | void pvr2_next_frame( void );
|
nkeynes@15 | 34 |
|
nkeynes@23 | 35 | struct dreamcast_module pvr2_module = { "PVR2", pvr2_init, NULL, NULL,
|
nkeynes@23 | 36 | pvr2_run_slice, NULL,
|
nkeynes@15 | 37 | NULL, NULL };
|
nkeynes@15 | 38 |
|
nkeynes@1 | 39 | void pvr2_init( void )
|
nkeynes@1 | 40 | {
|
nkeynes@1 | 41 | register_io_region( &mmio_region_PVR2 );
|
nkeynes@56 | 42 | register_io_region( &mmio_region_PVR2TA );
|
nkeynes@1 | 43 | video_base = mem_get_region_by_name( MEM_REGION_VIDEO );
|
nkeynes@1 | 44 | }
|
nkeynes@1 | 45 |
|
nkeynes@23 | 46 | uint32_t pvr2_time_counter = 0;
|
nkeynes@30 | 47 | uint32_t pvr2_time_per_frame = 20000000;
|
nkeynes@23 | 48 |
|
nkeynes@30 | 49 | uint32_t pvr2_run_slice( uint32_t nanosecs )
|
nkeynes@23 | 50 | {
|
nkeynes@30 | 51 | pvr2_time_counter += nanosecs;
|
nkeynes@30 | 52 | while( pvr2_time_counter >= pvr2_time_per_frame ) {
|
nkeynes@23 | 53 | pvr2_next_frame();
|
nkeynes@23 | 54 | pvr2_time_counter -= pvr2_time_per_frame;
|
nkeynes@23 | 55 | }
|
nkeynes@30 | 56 | return nanosecs;
|
nkeynes@23 | 57 | }
|
nkeynes@23 | 58 |
|
nkeynes@1 | 59 | uint32_t vid_stride, vid_lpf, vid_ppl, vid_hres, vid_vres, vid_col;
|
nkeynes@1 | 60 | int interlaced, bChanged = 1, bEnabled = 0, vid_size = 0;
|
nkeynes@1 | 61 | char *frame_start; /* current video start address (in real memory) */
|
nkeynes@1 | 62 |
|
nkeynes@1 | 63 | /*
|
nkeynes@1 | 64 | * Display the next frame, copying the current contents of video ram to
|
nkeynes@1 | 65 | * the window. If the video configuration has changed, first recompute the
|
nkeynes@1 | 66 | * new frame size/depth.
|
nkeynes@1 | 67 | */
|
nkeynes@1 | 68 | void pvr2_next_frame( void )
|
nkeynes@1 | 69 | {
|
nkeynes@1 | 70 | if( bChanged ) {
|
nkeynes@1 | 71 | int dispsize = MMIO_READ( PVR2, DISPSIZE );
|
nkeynes@1 | 72 | int dispmode = MMIO_READ( PVR2, DISPMODE );
|
nkeynes@1 | 73 | int vidcfg = MMIO_READ( PVR2, VIDCFG );
|
nkeynes@1 | 74 | vid_stride = ((dispsize & DISPSIZE_MODULO) >> 20) - 1;
|
nkeynes@1 | 75 | vid_lpf = ((dispsize & DISPSIZE_LPF) >> 10) + 1;
|
nkeynes@1 | 76 | vid_ppl = ((dispsize & DISPSIZE_PPL)) + 1;
|
nkeynes@1 | 77 | vid_col = (dispmode & DISPMODE_COL);
|
nkeynes@1 | 78 | frame_start = video_base + MMIO_READ( PVR2, DISPADDR1 );
|
nkeynes@1 | 79 | interlaced = (vidcfg & VIDCFG_I ? 1 : 0);
|
nkeynes@1 | 80 | bEnabled = (dispmode & DISPMODE_DE) && (vidcfg & VIDCFG_VO ) ? 1 : 0;
|
nkeynes@1 | 81 | vid_size = (vid_ppl * vid_lpf) << (interlaced ? 3 : 2);
|
nkeynes@1 | 82 | vid_hres = vid_ppl;
|
nkeynes@1 | 83 | vid_vres = vid_lpf;
|
nkeynes@1 | 84 | if( interlaced ) vid_vres <<= 1;
|
nkeynes@1 | 85 | switch( vid_col ) {
|
nkeynes@1 | 86 | case MODE_RGB15:
|
nkeynes@1 | 87 | case MODE_RGB16: vid_hres <<= 1; break;
|
nkeynes@1 | 88 | case MODE_RGB24: vid_hres *= 3; break;
|
nkeynes@1 | 89 | case MODE_RGB32: vid_hres <<= 2; break;
|
nkeynes@1 | 90 | }
|
nkeynes@1 | 91 | vid_hres >>= 2;
|
nkeynes@1 | 92 | video_update_size( vid_hres, vid_vres, vid_col );
|
nkeynes@1 | 93 | bChanged = 0;
|
nkeynes@1 | 94 | }
|
nkeynes@1 | 95 | if( bEnabled ) {
|
nkeynes@1 | 96 | /* Assume bit depths match for now... */
|
nkeynes@1 | 97 | memcpy( video_data, frame_start, vid_size );
|
nkeynes@1 | 98 | } else {
|
nkeynes@1 | 99 | memset( video_data, 0, vid_size );
|
nkeynes@1 | 100 | }
|
nkeynes@1 | 101 | video_update_frame();
|
nkeynes@1 | 102 | asic_event( EVENT_SCANLINE1 );
|
nkeynes@1 | 103 | asic_event( EVENT_SCANLINE2 );
|
nkeynes@1 | 104 | asic_event( EVENT_RETRACE );
|
nkeynes@1 | 105 | }
|
nkeynes@1 | 106 |
|
nkeynes@1 | 107 | void mmio_region_PVR2_write( uint32_t reg, uint32_t val )
|
nkeynes@1 | 108 | {
|
nkeynes@1 | 109 | if( reg >= 0x200 && reg < 0x600 ) { /* Fog table */
|
nkeynes@1 | 110 | MMIO_WRITE( PVR2, reg, val );
|
nkeynes@1 | 111 | /* I don't want to hear about these */
|
nkeynes@1 | 112 | return;
|
nkeynes@1 | 113 | }
|
nkeynes@1 | 114 |
|
nkeynes@1 | 115 | INFO( "PVR2 write to %08X <= %08X [%s: %s]", reg, val,
|
nkeynes@1 | 116 | MMIO_REGID(PVR2,reg), MMIO_REGDESC(PVR2,reg) );
|
nkeynes@1 | 117 |
|
nkeynes@1 | 118 | switch(reg) {
|
nkeynes@1 | 119 | case DISPSIZE: bChanged = 1;
|
nkeynes@1 | 120 | case DISPMODE: bChanged = 1;
|
nkeynes@1 | 121 | case DISPADDR1: bChanged = 1;
|
nkeynes@1 | 122 | case DISPADDR2: bChanged = 1;
|
nkeynes@1 | 123 | case VIDCFG: bChanged = 1;
|
nkeynes@1 | 124 | break;
|
nkeynes@1 | 125 |
|
nkeynes@1 | 126 | }
|
nkeynes@1 | 127 | MMIO_WRITE( PVR2, reg, val );
|
nkeynes@1 | 128 | }
|
nkeynes@1 | 129 |
|
nkeynes@1 | 130 | MMIO_REGION_READ_FN( PVR2, reg )
|
nkeynes@1 | 131 | {
|
nkeynes@1 | 132 | switch( reg ) {
|
nkeynes@1 | 133 | case BEAMPOS:
|
nkeynes@2 | 134 | return sh4r.icount&0x20 ? 0x2000 : 1;
|
nkeynes@1 | 135 | default:
|
nkeynes@1 | 136 | return MMIO_READ( PVR2, reg );
|
nkeynes@1 | 137 | }
|
nkeynes@1 | 138 | }
|
nkeynes@19 | 139 |
|
nkeynes@19 | 140 | void pvr2_set_base_address( uint32_t base )
|
nkeynes@19 | 141 | {
|
nkeynes@19 | 142 | mmio_region_PVR2_write( DISPADDR1, base );
|
nkeynes@19 | 143 | }
|
nkeynes@56 | 144 |
|
nkeynes@56 | 145 |
|
nkeynes@56 | 146 | int32_t mmio_region_PVR2TA_read( uint32_t reg )
|
nkeynes@56 | 147 | {
|
nkeynes@56 | 148 | return 0xFFFFFFFF;
|
nkeynes@56 | 149 | }
|
nkeynes@56 | 150 |
|
nkeynes@56 | 151 | char pvr2ta_remainder[8];
|
nkeynes@56 | 152 |
|
nkeynes@56 | 153 | void mmio_region_PVR2TA_write( uint32_t reg, uint32_t val )
|
nkeynes@56 | 154 | {
|
nkeynes@56 | 155 |
|
nkeynes@56 | 156 | }
|
nkeynes@56 | 157 |
|
nkeynes@56 | 158 | void pvr2ta_write( char *buf, uint32_t length )
|
nkeynes@56 | 159 | {
|
nkeynes@56 | 160 |
|
nkeynes@56 | 161 | }
|