Search
lxdream.org :: lxdream/src/asic.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/asic.c
changeset 1237:377077d10d62
prev1100:50e702af9373
next1269:50c63f63bf8f
author nkeynes
date Sat Feb 25 09:56:10 2012 +1000 (7 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
.