nkeynes@31 | 1 | /**
|
nkeynes@586 | 2 | * $Id$
|
nkeynes@31 | 3 | *
|
nkeynes@31 | 4 | * Support for the miscellaneous ASIC functions (Primarily event multiplexing,
|
nkeynes@31 | 5 | * and DMA).
|
nkeynes@31 | 6 | *
|
nkeynes@31 | 7 | * Copyright (c) 2005 Nathan Keynes.
|
nkeynes@31 | 8 | *
|
nkeynes@31 | 9 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@31 | 10 | * it under the terms of the GNU General Public License as published by
|
nkeynes@31 | 11 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@31 | 12 | * (at your option) any later version.
|
nkeynes@31 | 13 | *
|
nkeynes@31 | 14 | * This program is distributed in the hope that it will be useful,
|
nkeynes@31 | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@31 | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@31 | 17 | * GNU General Public License for more details.
|
nkeynes@31 | 18 | */
|
nkeynes@35 | 19 |
|
nkeynes@35 | 20 | #define MODULE asic_module
|
nkeynes@35 | 21 |
|
nkeynes@1 | 22 | #include <assert.h>
|
nkeynes@137 | 23 | #include <stdlib.h>
|
nkeynes@1 | 24 | #include "dream.h"
|
nkeynes@1 | 25 | #include "mem.h"
|
nkeynes@1 | 26 | #include "sh4/intc.h"
|
nkeynes@56 | 27 | #include "sh4/dmac.h"
|
nkeynes@586 | 28 | #include "sh4/sh4.h"
|
nkeynes@2 | 29 | #include "dreamcast.h"
|
nkeynes@25 | 30 | #include "maple/maple.h"
|
nkeynes@25 | 31 | #include "gdrom/ide.h"
|
nkeynes@422 | 32 | #include "pvr2/pvr2.h"
|
nkeynes@15 | 33 | #include "asic.h"
|
nkeynes@1 | 34 | #define MMIO_IMPL
|
nkeynes@1 | 35 | #include "asic.h"
|
nkeynes@1 | 36 | /*
|
nkeynes@1 | 37 | * Open questions:
|
nkeynes@1 | 38 | * 1) Does changing the mask after event occurance result in the
|
nkeynes@1 | 39 | * interrupt being delivered immediately?
|
nkeynes@1 | 40 | * TODO: Logic diagram of ASIC event/interrupt logic.
|
nkeynes@1 | 41 | *
|
nkeynes@1 | 42 | * ... don't even get me started on the "EXTDMA" page, about which, apparently,
|
nkeynes@1 | 43 | * practically nothing is publicly known...
|
nkeynes@1 | 44 | */
|
nkeynes@1 | 45 |
|
nkeynes@155 | 46 | static void asic_check_cleared_events( void );
|
nkeynes@155 | 47 | static void asic_init( void );
|
nkeynes@155 | 48 | static void asic_reset( void );
|
nkeynes@302 | 49 | static uint32_t asic_run_slice( uint32_t nanosecs );
|
nkeynes@155 | 50 | static void asic_save_state( FILE *f );
|
nkeynes@155 | 51 | static int asic_load_state( FILE *f );
|
nkeynes@302 | 52 | static uint32_t g2_update_fifo_status( uint32_t slice_cycle );
|
nkeynes@155 | 53 |
|
nkeynes@302 | 54 | struct dreamcast_module asic_module = { "ASIC", asic_init, asic_reset, NULL, asic_run_slice,
|
nkeynes@736 | 55 | NULL, asic_save_state, asic_load_state };
|
nkeynes@15 | 56 |
|
nkeynes@302 | 57 | #define G2_BIT5_TICKS 60
|
nkeynes@302 | 58 | #define G2_BIT4_TICKS 160
|
nkeynes@302 | 59 | #define G2_BIT0_ON_TICKS 120
|
nkeynes@302 | 60 | #define G2_BIT0_OFF_TICKS 420
|
nkeynes@137 | 61 |
|
nkeynes@137 | 62 | struct asic_g2_state {
|
nkeynes@302 | 63 | int bit5_off_timer;
|
nkeynes@302 | 64 | int bit4_on_timer;
|
nkeynes@302 | 65 | int bit4_off_timer;
|
nkeynes@302 | 66 | int bit0_on_timer;
|
nkeynes@302 | 67 | int bit0_off_timer;
|
nkeynes@155 | 68 | };
|
nkeynes@155 | 69 |
|
nkeynes@155 | 70 | static struct asic_g2_state g2_state;
|
nkeynes@155 | 71 |
|
nkeynes@302 | 72 | static uint32_t asic_run_slice( uint32_t nanosecs )
|
nkeynes@302 | 73 | {
|
nkeynes@302 | 74 | g2_update_fifo_status(nanosecs);
|
nkeynes@302 | 75 | if( g2_state.bit5_off_timer <= (int32_t)nanosecs ) {
|
nkeynes@736 | 76 | g2_state.bit5_off_timer = -1;
|
nkeynes@302 | 77 | } else {
|
nkeynes@736 | 78 | g2_state.bit5_off_timer -= nanosecs;
|
nkeynes@302 | 79 | }
|
nkeynes@302 | 80 |
|
nkeynes@302 | 81 | if( g2_state.bit4_off_timer <= (int32_t)nanosecs ) {
|
nkeynes@736 | 82 | g2_state.bit4_off_timer = -1;
|
nkeynes@302 | 83 | } else {
|
nkeynes@736 | 84 | g2_state.bit4_off_timer -= nanosecs;
|
nkeynes@302 | 85 | }
|
nkeynes@302 | 86 | if( g2_state.bit4_on_timer <= (int32_t)nanosecs ) {
|
nkeynes@736 | 87 | g2_state.bit4_on_timer = -1;
|
nkeynes@302 | 88 | } else {
|
nkeynes@736 | 89 | g2_state.bit4_on_timer -= nanosecs;
|
nkeynes@302 | 90 | }
|
nkeynes@736 | 91 |
|
nkeynes@302 | 92 | if( g2_state.bit0_off_timer <= (int32_t)nanosecs ) {
|
nkeynes@736 | 93 | g2_state.bit0_off_timer = -1;
|
nkeynes@302 | 94 | } else {
|
nkeynes@736 | 95 | g2_state.bit0_off_timer -= nanosecs;
|
nkeynes@302 | 96 | }
|
nkeynes@302 | 97 | if( g2_state.bit0_on_timer <= (int32_t)nanosecs ) {
|
nkeynes@736 | 98 | g2_state.bit0_on_timer = -1;
|
nkeynes@302 | 99 | } else {
|
nkeynes@736 | 100 | g2_state.bit0_on_timer -= nanosecs;
|
nkeynes@302 | 101 | }
|
nkeynes@736 | 102 |
|
nkeynes@302 | 103 | return nanosecs;
|
nkeynes@302 | 104 | }
|
nkeynes@302 | 105 |
|
nkeynes@155 | 106 | static void asic_init( void )
|
nkeynes@155 | 107 | {
|
nkeynes@155 | 108 | register_io_region( &mmio_region_ASIC );
|
nkeynes@155 | 109 | register_io_region( &mmio_region_EXTDMA );
|
nkeynes@155 | 110 | asic_reset();
|
nkeynes@155 | 111 | }
|
nkeynes@155 | 112 |
|
nkeynes@155 | 113 | static void asic_reset( void )
|
nkeynes@155 | 114 | {
|
nkeynes@302 | 115 | memset( &g2_state, 0xFF, sizeof(g2_state) );
|
nkeynes@155 | 116 | }
|
nkeynes@155 | 117 |
|
nkeynes@155 | 118 | static void asic_save_state( FILE *f )
|
nkeynes@155 | 119 | {
|
nkeynes@155 | 120 | fwrite( &g2_state, sizeof(g2_state), 1, f );
|
nkeynes@155 | 121 | }
|
nkeynes@155 | 122 |
|
nkeynes@155 | 123 | static int asic_load_state( FILE *f )
|
nkeynes@155 | 124 | {
|
nkeynes@155 | 125 | if( fread( &g2_state, sizeof(g2_state), 1, f ) != 1 )
|
nkeynes@736 | 126 | return 1;
|
nkeynes@155 | 127 | else
|
nkeynes@736 | 128 | return 0;
|
nkeynes@155 | 129 | }
|
nkeynes@155 | 130 |
|
nkeynes@137 | 131 |
|
nkeynes@302 | 132 | /**
|
nkeynes@302 | 133 | * Setup the timers for the 3 FIFO status bits following a write through the G2
|
nkeynes@302 | 134 | * bus from the SH4 side. The timing is roughly as follows: (times are
|
nkeynes@302 | 135 | * approximate based on software readings - I wouldn't take this as gospel but
|
nkeynes@302 | 136 | * it seems to be enough to fool most programs).
|
nkeynes@302 | 137 | * 0ns: Bit 5 (Input fifo?) goes high immediately on the write
|
nkeynes@302 | 138 | * 40ns: Bit 5 goes low and bit 4 goes high
|
nkeynes@302 | 139 | * 120ns: Bit 4 goes low, bit 0 goes high
|
nkeynes@302 | 140 | * 240ns: Bit 0 goes low.
|
nkeynes@302 | 141 | *
|
nkeynes@302 | 142 | * Additional writes while the FIFO is in operation extend the time that the
|
nkeynes@302 | 143 | * bits remain high as one might expect, without altering the time at which
|
nkeynes@302 | 144 | * they initially go high.
|
nkeynes@302 | 145 | */
|
nkeynes@137 | 146 | void asic_g2_write_word()
|
nkeynes@137 | 147 | {
|
nkeynes@302 | 148 | if( g2_state.bit5_off_timer < (int32_t)sh4r.slice_cycle ) {
|
nkeynes@736 | 149 | g2_state.bit5_off_timer = sh4r.slice_cycle + G2_BIT5_TICKS;
|
nkeynes@302 | 150 | } else {
|
nkeynes@736 | 151 | g2_state.bit5_off_timer += G2_BIT5_TICKS;
|
nkeynes@302 | 152 | }
|
nkeynes@302 | 153 |
|
nkeynes@302 | 154 | if( g2_state.bit4_on_timer < (int32_t)sh4r.slice_cycle ) {
|
nkeynes@736 | 155 | g2_state.bit4_on_timer = sh4r.slice_cycle + G2_BIT5_TICKS;
|
nkeynes@302 | 156 | }
|
nkeynes@302 | 157 |
|
nkeynes@302 | 158 | if( g2_state.bit4_off_timer < (int32_t)sh4r.slice_cycle ) {
|
nkeynes@736 | 159 | g2_state.bit4_off_timer = g2_state.bit4_on_timer + G2_BIT4_TICKS;
|
nkeynes@302 | 160 | } else {
|
nkeynes@736 | 161 | g2_state.bit4_off_timer += G2_BIT4_TICKS;
|
nkeynes@302 | 162 | }
|
nkeynes@302 | 163 |
|
nkeynes@302 | 164 | if( g2_state.bit0_on_timer < (int32_t)sh4r.slice_cycle ) {
|
nkeynes@736 | 165 | g2_state.bit0_on_timer = sh4r.slice_cycle + G2_BIT0_ON_TICKS;
|
nkeynes@302 | 166 | }
|
nkeynes@302 | 167 |
|
nkeynes@302 | 168 | if( g2_state.bit0_off_timer < (int32_t)sh4r.slice_cycle ) {
|
nkeynes@736 | 169 | g2_state.bit0_off_timer = g2_state.bit0_on_timer + G2_BIT0_OFF_TICKS;
|
nkeynes@137 | 170 | } else {
|
nkeynes@736 | 171 | g2_state.bit0_off_timer += G2_BIT0_OFF_TICKS;
|
nkeynes@137 | 172 | }
|
nkeynes@302 | 173 |
|
nkeynes@137 | 174 | MMIO_WRITE( ASIC, G2STATUS, MMIO_READ(ASIC, G2STATUS) | 0x20 );
|
nkeynes@137 | 175 | }
|
nkeynes@137 | 176 |
|
nkeynes@302 | 177 | static uint32_t g2_update_fifo_status( uint32_t nanos )
|
nkeynes@137 | 178 | {
|
nkeynes@302 | 179 | uint32_t val = MMIO_READ( ASIC, G2STATUS );
|
nkeynes@302 | 180 | if( ((uint32_t)g2_state.bit5_off_timer) <= nanos ) {
|
nkeynes@736 | 181 | val = val & (~0x20);
|
nkeynes@736 | 182 | g2_state.bit5_off_timer = -1;
|
nkeynes@163 | 183 | }
|
nkeynes@302 | 184 | if( ((uint32_t)g2_state.bit4_on_timer) <= nanos ) {
|
nkeynes@736 | 185 | val = val | 0x10;
|
nkeynes@736 | 186 | g2_state.bit4_on_timer = -1;
|
nkeynes@302 | 187 | }
|
nkeynes@302 | 188 | if( ((uint32_t)g2_state.bit4_off_timer) <= nanos ) {
|
nkeynes@736 | 189 | val = val & (~0x10);
|
nkeynes@736 | 190 | g2_state.bit4_off_timer = -1;
|
nkeynes@302 | 191 | }
|
nkeynes@302 | 192 |
|
nkeynes@302 | 193 | if( ((uint32_t)g2_state.bit0_on_timer) <= nanos ) {
|
nkeynes@736 | 194 | val = val | 0x01;
|
nkeynes@736 | 195 | g2_state.bit0_on_timer = -1;
|
nkeynes@302 | 196 | }
|
nkeynes@302 | 197 | if( ((uint32_t)g2_state.bit0_off_timer) <= nanos ) {
|
nkeynes@736 | 198 | val = val & (~0x01);
|
nkeynes@736 | 199 | g2_state.bit0_off_timer = -1;
|
nkeynes@302 | 200 | }
|
nkeynes@302 | 201 |
|
nkeynes@302 | 202 | MMIO_WRITE( ASIC, G2STATUS, val );
|
nkeynes@302 | 203 | return val;
|
nkeynes@137 | 204 | }
|
nkeynes@137 | 205 |
|
nkeynes@302 | 206 | static int g2_read_status() {
|
nkeynes@302 | 207 | return g2_update_fifo_status( sh4r.slice_cycle );
|
nkeynes@302 | 208 | }
|
nkeynes@302 | 209 |
|
nkeynes@20 | 210 |
|
nkeynes@155 | 211 | void asic_event( int event )
|
nkeynes@1 | 212 | {
|
nkeynes@155 | 213 | int offset = ((event&0x60)>>3);
|
nkeynes@155 | 214 | int result = (MMIO_READ(ASIC, PIRQ0 + offset)) |= (1<<(event&0x1F));
|
nkeynes@155 | 215 |
|
nkeynes@155 | 216 | if( result & MMIO_READ(ASIC, IRQA0 + offset) )
|
nkeynes@155 | 217 | intc_raise_interrupt( INT_IRQ13 );
|
nkeynes@155 | 218 | if( result & MMIO_READ(ASIC, IRQB0 + offset) )
|
nkeynes@155 | 219 | intc_raise_interrupt( INT_IRQ11 );
|
nkeynes@155 | 220 | if( result & MMIO_READ(ASIC, IRQC0 + offset) )
|
nkeynes@155 | 221 | intc_raise_interrupt( INT_IRQ9 );
|
nkeynes@305 | 222 |
|
nkeynes@305 | 223 | if( event >= 64 ) { /* Third word */
|
nkeynes@736 | 224 | asic_event( EVENT_CASCADE2 );
|
nkeynes@305 | 225 | } else if( event >= 32 ) { /* Second word */
|
nkeynes@736 | 226 | asic_event( EVENT_CASCADE1 );
|
nkeynes@305 | 227 | }
|
nkeynes@1 | 228 | }
|
nkeynes@1 | 229 |
|
nkeynes@155 | 230 | void asic_clear_event( int event ) {
|
nkeynes@155 | 231 | int offset = ((event&0x60)>>3);
|
nkeynes@155 | 232 | uint32_t result = MMIO_READ(ASIC, PIRQ0 + offset) & (~(1<<(event&0x1F)));
|
nkeynes@155 | 233 | MMIO_WRITE( ASIC, PIRQ0 + offset, result );
|
nkeynes@305 | 234 | if( result == 0 ) {
|
nkeynes@736 | 235 | /* clear cascades if necessary */
|
nkeynes@736 | 236 | if( event >= 64 ) {
|
nkeynes@736 | 237 | MMIO_WRITE( ASIC, PIRQ0, MMIO_READ( ASIC, PIRQ0 ) & 0x7FFFFFFF );
|
nkeynes@736 | 238 | } else if( event >= 32 ) {
|
nkeynes@736 | 239 | MMIO_WRITE( ASIC, PIRQ0, MMIO_READ( ASIC, PIRQ0 ) & 0xBFFFFFFF );
|
nkeynes@736 | 240 | }
|
nkeynes@305 | 241 | }
|
nkeynes@736 | 242 |
|
nkeynes@155 | 243 | asic_check_cleared_events();
|
nkeynes@155 | 244 | }
|
nkeynes@155 | 245 |
|
nkeynes@155 | 246 | void asic_check_cleared_events( )
|
nkeynes@155 | 247 | {
|
nkeynes@155 | 248 | int i, setA = 0, setB = 0, setC = 0;
|
nkeynes@155 | 249 | uint32_t bits;
|
nkeynes@594 | 250 | for( i=0; i<12; i+=4 ) {
|
nkeynes@736 | 251 | bits = MMIO_READ( ASIC, PIRQ0 + i );
|
nkeynes@736 | 252 | setA |= (bits & MMIO_READ(ASIC, IRQA0 + i ));
|
nkeynes@736 | 253 | setB |= (bits & MMIO_READ(ASIC, IRQB0 + i ));
|
nkeynes@736 | 254 | setC |= (bits & MMIO_READ(ASIC, IRQC0 + i ));
|
nkeynes@155 | 255 | }
|
nkeynes@155 | 256 | if( setA == 0 )
|
nkeynes@736 | 257 | intc_clear_interrupt( INT_IRQ13 );
|
nkeynes@155 | 258 | if( setB == 0 )
|
nkeynes@736 | 259 | intc_clear_interrupt( INT_IRQ11 );
|
nkeynes@155 | 260 | if( setC == 0 )
|
nkeynes@736 | 261 | intc_clear_interrupt( INT_IRQ9 );
|
nkeynes@155 | 262 | }
|
nkeynes@155 | 263 |
|
nkeynes@594 | 264 | void asic_event_mask_changed( )
|
nkeynes@594 | 265 | {
|
nkeynes@594 | 266 | int i, setA = 0, setB = 0, setC = 0;
|
nkeynes@594 | 267 | uint32_t bits;
|
nkeynes@594 | 268 | for( i=0; i<12; i+=4 ) {
|
nkeynes@736 | 269 | bits = MMIO_READ( ASIC, PIRQ0 + i );
|
nkeynes@736 | 270 | setA |= (bits & MMIO_READ(ASIC, IRQA0 + i ));
|
nkeynes@736 | 271 | setB |= (bits & MMIO_READ(ASIC, IRQB0 + i ));
|
nkeynes@736 | 272 | setC |= (bits & MMIO_READ(ASIC, IRQC0 + i ));
|
nkeynes@594 | 273 | }
|
nkeynes@594 | 274 | if( setA == 0 )
|
nkeynes@736 | 275 | intc_clear_interrupt( INT_IRQ13 );
|
nkeynes@594 | 276 | else
|
nkeynes@736 | 277 | intc_raise_interrupt( INT_IRQ13 );
|
nkeynes@594 | 278 | if( setB == 0 )
|
nkeynes@736 | 279 | intc_clear_interrupt( INT_IRQ11 );
|
nkeynes@594 | 280 | else
|
nkeynes@736 | 281 | intc_raise_interrupt( INT_IRQ11 );
|
nkeynes@594 | 282 | if( setC == 0 )
|
nkeynes@736 | 283 | intc_clear_interrupt( INT_IRQ9 );
|
nkeynes@594 | 284 | else
|
nkeynes@736 | 285 | intc_raise_interrupt( INT_IRQ9 );
|
nkeynes@594 | 286 | }
|
nkeynes@594 | 287 |
|
nkeynes@279 | 288 | void g2_dma_transfer( int channel )
|
nkeynes@279 | 289 | {
|
nkeynes@279 | 290 | uint32_t offset = channel << 5;
|
nkeynes@279 | 291 |
|
nkeynes@302 | 292 | if( MMIO_READ( EXTDMA, G2DMA0CTL1 + offset ) == 1 ) {
|
nkeynes@736 | 293 | if( MMIO_READ( EXTDMA, G2DMA0CTL2 + offset ) == 1 ) {
|
nkeynes@736 | 294 | uint32_t extaddr = MMIO_READ( EXTDMA, G2DMA0EXT + offset );
|
nkeynes@736 | 295 | uint32_t sh4addr = MMIO_READ( EXTDMA, G2DMA0SH4 + offset );
|
nkeynes@736 | 296 | uint32_t length = MMIO_READ( EXTDMA, G2DMA0SIZ + offset ) & 0x1FFFFFFF;
|
nkeynes@736 | 297 | uint32_t dir = MMIO_READ( EXTDMA, G2DMA0DIR + offset );
|
nkeynes@736 | 298 | // uint32_t mode = MMIO_READ( EXTDMA, G2DMA0MOD + offset );
|
nkeynes@736 | 299 | unsigned char buf[length];
|
nkeynes@736 | 300 | if( dir == 0 ) { /* SH4 to device */
|
nkeynes@736 | 301 | mem_copy_from_sh4( buf, sh4addr, length );
|
nkeynes@736 | 302 | mem_copy_to_sh4( extaddr, buf, length );
|
nkeynes@736 | 303 | } else { /* Device to SH4 */
|
nkeynes@736 | 304 | mem_copy_from_sh4( buf, extaddr, length );
|
nkeynes@736 | 305 | mem_copy_to_sh4( sh4addr, buf, length );
|
nkeynes@736 | 306 | }
|
nkeynes@736 | 307 | MMIO_WRITE( EXTDMA, G2DMA0CTL2 + offset, 0 );
|
nkeynes@736 | 308 | asic_event( EVENT_G2_DMA0 + channel );
|
nkeynes@736 | 309 | } else {
|
nkeynes@736 | 310 | MMIO_WRITE( EXTDMA, G2DMA0CTL2 + offset, 0 );
|
nkeynes@736 | 311 | }
|
nkeynes@279 | 312 | }
|
nkeynes@279 | 313 | }
|
nkeynes@155 | 314 |
|
nkeynes@155 | 315 | void asic_ide_dma_transfer( )
|
nkeynes@155 | 316 | {
|
nkeynes@158 | 317 | if( MMIO_READ( EXTDMA, IDEDMACTL2 ) == 1 ) {
|
nkeynes@736 | 318 | if( MMIO_READ( EXTDMA, IDEDMACTL1 ) == 1 ) {
|
nkeynes@736 | 319 | MMIO_WRITE( EXTDMA, IDEDMATXSIZ, 0 );
|
nkeynes@736 | 320 |
|
nkeynes@736 | 321 | uint32_t addr = MMIO_READ( EXTDMA, IDEDMASH4 );
|
nkeynes@736 | 322 | uint32_t length = MMIO_READ( EXTDMA, IDEDMASIZ );
|
nkeynes@736 | 323 | // int dir = MMIO_READ( EXTDMA, IDEDMADIR );
|
nkeynes@736 | 324 |
|
nkeynes@736 | 325 | uint32_t xfer = ide_read_data_dma( addr, length );
|
nkeynes@736 | 326 | MMIO_WRITE( EXTDMA, IDEDMATXSIZ, xfer );
|
nkeynes@736 | 327 | MMIO_WRITE( EXTDMA, IDEDMACTL2, 0 );
|
nkeynes@833 | 328 | asic_event( EVENT_IDE_DMA );
|
nkeynes@736 | 329 | } else { /* 0 */
|
nkeynes@736 | 330 | MMIO_WRITE( EXTDMA, IDEDMACTL2, 0 );
|
nkeynes@736 | 331 | }
|
nkeynes@155 | 332 | }
|
nkeynes@155 | 333 | }
|
nkeynes@155 | 334 |
|
nkeynes@325 | 335 | void pvr_dma_transfer( )
|
nkeynes@325 | 336 | {
|
nkeynes@325 | 337 | sh4addr_t destaddr = MMIO_READ( ASIC, PVRDMADEST) &0x1FFFFFE0;
|
nkeynes@325 | 338 | uint32_t count = MMIO_READ( ASIC, PVRDMACNT );
|
nkeynes@430 | 339 | unsigned char *data = alloca( count );
|
nkeynes@325 | 340 | uint32_t rcount = DMAC_get_buffer( 2, data, count );
|
nkeynes@325 | 341 | if( rcount != count )
|
nkeynes@736 | 342 | WARN( "PVR received %08X bytes from DMA, expected %08X", rcount, count );
|
nkeynes@736 | 343 |
|
nkeynes@325 | 344 | pvr2_dma_write( destaddr, data, rcount );
|
nkeynes@736 | 345 |
|
nkeynes@325 | 346 | MMIO_WRITE( ASIC, PVRDMACTL, 0 );
|
nkeynes@325 | 347 | MMIO_WRITE( ASIC, PVRDMACNT, 0 );
|
nkeynes@325 | 348 | if( destaddr & 0x01000000 ) { /* Write to texture RAM */
|
nkeynes@736 | 349 | MMIO_WRITE( ASIC, PVRDMADEST, destaddr + rcount );
|
nkeynes@325 | 350 | }
|
nkeynes@325 | 351 | asic_event( EVENT_PVR_DMA );
|
nkeynes@325 | 352 | }
|
nkeynes@155 | 353 |
|
nkeynes@855 | 354 | void pvr_dma2_transfer()
|
nkeynes@855 | 355 | {
|
nkeynes@855 | 356 | if( MMIO_READ( EXTDMA, PVRDMA2CTL2 ) == 1 ) {
|
nkeynes@855 | 357 | if( MMIO_READ( EXTDMA, PVRDMA2CTL1 ) == 1 ) {
|
nkeynes@855 | 358 | sh4addr_t extaddr = MMIO_READ( EXTDMA, PVRDMA2EXT );
|
nkeynes@855 | 359 | sh4addr_t sh4addr = MMIO_READ( EXTDMA, PVRDMA2SH4 );
|
nkeynes@855 | 360 | int dir = MMIO_READ( EXTDMA, PVRDMA2DIR );
|
nkeynes@855 | 361 | uint32_t length = MMIO_READ( EXTDMA, PVRDMA2SIZ );
|
nkeynes@855 | 362 | unsigned char buf[length];
|
nkeynes@855 | 363 | if( dir == 0 ) { /* SH4 to PVR */
|
nkeynes@855 | 364 | mem_copy_from_sh4( buf, sh4addr, length );
|
nkeynes@855 | 365 | mem_copy_to_sh4( extaddr, buf, length );
|
nkeynes@855 | 366 | } else { /* PVR to SH4 */
|
nkeynes@855 | 367 | mem_copy_from_sh4( buf, extaddr, length );
|
nkeynes@855 | 368 | mem_copy_to_sh4( sh4addr, buf, length );
|
nkeynes@855 | 369 | }
|
nkeynes@855 | 370 | MMIO_WRITE( EXTDMA, PVRDMA2CTL2, 0 );
|
nkeynes@855 | 371 | asic_event( EVENT_PVR_DMA2 );
|
nkeynes@855 | 372 | }
|
nkeynes@855 | 373 | }
|
nkeynes@855 | 374 | }
|
nkeynes@855 | 375 |
|
nkeynes@728 | 376 | void sort_dma_transfer( )
|
nkeynes@728 | 377 | {
|
nkeynes@728 | 378 | sh4addr_t table_addr = MMIO_READ( ASIC, SORTDMATBL );
|
nkeynes@728 | 379 | sh4addr_t data_addr = MMIO_READ( ASIC, SORTDMADATA );
|
nkeynes@728 | 380 | int table_size = MMIO_READ( ASIC, SORTDMATSIZ );
|
nkeynes@753 | 381 | int addr_shift = MMIO_READ( ASIC, SORTDMAASIZ ) ? 5 : 0;
|
nkeynes@753 | 382 | int count = 1;
|
nkeynes@736 | 383 |
|
nkeynes@753 | 384 | uint32_t *table32 = (uint32_t *)mem_get_region( table_addr );
|
nkeynes@753 | 385 | uint16_t *table16 = (uint16_t *)table32;
|
nkeynes@753 | 386 | uint32_t next = table_size ? (*table32++) : (uint32_t)(*table16++);
|
nkeynes@753 | 387 | while(1) {
|
nkeynes@753 | 388 | next &= 0x07FFFFFF;
|
nkeynes@753 | 389 | if( next == 1 ) {
|
nkeynes@753 | 390 | next = table_size ? (*table32++) : (uint32_t)(*table16++);
|
nkeynes@753 | 391 | count++;
|
nkeynes@753 | 392 | continue;
|
nkeynes@753 | 393 | } else if( next == 2 ) {
|
nkeynes@753 | 394 | asic_event( EVENT_SORT_DMA );
|
nkeynes@753 | 395 | break;
|
nkeynes@753 | 396 | }
|
nkeynes@753 | 397 | uint32_t *data = (uint32_t *)mem_get_region(data_addr + (next<<addr_shift));
|
nkeynes@753 | 398 | if( data == NULL ) {
|
nkeynes@753 | 399 | break;
|
nkeynes@753 | 400 | }
|
nkeynes@753 | 401 |
|
nkeynes@753 | 402 | uint32_t *poly = pvr2_ta_find_polygon_context(data, 128);
|
nkeynes@753 | 403 | if( poly == NULL ) {
|
nkeynes@753 | 404 | asic_event( EVENT_SORT_DMA_ERR );
|
nkeynes@753 | 405 | break;
|
nkeynes@753 | 406 | }
|
nkeynes@753 | 407 | uint32_t size = poly[6] & 0xFF;
|
nkeynes@753 | 408 | if( size == 0 ) {
|
nkeynes@753 | 409 | size = 0x100;
|
nkeynes@753 | 410 | }
|
nkeynes@753 | 411 | next = poly[7];
|
nkeynes@753 | 412 | pvr2_ta_write( (unsigned char *)data, size<<5 );
|
nkeynes@753 | 413 | }
|
nkeynes@753 | 414 |
|
nkeynes@753 | 415 | MMIO_WRITE( ASIC, SORTDMACNT, count );
|
nkeynes@753 | 416 | MMIO_WRITE( ASIC, SORTDMACTL, 0 );
|
nkeynes@728 | 417 | }
|
nkeynes@728 | 418 |
|
nkeynes@929 | 419 | MMIO_REGION_READ_FN( ASIC, reg )
|
nkeynes@1 | 420 | {
|
nkeynes@929 | 421 | int32_t val;
|
nkeynes@929 | 422 | reg &= 0xFFF;
|
nkeynes@929 | 423 | switch( reg ) {
|
nkeynes@929 | 424 | case PIRQ0:
|
nkeynes@929 | 425 | case PIRQ1:
|
nkeynes@929 | 426 | case PIRQ2:
|
nkeynes@929 | 427 | case IRQA0:
|
nkeynes@929 | 428 | case IRQA1:
|
nkeynes@929 | 429 | case IRQA2:
|
nkeynes@929 | 430 | case IRQB0:
|
nkeynes@929 | 431 | case IRQB1:
|
nkeynes@929 | 432 | case IRQB2:
|
nkeynes@929 | 433 | case IRQC0:
|
nkeynes@929 | 434 | case IRQC1:
|
nkeynes@929 | 435 | case IRQC2:
|
nkeynes@929 | 436 | case MAPLE_STATE:
|
nkeynes@929 | 437 | val = MMIO_READ(ASIC, reg);
|
nkeynes@929 | 438 | return val;
|
nkeynes@929 | 439 | case G2STATUS:
|
nkeynes@929 | 440 | return g2_read_status();
|
nkeynes@929 | 441 | default:
|
nkeynes@929 | 442 | val = MMIO_READ(ASIC, reg);
|
nkeynes@929 | 443 | return val;
|
nkeynes@929 | 444 | }
|
nkeynes@929 | 445 |
|
nkeynes@929 | 446 | }
|
nkeynes@929 | 447 |
|
nkeynes@975 | 448 | MMIO_REGION_READ_DEFSUBFNS(ASIC)
|
nkeynes@975 | 449 |
|
nkeynes@929 | 450 | MMIO_REGION_WRITE_FN( ASIC, reg, val )
|
nkeynes@929 | 451 | {
|
nkeynes@929 | 452 | reg &= 0xFFF;
|
nkeynes@1 | 453 | switch( reg ) {
|
nkeynes@125 | 454 | case PIRQ1:
|
nkeynes@736 | 455 | break; /* Treat this as read-only for the moment */
|
nkeynes@56 | 456 | case PIRQ0:
|
nkeynes@736 | 457 | val = val & 0x3FFFFFFF; /* Top two bits aren't clearable */
|
nkeynes@736 | 458 | MMIO_WRITE( ASIC, reg, MMIO_READ(ASIC, reg)&~val );
|
nkeynes@736 | 459 | asic_check_cleared_events();
|
nkeynes@736 | 460 | break;
|
nkeynes@56 | 461 | case PIRQ2:
|
nkeynes@736 | 462 | /* Clear any events */
|
nkeynes@736 | 463 | val = MMIO_READ(ASIC, reg)&(~val);
|
nkeynes@736 | 464 | MMIO_WRITE( ASIC, reg, val );
|
nkeynes@736 | 465 | if( val == 0 ) { /* all clear - clear the cascade bit */
|
nkeynes@736 | 466 | MMIO_WRITE( ASIC, PIRQ0, MMIO_READ( ASIC, PIRQ0 ) & 0x7FFFFFFF );
|
nkeynes@736 | 467 | }
|
nkeynes@736 | 468 | asic_check_cleared_events();
|
nkeynes@736 | 469 | break;
|
nkeynes@594 | 470 | case IRQA0:
|
nkeynes@594 | 471 | case IRQA1:
|
nkeynes@594 | 472 | case IRQA2:
|
nkeynes@594 | 473 | case IRQB0:
|
nkeynes@594 | 474 | case IRQB1:
|
nkeynes@594 | 475 | case IRQB2:
|
nkeynes@594 | 476 | case IRQC0:
|
nkeynes@594 | 477 | case IRQC1:
|
nkeynes@594 | 478 | case IRQC2:
|
nkeynes@736 | 479 | MMIO_WRITE( ASIC, reg, val );
|
nkeynes@736 | 480 | asic_event_mask_changed();
|
nkeynes@736 | 481 | break;
|
nkeynes@244 | 482 | case SYSRESET:
|
nkeynes@736 | 483 | if( val == 0x7611 ) {
|
nkeynes@736 | 484 | dreamcast_reset();
|
nkeynes@736 | 485 | } else {
|
nkeynes@736 | 486 | WARN( "Unknown value %08X written to SYSRESET port", val );
|
nkeynes@736 | 487 | }
|
nkeynes@736 | 488 | break;
|
nkeynes@56 | 489 | case MAPLE_STATE:
|
nkeynes@736 | 490 | MMIO_WRITE( ASIC, reg, val );
|
nkeynes@736 | 491 | if( val & 1 ) {
|
nkeynes@736 | 492 | uint32_t maple_addr = MMIO_READ( ASIC, MAPLE_DMA) &0x1FFFFFE0;
|
nkeynes@736 | 493 | maple_handle_buffer( maple_addr );
|
nkeynes@736 | 494 | MMIO_WRITE( ASIC, reg, 0 );
|
nkeynes@736 | 495 | }
|
nkeynes@736 | 496 | break;
|
nkeynes@325 | 497 | case PVRDMADEST:
|
nkeynes@736 | 498 | MMIO_WRITE( ASIC, reg, (val & 0x03FFFFE0) | 0x10000000 );
|
nkeynes@736 | 499 | break;
|
nkeynes@325 | 500 | case PVRDMACNT:
|
nkeynes@736 | 501 | MMIO_WRITE( ASIC, reg, val & 0x00FFFFE0 );
|
nkeynes@736 | 502 | break;
|
nkeynes@56 | 503 | case PVRDMACTL: /* Initiate PVR DMA transfer */
|
nkeynes@736 | 504 | val = val & 0x01;
|
nkeynes@736 | 505 | MMIO_WRITE( ASIC, reg, val );
|
nkeynes@736 | 506 | if( val == 1 ) {
|
nkeynes@736 | 507 | pvr_dma_transfer();
|
nkeynes@736 | 508 | }
|
nkeynes@736 | 509 | break;
|
nkeynes@728 | 510 | case SORTDMATBL: case SORTDMADATA:
|
nkeynes@728 | 511 | MMIO_WRITE( ASIC, reg, (val & 0x0FFFFFE0) | 0x08000000 );
|
nkeynes@728 | 512 | break;
|
nkeynes@753 | 513 | case SORTDMATSIZ: case SORTDMAASIZ:
|
nkeynes@728 | 514 | MMIO_WRITE( ASIC, reg, (val & 1) );
|
nkeynes@728 | 515 | break;
|
nkeynes@728 | 516 | case SORTDMACTL:
|
nkeynes@728 | 517 | val = val & 1;
|
nkeynes@728 | 518 | MMIO_WRITE( ASIC, reg, val );
|
nkeynes@728 | 519 | if( val == 1 ) {
|
nkeynes@728 | 520 | sort_dma_transfer();
|
nkeynes@728 | 521 | }
|
nkeynes@728 | 522 | break;
|
nkeynes@325 | 523 | case MAPLE_DMA:
|
nkeynes@736 | 524 | MMIO_WRITE( ASIC, reg, val );
|
nkeynes@736 | 525 | break;
|
nkeynes@56 | 526 | default:
|
nkeynes@736 | 527 | MMIO_WRITE( ASIC, reg, val );
|
nkeynes@1 | 528 | }
|
nkeynes@1 | 529 | }
|
nkeynes@1 | 530 |
|
nkeynes@929 | 531 | MMIO_REGION_READ_FN( EXTDMA, reg )
|
nkeynes@1 | 532 | {
|
nkeynes@929 | 533 | uint32_t val;
|
nkeynes@929 | 534 | reg &= 0xFFF;
|
nkeynes@929 | 535 | if( !idereg.interface_enabled && IS_IDE_REGISTER(reg) ) {
|
nkeynes@929 | 536 | return 0xFFFFFFFF; /* disabled */
|
nkeynes@929 | 537 | }
|
nkeynes@929 | 538 |
|
nkeynes@1 | 539 | switch( reg ) {
|
nkeynes@929 | 540 | case IDEALTSTATUS:
|
nkeynes@929 | 541 | val = idereg.status;
|
nkeynes@929 | 542 | return val;
|
nkeynes@929 | 543 | case IDEDATA: return ide_read_data_pio( );
|
nkeynes@929 | 544 | case IDEFEAT: return idereg.error;
|
nkeynes@929 | 545 | case IDECOUNT:return idereg.count;
|
nkeynes@929 | 546 | case IDELBA0: return ide_get_drive_status();
|
nkeynes@929 | 547 | case IDELBA1: return idereg.lba1;
|
nkeynes@929 | 548 | case IDELBA2: return idereg.lba2;
|
nkeynes@929 | 549 | case IDEDEV: return idereg.device;
|
nkeynes@929 | 550 | case IDECMD:
|
nkeynes@929 | 551 | val = ide_read_status();
|
nkeynes@929 | 552 | return val;
|
nkeynes@94 | 553 | default:
|
nkeynes@929 | 554 | val = MMIO_READ( EXTDMA, reg );
|
nkeynes@736 | 555 | return val;
|
nkeynes@1 | 556 | }
|
nkeynes@1 | 557 | }
|
nkeynes@975 | 558 | MMIO_REGION_READ_DEFSUBFNS(EXTDMA)
|
nkeynes@975 | 559 |
|
nkeynes@1 | 560 |
|
nkeynes@1 | 561 | MMIO_REGION_WRITE_FN( EXTDMA, reg, val )
|
nkeynes@1 | 562 | {
|
nkeynes@929 | 563 | reg &= 0xFFF;
|
nkeynes@244 | 564 | if( !idereg.interface_enabled && IS_IDE_REGISTER(reg) ) {
|
nkeynes@736 | 565 | return; /* disabled */
|
nkeynes@244 | 566 | }
|
nkeynes@244 | 567 |
|
nkeynes@2 | 568 | switch( reg ) {
|
nkeynes@125 | 569 | case IDEALTSTATUS: /* Device control */
|
nkeynes@736 | 570 | ide_write_control( val );
|
nkeynes@736 | 571 | break;
|
nkeynes@125 | 572 | case IDEDATA:
|
nkeynes@736 | 573 | ide_write_data_pio( val );
|
nkeynes@736 | 574 | break;
|
nkeynes@125 | 575 | case IDEFEAT:
|
nkeynes@736 | 576 | if( ide_can_write_regs() )
|
nkeynes@736 | 577 | idereg.feature = (uint8_t)val;
|
nkeynes@736 | 578 | break;
|
nkeynes@125 | 579 | case IDECOUNT:
|
nkeynes@736 | 580 | if( ide_can_write_regs() )
|
nkeynes@736 | 581 | idereg.count = (uint8_t)val;
|
nkeynes@736 | 582 | break;
|
nkeynes@125 | 583 | case IDELBA0:
|
nkeynes@736 | 584 | if( ide_can_write_regs() )
|
nkeynes@736 | 585 | idereg.lba0 = (uint8_t)val;
|
nkeynes@736 | 586 | break;
|
nkeynes@125 | 587 | case IDELBA1:
|
nkeynes@736 | 588 | if( ide_can_write_regs() )
|
nkeynes@736 | 589 | idereg.lba1 = (uint8_t)val;
|
nkeynes@736 | 590 | break;
|
nkeynes@125 | 591 | case IDELBA2:
|
nkeynes@736 | 592 | if( ide_can_write_regs() )
|
nkeynes@736 | 593 | idereg.lba2 = (uint8_t)val;
|
nkeynes@736 | 594 | break;
|
nkeynes@125 | 595 | case IDEDEV:
|
nkeynes@736 | 596 | if( ide_can_write_regs() )
|
nkeynes@736 | 597 | idereg.device = (uint8_t)val;
|
nkeynes@736 | 598 | break;
|
nkeynes@125 | 599 | case IDECMD:
|
nkeynes@736 | 600 | if( ide_can_write_regs() || val == IDE_CMD_NOP ) {
|
nkeynes@736 | 601 | ide_write_command( (uint8_t)val );
|
nkeynes@736 | 602 | }
|
nkeynes@736 | 603 | break;
|
nkeynes@334 | 604 | case IDEDMASH4:
|
nkeynes@736 | 605 | MMIO_WRITE( EXTDMA, reg, val & 0x1FFFFFE0 );
|
nkeynes@736 | 606 | break;
|
nkeynes@334 | 607 | case IDEDMASIZ:
|
nkeynes@736 | 608 | MMIO_WRITE( EXTDMA, reg, val & 0x01FFFFFE );
|
nkeynes@736 | 609 | break;
|
nkeynes@549 | 610 | case IDEDMADIR:
|
nkeynes@736 | 611 | MMIO_WRITE( EXTDMA, reg, val & 1 );
|
nkeynes@736 | 612 | break;
|
nkeynes@125 | 613 | case IDEDMACTL1:
|
nkeynes@125 | 614 | case IDEDMACTL2:
|
nkeynes@736 | 615 | MMIO_WRITE( EXTDMA, reg, val & 0x01 );
|
nkeynes@736 | 616 | asic_ide_dma_transfer( );
|
nkeynes@736 | 617 | break;
|
nkeynes@244 | 618 | case IDEACTIVATE:
|
nkeynes@736 | 619 | if( val == 0x001FFFFF ) {
|
nkeynes@736 | 620 | idereg.interface_enabled = TRUE;
|
nkeynes@736 | 621 | /* Conventional wisdom says that this is necessary but not
|
nkeynes@736 | 622 | * sufficient to enable the IDE interface.
|
nkeynes@736 | 623 | */
|
nkeynes@736 | 624 | } else if( val == 0x000042FE ) {
|
nkeynes@736 | 625 | idereg.interface_enabled = FALSE;
|
nkeynes@736 | 626 | }
|
nkeynes@736 | 627 | break;
|
nkeynes@549 | 628 | case G2DMA0EXT: case G2DMA0SH4: case G2DMA0SIZ:
|
nkeynes@549 | 629 | case G2DMA1EXT: case G2DMA1SH4: case G2DMA1SIZ:
|
nkeynes@549 | 630 | case G2DMA2EXT: case G2DMA2SH4: case G2DMA2SIZ:
|
nkeynes@549 | 631 | case G2DMA3EXT: case G2DMA3SH4: case G2DMA3SIZ:
|
nkeynes@736 | 632 | MMIO_WRITE( EXTDMA, reg, val & 0x9FFFFFE0 );
|
nkeynes@736 | 633 | break;
|
nkeynes@549 | 634 | case G2DMA0MOD: case G2DMA1MOD: case G2DMA2MOD: case G2DMA3MOD:
|
nkeynes@736 | 635 | MMIO_WRITE( EXTDMA, reg, val & 0x07 );
|
nkeynes@736 | 636 | break;
|
nkeynes@549 | 637 | case G2DMA0DIR: case G2DMA1DIR: case G2DMA2DIR: case G2DMA3DIR:
|
nkeynes@736 | 638 | MMIO_WRITE( EXTDMA, reg, val & 0x01 );
|
nkeynes@736 | 639 | break;
|
nkeynes@302 | 640 | case G2DMA0CTL1:
|
nkeynes@302 | 641 | case G2DMA0CTL2:
|
nkeynes@736 | 642 | MMIO_WRITE( EXTDMA, reg, val & 1);
|
nkeynes@736 | 643 | g2_dma_transfer( 0 );
|
nkeynes@736 | 644 | break;
|
nkeynes@302 | 645 | case G2DMA0STOP:
|
nkeynes@736 | 646 | MMIO_WRITE( EXTDMA, reg, val & 0x37 );
|
nkeynes@736 | 647 | break;
|
nkeynes@302 | 648 | case G2DMA1CTL1:
|
nkeynes@302 | 649 | case G2DMA1CTL2:
|
nkeynes@736 | 650 | MMIO_WRITE( EXTDMA, reg, val & 1);
|
nkeynes@736 | 651 | g2_dma_transfer( 1 );
|
nkeynes@736 | 652 | break;
|
nkeynes@279 | 653 |
|
nkeynes@302 | 654 | case G2DMA1STOP:
|
nkeynes@736 | 655 | MMIO_WRITE( EXTDMA, reg, val & 0x37 );
|
nkeynes@736 | 656 | break;
|
nkeynes@302 | 657 | case G2DMA2CTL1:
|
nkeynes@302 | 658 | case G2DMA2CTL2:
|
nkeynes@736 | 659 | MMIO_WRITE( EXTDMA, reg, val &1 );
|
nkeynes@736 | 660 | g2_dma_transfer( 2 );
|
nkeynes@736 | 661 | break;
|
nkeynes@302 | 662 | case G2DMA2STOP:
|
nkeynes@736 | 663 | MMIO_WRITE( EXTDMA, reg, val & 0x37 );
|
nkeynes@736 | 664 | break;
|
nkeynes@302 | 665 | case G2DMA3CTL1:
|
nkeynes@302 | 666 | case G2DMA3CTL2:
|
nkeynes@736 | 667 | MMIO_WRITE( EXTDMA, reg, val &1 );
|
nkeynes@736 | 668 | g2_dma_transfer( 3 );
|
nkeynes@736 | 669 | break;
|
nkeynes@302 | 670 | case G2DMA3STOP:
|
nkeynes@736 | 671 | MMIO_WRITE( EXTDMA, reg, val & 0x37 );
|
nkeynes@736 | 672 | break;
|
nkeynes@279 | 673 | case PVRDMA2CTL1:
|
nkeynes@279 | 674 | case PVRDMA2CTL2:
|
nkeynes@855 | 675 | MMIO_WRITE( EXTDMA, reg, val & 1 );
|
nkeynes@855 | 676 | pvr_dma2_transfer();
|
nkeynes@736 | 677 | break;
|
nkeynes@125 | 678 | default:
|
nkeynes@736 | 679 | MMIO_WRITE( EXTDMA, reg, val );
|
nkeynes@2 | 680 | }
|
nkeynes@1 | 681 | }
|
nkeynes@1 | 682 |
|