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