Search
lxdream.org :: lxdream/src/asic.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/asic.c
changeset 1100:50e702af9373
prev1065:bc1cc0c54917
next1237:377077d10d62
author nkeynes
date Fri Sep 17 20:08:50 2010 +1000 (13 years ago)
permissions -rw-r--r--
last change Refactor shader management to support multiple programs, which are all
defined in the shaders.glsl, rather than split up into one file per
fragment.
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@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@564
    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@155
   286
}
nkeynes@155
   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@1
   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@1
   373
    }
nkeynes@1
   374
}
nkeynes@1
   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@1100
   419
gboolean asic_enable_ide_interface( gboolean enable )
nkeynes@1100
   420
{
nkeynes@1100
   421
    gboolean oldval = idereg.interface_enabled;
nkeynes@1100
   422
    idereg.interface_enabled = enable;
nkeynes@1100
   423
    return oldval;
nkeynes@1100
   424
}
nkeynes@1100
   425
nkeynes@929
   426
MMIO_REGION_READ_FN( ASIC, reg )
nkeynes@1
   427
{
nkeynes@1
   428
    int32_t val;
nkeynes@929
   429
    reg &= 0xFFF;
nkeynes@1
   430
    switch( reg ) {
nkeynes@94
   431
    case PIRQ0:
nkeynes@94
   432
    case PIRQ1:
nkeynes@94
   433
    case PIRQ2:
nkeynes@94
   434
    case IRQA0:
nkeynes@94
   435
    case IRQA1:
nkeynes@94
   436
    case IRQA2:
nkeynes@94
   437
    case IRQB0:
nkeynes@94
   438
    case IRQB1:
nkeynes@94
   439
    case IRQB2:
nkeynes@94
   440
    case IRQC0:
nkeynes@94
   441
    case IRQC1:
nkeynes@94
   442
    case IRQC2:
nkeynes@158
   443
    case MAPLE_STATE:
nkeynes@929
   444
        val = MMIO_READ(ASIC, reg);
nkeynes@929
   445
        return val;            
nkeynes@94
   446
    case G2STATUS:
nkeynes@929
   447
        return g2_read_status();
nkeynes@94
   448
    default:
nkeynes@929
   449
        val = MMIO_READ(ASIC, reg);
nkeynes@929
   450
        return val;
nkeynes@1
   451
    }
nkeynes@929
   452
nkeynes@1
   453
}
nkeynes@1
   454
nkeynes@975
   455
MMIO_REGION_READ_DEFSUBFNS(ASIC)
nkeynes@975
   456
nkeynes@929
   457
MMIO_REGION_WRITE_FN( ASIC, reg, val )
nkeynes@1
   458
{
nkeynes@929
   459
    reg &= 0xFFF;
nkeynes@2
   460
    switch( reg ) {
nkeynes@125
   461
    case PIRQ1:
nkeynes@736
   462
        break; /* Treat this as read-only for the moment */
nkeynes@56
   463
    case PIRQ0:
nkeynes@736
   464
        val = val & 0x3FFFFFFF; /* Top two bits aren't clearable */
nkeynes@736
   465
        MMIO_WRITE( ASIC, reg, MMIO_READ(ASIC, reg)&~val );
nkeynes@736
   466
        asic_check_cleared_events();
nkeynes@736
   467
        break;
nkeynes@56
   468
    case PIRQ2:
nkeynes@736
   469
        /* Clear any events */
nkeynes@736
   470
        val = MMIO_READ(ASIC, reg)&(~val);
nkeynes@736
   471
        MMIO_WRITE( ASIC, reg, val );
nkeynes@736
   472
        if( val == 0 ) { /* all clear - clear the cascade bit */
nkeynes@736
   473
            MMIO_WRITE( ASIC, PIRQ0, MMIO_READ( ASIC, PIRQ0 ) & 0x7FFFFFFF );
nkeynes@736
   474
        }
nkeynes@736
   475
        asic_check_cleared_events();
nkeynes@736
   476
        break;
nkeynes@594
   477
    case IRQA0:
nkeynes@594
   478
    case IRQA1:
nkeynes@594
   479
    case IRQA2:
nkeynes@594
   480
    case IRQB0:
nkeynes@594
   481
    case IRQB1:
nkeynes@594
   482
    case IRQB2:
nkeynes@594
   483
    case IRQC0:
nkeynes@594
   484
    case IRQC1:
nkeynes@594
   485
    case IRQC2:
nkeynes@736
   486
        MMIO_WRITE( ASIC, reg, val );
nkeynes@736
   487
        asic_event_mask_changed();
nkeynes@736
   488
        break;
nkeynes@244
   489
    case SYSRESET:
nkeynes@736
   490
        if( val == 0x7611 ) {
nkeynes@736
   491
            dreamcast_reset();
nkeynes@736
   492
        } else {
nkeynes@736
   493
            WARN( "Unknown value %08X written to SYSRESET port", val );
nkeynes@736
   494
        }
nkeynes@736
   495
        break;
nkeynes@56
   496
    case MAPLE_STATE:
nkeynes@736
   497
        MMIO_WRITE( ASIC, reg, val );
nkeynes@736
   498
        if( val & 1 ) {
nkeynes@736
   499
            uint32_t maple_addr = MMIO_READ( ASIC, MAPLE_DMA) &0x1FFFFFE0;
nkeynes@736
   500
            maple_handle_buffer( maple_addr );
nkeynes@736
   501
            MMIO_WRITE( ASIC, reg, 0 );
nkeynes@736
   502
        }
nkeynes@736
   503
        break;
nkeynes@325
   504
    case PVRDMADEST:
nkeynes@736
   505
        MMIO_WRITE( ASIC, reg, (val & 0x03FFFFE0) | 0x10000000 );
nkeynes@736
   506
        break;
nkeynes@325
   507
    case PVRDMACNT: 
nkeynes@736
   508
        MMIO_WRITE( ASIC, reg, val & 0x00FFFFE0 );
nkeynes@736
   509
        break;
nkeynes@56
   510
    case PVRDMACTL: /* Initiate PVR DMA transfer */
nkeynes@736
   511
        val = val & 0x01;
nkeynes@736
   512
        MMIO_WRITE( ASIC, reg, val );
nkeynes@736
   513
        if( val == 1 ) {
nkeynes@736
   514
            pvr_dma_transfer();
nkeynes@736
   515
        }
nkeynes@736
   516
        break;
nkeynes@728
   517
    case SORTDMATBL: case SORTDMADATA:
nkeynes@728
   518
        MMIO_WRITE( ASIC, reg, (val & 0x0FFFFFE0) | 0x08000000 );
nkeynes@728
   519
        break;
nkeynes@753
   520
    case SORTDMATSIZ: case SORTDMAASIZ:
nkeynes@728
   521
        MMIO_WRITE( ASIC, reg, (val & 1) );
nkeynes@728
   522
        break;
nkeynes@728
   523
    case SORTDMACTL:
nkeynes@728
   524
        val = val & 1;
nkeynes@728
   525
        MMIO_WRITE( ASIC, reg, val );
nkeynes@728
   526
        if( val == 1 ) {
nkeynes@728
   527
            sort_dma_transfer();
nkeynes@728
   528
        }
nkeynes@728
   529
        break;
nkeynes@325
   530
    case MAPLE_DMA:
nkeynes@736
   531
        MMIO_WRITE( ASIC, reg, val );
nkeynes@736
   532
        break;
nkeynes@125
   533
    default:
nkeynes@736
   534
        MMIO_WRITE( ASIC, reg, val );
nkeynes@2
   535
    }
nkeynes@1
   536
}
nkeynes@1
   537
nkeynes@1
   538
MMIO_REGION_READ_FN( EXTDMA, reg )
nkeynes@1
   539
{
nkeynes@56
   540
    uint32_t val;
nkeynes@929
   541
    reg &= 0xFFF;
nkeynes@244
   542
    if( !idereg.interface_enabled && IS_IDE_REGISTER(reg) ) {
nkeynes@929
   543
        return 0xFFFFFFFF; /* disabled */
nkeynes@244
   544
    }
nkeynes@244
   545
nkeynes@1
   546
    switch( reg ) {
nkeynes@158
   547
    case IDEALTSTATUS: 
nkeynes@929
   548
        val = idereg.status;
nkeynes@929
   549
        return val;
nkeynes@158
   550
    case IDEDATA: return ide_read_data_pio( );
nkeynes@158
   551
    case IDEFEAT: return idereg.error;
nkeynes@158
   552
    case IDECOUNT:return idereg.count;
nkeynes@342
   553
    case IDELBA0: return ide_get_drive_status();
nkeynes@158
   554
    case IDELBA1: return idereg.lba1;
nkeynes@158
   555
    case IDELBA2: return idereg.lba2;
nkeynes@158
   556
    case IDEDEV: return idereg.device;
nkeynes@158
   557
    case IDECMD:
nkeynes@929
   558
        val = ide_read_status();
nkeynes@929
   559
        return val;
nkeynes@158
   560
    default:
nkeynes@929
   561
        val = MMIO_READ( EXTDMA, reg );
nkeynes@736
   562
        return val;
nkeynes@1
   563
    }
nkeynes@1
   564
}
nkeynes@975
   565
MMIO_REGION_READ_DEFSUBFNS(EXTDMA)
nkeynes@975
   566
nkeynes@1
   567
nkeynes@1
   568
MMIO_REGION_WRITE_FN( EXTDMA, reg, val )
nkeynes@1
   569
{
nkeynes@929
   570
    reg &= 0xFFF;
nkeynes@244
   571
    if( !idereg.interface_enabled && IS_IDE_REGISTER(reg) ) {
nkeynes@736
   572
        return; /* disabled */
nkeynes@244
   573
    }
nkeynes@244
   574
nkeynes@2
   575
    switch( reg ) {
nkeynes@125
   576
    case IDEALTSTATUS: /* Device control */
nkeynes@736
   577
        ide_write_control( val );
nkeynes@736
   578
        break;
nkeynes@125
   579
    case IDEDATA:
nkeynes@736
   580
        ide_write_data_pio( val );
nkeynes@736
   581
        break;
nkeynes@125
   582
    case IDEFEAT:
nkeynes@736
   583
        if( ide_can_write_regs() )
nkeynes@736
   584
            idereg.feature = (uint8_t)val;
nkeynes@736
   585
        break;
nkeynes@125
   586
    case IDECOUNT:
nkeynes@736
   587
        if( ide_can_write_regs() )
nkeynes@736
   588
            idereg.count = (uint8_t)val;
nkeynes@736
   589
        break;
nkeynes@125
   590
    case IDELBA0:
nkeynes@736
   591
        if( ide_can_write_regs() )
nkeynes@736
   592
            idereg.lba0 = (uint8_t)val;
nkeynes@736
   593
        break;
nkeynes@125
   594
    case IDELBA1:
nkeynes@736
   595
        if( ide_can_write_regs() )
nkeynes@736
   596
            idereg.lba1 = (uint8_t)val;
nkeynes@736
   597
        break;
nkeynes@125
   598
    case IDELBA2:
nkeynes@736
   599
        if( ide_can_write_regs() )
nkeynes@736
   600
            idereg.lba2 = (uint8_t)val;
nkeynes@736
   601
        break;
nkeynes@125
   602
    case IDEDEV:
nkeynes@736
   603
        if( ide_can_write_regs() )
nkeynes@736
   604
            idereg.device = (uint8_t)val;
nkeynes@736
   605
        break;
nkeynes@125
   606
    case IDECMD:
nkeynes@736
   607
        if( ide_can_write_regs() || val == IDE_CMD_NOP ) {
nkeynes@736
   608
            ide_write_command( (uint8_t)val );
nkeynes@736
   609
        }
nkeynes@736
   610
        break;
nkeynes@334
   611
    case IDEDMASH4:
nkeynes@736
   612
        MMIO_WRITE( EXTDMA, reg, val & 0x1FFFFFE0 );
nkeynes@736
   613
        break;
nkeynes@334
   614
    case IDEDMASIZ:
nkeynes@736
   615
        MMIO_WRITE( EXTDMA, reg, val & 0x01FFFFFE );
nkeynes@736
   616
        break;
nkeynes@549
   617
    case IDEDMADIR:
nkeynes@736
   618
        MMIO_WRITE( EXTDMA, reg, val & 1 );
nkeynes@736
   619
        break;
nkeynes@125
   620
    case IDEDMACTL1:
nkeynes@125
   621
    case IDEDMACTL2:
nkeynes@736
   622
        MMIO_WRITE( EXTDMA, reg, val & 0x01 );
nkeynes@736
   623
        asic_ide_dma_transfer( );
nkeynes@736
   624
        break;
nkeynes@244
   625
    case IDEACTIVATE:
nkeynes@736
   626
        if( val == 0x001FFFFF ) {
nkeynes@736
   627
            idereg.interface_enabled = TRUE;
nkeynes@736
   628
            /* Conventional wisdom says that this is necessary but not
nkeynes@736
   629
             * sufficient to enable the IDE interface.
nkeynes@736
   630
             */
nkeynes@736
   631
        } else if( val == 0x000042FE ) {
nkeynes@736
   632
            idereg.interface_enabled = FALSE;
nkeynes@736
   633
        }
nkeynes@736
   634
        break;
nkeynes@549
   635
    case G2DMA0EXT: case G2DMA0SH4: case G2DMA0SIZ:
nkeynes@549
   636
    case G2DMA1EXT: case G2DMA1SH4: case G2DMA1SIZ:
nkeynes@549
   637
    case G2DMA2EXT: case G2DMA2SH4: case G2DMA2SIZ:
nkeynes@549
   638
    case G2DMA3EXT: case G2DMA3SH4: case G2DMA3SIZ:
nkeynes@736
   639
        MMIO_WRITE( EXTDMA, reg, val & 0x9FFFFFE0 );
nkeynes@736
   640
        break;
nkeynes@549
   641
    case G2DMA0MOD: case G2DMA1MOD: case G2DMA2MOD: case G2DMA3MOD:
nkeynes@736
   642
        MMIO_WRITE( EXTDMA, reg, val & 0x07 );
nkeynes@736
   643
        break;
nkeynes@549
   644
    case G2DMA0DIR: case G2DMA1DIR: case G2DMA2DIR: case G2DMA3DIR:
nkeynes@736
   645
        MMIO_WRITE( EXTDMA, reg, val & 0x01 );
nkeynes@736
   646
        break;
nkeynes@302
   647
    case G2DMA0CTL1:
nkeynes@302
   648
    case G2DMA0CTL2:
nkeynes@736
   649
        MMIO_WRITE( EXTDMA, reg, val & 1);
nkeynes@736
   650
        g2_dma_transfer( 0 );
nkeynes@736
   651
        break;
nkeynes@302
   652
    case G2DMA0STOP:
nkeynes@736
   653
        MMIO_WRITE( EXTDMA, reg, val & 0x37 );
nkeynes@736
   654
        break;
nkeynes@302
   655
    case G2DMA1CTL1:
nkeynes@302
   656
    case G2DMA1CTL2:
nkeynes@736
   657
        MMIO_WRITE( EXTDMA, reg, val & 1);
nkeynes@736
   658
        g2_dma_transfer( 1 );
nkeynes@736
   659
        break;
nkeynes@279
   660
nkeynes@302
   661
    case G2DMA1STOP:
nkeynes@736
   662
        MMIO_WRITE( EXTDMA, reg, val & 0x37 );
nkeynes@736
   663
        break;
nkeynes@302
   664
    case G2DMA2CTL1:
nkeynes@302
   665
    case G2DMA2CTL2:
nkeynes@736
   666
        MMIO_WRITE( EXTDMA, reg, val &1 );
nkeynes@736
   667
        g2_dma_transfer( 2 );
nkeynes@736
   668
        break;
nkeynes@302
   669
    case G2DMA2STOP:
nkeynes@736
   670
        MMIO_WRITE( EXTDMA, reg, val & 0x37 );
nkeynes@736
   671
        break;
nkeynes@302
   672
    case G2DMA3CTL1:
nkeynes@302
   673
    case G2DMA3CTL2:
nkeynes@736
   674
        MMIO_WRITE( EXTDMA, reg, val &1 );
nkeynes@736
   675
        g2_dma_transfer( 3 );
nkeynes@736
   676
        break;
nkeynes@302
   677
    case G2DMA3STOP:
nkeynes@736
   678
        MMIO_WRITE( EXTDMA, reg, val & 0x37 );
nkeynes@736
   679
        break;
nkeynes@279
   680
    case PVRDMA2CTL1:
nkeynes@279
   681
    case PVRDMA2CTL2:
nkeynes@855
   682
        MMIO_WRITE( EXTDMA, reg, val & 1 );
nkeynes@855
   683
        pvr_dma2_transfer();
nkeynes@736
   684
        break;
nkeynes@125
   685
    default:
nkeynes@736
   686
        MMIO_WRITE( EXTDMA, reg, val );
nkeynes@1
   687
    }
nkeynes@1
   688
}
nkeynes@1
   689
.