nkeynes@31: /** nkeynes@586: * $Id$ nkeynes@31: * nkeynes@31: * Support for the miscellaneous ASIC functions (Primarily event multiplexing, nkeynes@31: * and DMA). nkeynes@31: * nkeynes@31: * Copyright (c) 2005 Nathan Keynes. nkeynes@31: * nkeynes@31: * This program is free software; you can redistribute it and/or modify nkeynes@31: * it under the terms of the GNU General Public License as published by nkeynes@31: * the Free Software Foundation; either version 2 of the License, or nkeynes@31: * (at your option) any later version. nkeynes@31: * nkeynes@31: * This program is distributed in the hope that it will be useful, nkeynes@31: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@31: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@31: * GNU General Public License for more details. nkeynes@31: */ nkeynes@35: nkeynes@35: #define MODULE asic_module nkeynes@35: nkeynes@1: #include nkeynes@137: #include nkeynes@1: #include "dream.h" nkeynes@1: #include "mem.h" nkeynes@1: #include "sh4/intc.h" nkeynes@56: #include "sh4/dmac.h" nkeynes@586: #include "sh4/sh4.h" nkeynes@2: #include "dreamcast.h" nkeynes@25: #include "maple/maple.h" nkeynes@25: #include "gdrom/ide.h" nkeynes@422: #include "pvr2/pvr2.h" nkeynes@15: #include "asic.h" nkeynes@1: #define MMIO_IMPL nkeynes@1: #include "asic.h" nkeynes@1: /* nkeynes@1: * Open questions: nkeynes@1: * 1) Does changing the mask after event occurance result in the nkeynes@1: * interrupt being delivered immediately? nkeynes@1: * TODO: Logic diagram of ASIC event/interrupt logic. nkeynes@1: * nkeynes@1: * ... don't even get me started on the "EXTDMA" page, about which, apparently, nkeynes@1: * practically nothing is publicly known... nkeynes@1: */ nkeynes@1: nkeynes@155: static void asic_check_cleared_events( void ); nkeynes@155: static void asic_init( void ); nkeynes@155: static void asic_reset( void ); nkeynes@302: static uint32_t asic_run_slice( uint32_t nanosecs ); nkeynes@155: static void asic_save_state( FILE *f ); nkeynes@155: static int asic_load_state( FILE *f ); nkeynes@302: static uint32_t g2_update_fifo_status( uint32_t slice_cycle ); nkeynes@155: nkeynes@302: struct dreamcast_module asic_module = { "ASIC", asic_init, asic_reset, NULL, asic_run_slice, nkeynes@155: NULL, asic_save_state, asic_load_state }; nkeynes@15: nkeynes@302: #define G2_BIT5_TICKS 60 nkeynes@302: #define G2_BIT4_TICKS 160 nkeynes@302: #define G2_BIT0_ON_TICKS 120 nkeynes@302: #define G2_BIT0_OFF_TICKS 420 nkeynes@137: nkeynes@137: struct asic_g2_state { nkeynes@302: int bit5_off_timer; nkeynes@302: int bit4_on_timer; nkeynes@302: int bit4_off_timer; nkeynes@302: int bit0_on_timer; nkeynes@302: int bit0_off_timer; nkeynes@155: }; nkeynes@155: nkeynes@155: static struct asic_g2_state g2_state; nkeynes@155: nkeynes@302: static uint32_t asic_run_slice( uint32_t nanosecs ) nkeynes@302: { nkeynes@302: g2_update_fifo_status(nanosecs); nkeynes@302: if( g2_state.bit5_off_timer <= (int32_t)nanosecs ) { nkeynes@302: g2_state.bit5_off_timer = -1; nkeynes@302: } else { nkeynes@302: g2_state.bit5_off_timer -= nanosecs; nkeynes@302: } nkeynes@302: nkeynes@302: if( g2_state.bit4_off_timer <= (int32_t)nanosecs ) { nkeynes@302: g2_state.bit4_off_timer = -1; nkeynes@302: } else { nkeynes@302: g2_state.bit4_off_timer -= nanosecs; nkeynes@302: } nkeynes@302: if( g2_state.bit4_on_timer <= (int32_t)nanosecs ) { nkeynes@302: g2_state.bit4_on_timer = -1; nkeynes@302: } else { nkeynes@302: g2_state.bit4_on_timer -= nanosecs; nkeynes@302: } nkeynes@302: nkeynes@302: if( g2_state.bit0_off_timer <= (int32_t)nanosecs ) { nkeynes@302: g2_state.bit0_off_timer = -1; nkeynes@302: } else { nkeynes@302: g2_state.bit0_off_timer -= nanosecs; nkeynes@302: } nkeynes@302: if( g2_state.bit0_on_timer <= (int32_t)nanosecs ) { nkeynes@302: g2_state.bit0_on_timer = -1; nkeynes@302: } else { nkeynes@302: g2_state.bit0_on_timer -= nanosecs; nkeynes@302: } nkeynes@302: nkeynes@302: return nanosecs; nkeynes@302: } nkeynes@302: nkeynes@155: static void asic_init( void ) nkeynes@155: { nkeynes@155: register_io_region( &mmio_region_ASIC ); nkeynes@155: register_io_region( &mmio_region_EXTDMA ); nkeynes@155: asic_reset(); nkeynes@155: } nkeynes@155: nkeynes@155: static void asic_reset( void ) nkeynes@155: { nkeynes@302: memset( &g2_state, 0xFF, sizeof(g2_state) ); nkeynes@155: } nkeynes@155: nkeynes@155: static void asic_save_state( FILE *f ) nkeynes@155: { nkeynes@155: fwrite( &g2_state, sizeof(g2_state), 1, f ); nkeynes@155: } nkeynes@155: nkeynes@155: static int asic_load_state( FILE *f ) nkeynes@155: { nkeynes@155: if( fread( &g2_state, sizeof(g2_state), 1, f ) != 1 ) nkeynes@155: return 1; nkeynes@155: else nkeynes@155: return 0; nkeynes@155: } nkeynes@155: nkeynes@137: nkeynes@302: /** nkeynes@302: * Setup the timers for the 3 FIFO status bits following a write through the G2 nkeynes@302: * bus from the SH4 side. The timing is roughly as follows: (times are nkeynes@302: * approximate based on software readings - I wouldn't take this as gospel but nkeynes@302: * it seems to be enough to fool most programs). nkeynes@302: * 0ns: Bit 5 (Input fifo?) goes high immediately on the write nkeynes@302: * 40ns: Bit 5 goes low and bit 4 goes high nkeynes@302: * 120ns: Bit 4 goes low, bit 0 goes high nkeynes@302: * 240ns: Bit 0 goes low. nkeynes@302: * nkeynes@302: * Additional writes while the FIFO is in operation extend the time that the nkeynes@302: * bits remain high as one might expect, without altering the time at which nkeynes@302: * they initially go high. nkeynes@302: */ nkeynes@137: void asic_g2_write_word() nkeynes@137: { nkeynes@302: if( g2_state.bit5_off_timer < (int32_t)sh4r.slice_cycle ) { nkeynes@302: g2_state.bit5_off_timer = sh4r.slice_cycle + G2_BIT5_TICKS; nkeynes@302: } else { nkeynes@302: g2_state.bit5_off_timer += G2_BIT5_TICKS; nkeynes@302: } nkeynes@302: nkeynes@302: if( g2_state.bit4_on_timer < (int32_t)sh4r.slice_cycle ) { nkeynes@302: g2_state.bit4_on_timer = sh4r.slice_cycle + G2_BIT5_TICKS; nkeynes@302: } nkeynes@302: nkeynes@302: if( g2_state.bit4_off_timer < (int32_t)sh4r.slice_cycle ) { nkeynes@302: g2_state.bit4_off_timer = g2_state.bit4_on_timer + G2_BIT4_TICKS; nkeynes@302: } else { nkeynes@302: g2_state.bit4_off_timer += G2_BIT4_TICKS; nkeynes@302: } nkeynes@302: nkeynes@302: if( g2_state.bit0_on_timer < (int32_t)sh4r.slice_cycle ) { nkeynes@302: g2_state.bit0_on_timer = sh4r.slice_cycle + G2_BIT0_ON_TICKS; nkeynes@302: } nkeynes@302: nkeynes@302: if( g2_state.bit0_off_timer < (int32_t)sh4r.slice_cycle ) { nkeynes@137: g2_state.bit0_off_timer = g2_state.bit0_on_timer + G2_BIT0_OFF_TICKS; nkeynes@137: } else { nkeynes@137: g2_state.bit0_off_timer += G2_BIT0_OFF_TICKS; nkeynes@137: } nkeynes@302: nkeynes@137: MMIO_WRITE( ASIC, G2STATUS, MMIO_READ(ASIC, G2STATUS) | 0x20 ); nkeynes@137: } nkeynes@137: nkeynes@302: static uint32_t g2_update_fifo_status( uint32_t nanos ) nkeynes@137: { nkeynes@302: uint32_t val = MMIO_READ( ASIC, G2STATUS ); nkeynes@302: if( ((uint32_t)g2_state.bit5_off_timer) <= nanos ) { nkeynes@302: val = val & (~0x20); nkeynes@302: g2_state.bit5_off_timer = -1; nkeynes@163: } nkeynes@302: if( ((uint32_t)g2_state.bit4_on_timer) <= nanos ) { nkeynes@302: val = val | 0x10; nkeynes@302: g2_state.bit4_on_timer = -1; nkeynes@302: } nkeynes@302: if( ((uint32_t)g2_state.bit4_off_timer) <= nanos ) { nkeynes@137: val = val & (~0x10); nkeynes@302: g2_state.bit4_off_timer = -1; nkeynes@302: } nkeynes@302: nkeynes@302: if( ((uint32_t)g2_state.bit0_on_timer) <= nanos ) { nkeynes@302: val = val | 0x01; nkeynes@302: g2_state.bit0_on_timer = -1; nkeynes@302: } nkeynes@302: if( ((uint32_t)g2_state.bit0_off_timer) <= nanos ) { nkeynes@137: val = val & (~0x01); nkeynes@302: g2_state.bit0_off_timer = -1; nkeynes@302: } nkeynes@302: nkeynes@302: MMIO_WRITE( ASIC, G2STATUS, val ); nkeynes@302: return val; nkeynes@137: } nkeynes@137: nkeynes@302: static int g2_read_status() { nkeynes@302: return g2_update_fifo_status( sh4r.slice_cycle ); nkeynes@302: } nkeynes@302: nkeynes@20: nkeynes@155: void asic_event( int event ) nkeynes@1: { nkeynes@155: int offset = ((event&0x60)>>3); nkeynes@155: int result = (MMIO_READ(ASIC, PIRQ0 + offset)) |= (1<<(event&0x1F)); nkeynes@155: nkeynes@155: if( result & MMIO_READ(ASIC, IRQA0 + offset) ) nkeynes@155: intc_raise_interrupt( INT_IRQ13 ); nkeynes@155: if( result & MMIO_READ(ASIC, IRQB0 + offset) ) nkeynes@155: intc_raise_interrupt( INT_IRQ11 ); nkeynes@155: if( result & MMIO_READ(ASIC, IRQC0 + offset) ) nkeynes@155: intc_raise_interrupt( INT_IRQ9 ); nkeynes@305: nkeynes@305: if( event >= 64 ) { /* Third word */ nkeynes@305: asic_event( EVENT_CASCADE2 ); nkeynes@305: } else if( event >= 32 ) { /* Second word */ nkeynes@305: asic_event( EVENT_CASCADE1 ); nkeynes@305: } nkeynes@1: } nkeynes@1: nkeynes@155: void asic_clear_event( int event ) { nkeynes@155: int offset = ((event&0x60)>>3); nkeynes@155: uint32_t result = MMIO_READ(ASIC, PIRQ0 + offset) & (~(1<<(event&0x1F))); nkeynes@155: MMIO_WRITE( ASIC, PIRQ0 + offset, result ); nkeynes@305: if( result == 0 ) { nkeynes@305: /* clear cascades if necessary */ nkeynes@305: if( event >= 64 ) { nkeynes@305: MMIO_WRITE( ASIC, PIRQ0, MMIO_READ( ASIC, PIRQ0 ) & 0x7FFFFFFF ); nkeynes@305: } else if( event >= 32 ) { nkeynes@305: MMIO_WRITE( ASIC, PIRQ0, MMIO_READ( ASIC, PIRQ0 ) & 0xBFFFFFFF ); nkeynes@305: } nkeynes@305: } nkeynes@305: nkeynes@155: asic_check_cleared_events(); nkeynes@155: } nkeynes@155: nkeynes@155: void asic_check_cleared_events( ) nkeynes@155: { nkeynes@155: int i, setA = 0, setB = 0, setC = 0; nkeynes@155: uint32_t bits; nkeynes@594: for( i=0; i<12; i+=4 ) { nkeynes@155: bits = MMIO_READ( ASIC, PIRQ0 + i ); nkeynes@155: setA |= (bits & MMIO_READ(ASIC, IRQA0 + i )); nkeynes@155: setB |= (bits & MMIO_READ(ASIC, IRQB0 + i )); nkeynes@155: setC |= (bits & MMIO_READ(ASIC, IRQC0 + i )); nkeynes@155: } nkeynes@155: if( setA == 0 ) nkeynes@155: intc_clear_interrupt( INT_IRQ13 ); nkeynes@155: if( setB == 0 ) nkeynes@155: intc_clear_interrupt( INT_IRQ11 ); nkeynes@155: if( setC == 0 ) nkeynes@155: intc_clear_interrupt( INT_IRQ9 ); nkeynes@155: } nkeynes@155: nkeynes@594: void asic_event_mask_changed( ) nkeynes@594: { nkeynes@594: int i, setA = 0, setB = 0, setC = 0; nkeynes@594: uint32_t bits; nkeynes@594: for( i=0; i<12; i+=4 ) { nkeynes@594: bits = MMIO_READ( ASIC, PIRQ0 + i ); nkeynes@594: setA |= (bits & MMIO_READ(ASIC, IRQA0 + i )); nkeynes@594: setB |= (bits & MMIO_READ(ASIC, IRQB0 + i )); nkeynes@594: setC |= (bits & MMIO_READ(ASIC, IRQC0 + i )); nkeynes@594: } nkeynes@594: if( setA == 0 ) nkeynes@594: intc_clear_interrupt( INT_IRQ13 ); nkeynes@594: else nkeynes@594: intc_raise_interrupt( INT_IRQ13 ); nkeynes@594: if( setB == 0 ) nkeynes@594: intc_clear_interrupt( INT_IRQ11 ); nkeynes@594: else nkeynes@594: intc_raise_interrupt( INT_IRQ11 ); nkeynes@594: if( setC == 0 ) nkeynes@594: intc_clear_interrupt( INT_IRQ9 ); nkeynes@594: else nkeynes@594: intc_raise_interrupt( INT_IRQ9 ); nkeynes@594: } nkeynes@594: nkeynes@279: void g2_dma_transfer( int channel ) nkeynes@279: { nkeynes@279: uint32_t offset = channel << 5; nkeynes@279: nkeynes@302: if( MMIO_READ( EXTDMA, G2DMA0CTL1 + offset ) == 1 ) { nkeynes@302: if( MMIO_READ( EXTDMA, G2DMA0CTL2 + offset ) == 1 ) { nkeynes@302: uint32_t extaddr = MMIO_READ( EXTDMA, G2DMA0EXT + offset ); nkeynes@302: uint32_t sh4addr = MMIO_READ( EXTDMA, G2DMA0SH4 + offset ); nkeynes@302: uint32_t length = MMIO_READ( EXTDMA, G2DMA0SIZ + offset ) & 0x1FFFFFFF; nkeynes@302: uint32_t dir = MMIO_READ( EXTDMA, G2DMA0DIR + offset ); nkeynes@422: // uint32_t mode = MMIO_READ( EXTDMA, G2DMA0MOD + offset ); nkeynes@430: unsigned char buf[length]; nkeynes@279: if( dir == 0 ) { /* SH4 to device */ nkeynes@279: mem_copy_from_sh4( buf, sh4addr, length ); nkeynes@279: mem_copy_to_sh4( extaddr, buf, length ); nkeynes@279: } else { /* Device to SH4 */ nkeynes@279: mem_copy_from_sh4( buf, extaddr, length ); nkeynes@279: mem_copy_to_sh4( sh4addr, buf, length ); nkeynes@279: } nkeynes@302: MMIO_WRITE( EXTDMA, G2DMA0CTL2 + offset, 0 ); nkeynes@302: asic_event( EVENT_G2_DMA0 + channel ); nkeynes@279: } else { nkeynes@302: MMIO_WRITE( EXTDMA, G2DMA0CTL2 + offset, 0 ); nkeynes@279: } nkeynes@279: } nkeynes@279: } nkeynes@155: nkeynes@155: void asic_ide_dma_transfer( ) nkeynes@155: { nkeynes@158: if( MMIO_READ( EXTDMA, IDEDMACTL2 ) == 1 ) { nkeynes@158: if( MMIO_READ( EXTDMA, IDEDMACTL1 ) == 1 ) { nkeynes@158: MMIO_WRITE( EXTDMA, IDEDMATXSIZ, 0 ); nkeynes@158: nkeynes@158: uint32_t addr = MMIO_READ( EXTDMA, IDEDMASH4 ); nkeynes@158: uint32_t length = MMIO_READ( EXTDMA, IDEDMASIZ ); nkeynes@422: // int dir = MMIO_READ( EXTDMA, IDEDMADIR ); nkeynes@158: nkeynes@158: uint32_t xfer = ide_read_data_dma( addr, length ); nkeynes@158: MMIO_WRITE( EXTDMA, IDEDMATXSIZ, xfer ); nkeynes@158: MMIO_WRITE( EXTDMA, IDEDMACTL2, 0 ); nkeynes@158: } else { /* 0 */ nkeynes@158: MMIO_WRITE( EXTDMA, IDEDMACTL2, 0 ); nkeynes@155: } nkeynes@155: } nkeynes@155: } nkeynes@155: nkeynes@325: void pvr_dma_transfer( ) nkeynes@325: { nkeynes@325: sh4addr_t destaddr = MMIO_READ( ASIC, PVRDMADEST) &0x1FFFFFE0; nkeynes@325: uint32_t count = MMIO_READ( ASIC, PVRDMACNT ); nkeynes@430: unsigned char *data = alloca( count ); nkeynes@325: uint32_t rcount = DMAC_get_buffer( 2, data, count ); nkeynes@325: if( rcount != count ) nkeynes@325: WARN( "PVR received %08X bytes from DMA, expected %08X", rcount, count ); nkeynes@325: nkeynes@325: pvr2_dma_write( destaddr, data, rcount ); nkeynes@325: nkeynes@325: MMIO_WRITE( ASIC, PVRDMACTL, 0 ); nkeynes@325: MMIO_WRITE( ASIC, PVRDMACNT, 0 ); nkeynes@325: if( destaddr & 0x01000000 ) { /* Write to texture RAM */ nkeynes@325: MMIO_WRITE( ASIC, PVRDMADEST, destaddr + rcount ); nkeynes@325: } nkeynes@325: asic_event( EVENT_PVR_DMA ); nkeynes@325: } nkeynes@155: nkeynes@1: void mmio_region_ASIC_write( uint32_t reg, uint32_t val ) nkeynes@1: { nkeynes@1: switch( reg ) { nkeynes@125: case PIRQ1: nkeynes@305: break; /* Treat this as read-only for the moment */ nkeynes@56: case PIRQ0: nkeynes@305: val = val & 0x3FFFFFFF; /* Top two bits aren't clearable */ nkeynes@305: MMIO_WRITE( ASIC, reg, MMIO_READ(ASIC, reg)&~val ); nkeynes@305: asic_check_cleared_events(); nkeynes@305: break; nkeynes@56: case PIRQ2: nkeynes@305: /* Clear any events */ nkeynes@305: val = MMIO_READ(ASIC, reg)&(~val); nkeynes@305: MMIO_WRITE( ASIC, reg, val ); nkeynes@305: if( val == 0 ) { /* all clear - clear the cascade bit */ nkeynes@305: MMIO_WRITE( ASIC, PIRQ0, MMIO_READ( ASIC, PIRQ0 ) & 0x7FFFFFFF ); nkeynes@305: } nkeynes@56: asic_check_cleared_events(); nkeynes@56: break; nkeynes@594: case IRQA0: nkeynes@594: case IRQA1: nkeynes@594: case IRQA2: nkeynes@594: case IRQB0: nkeynes@594: case IRQB1: nkeynes@594: case IRQB2: nkeynes@594: case IRQC0: nkeynes@594: case IRQC1: nkeynes@594: case IRQC2: nkeynes@594: MMIO_WRITE( ASIC, reg, val ); nkeynes@594: asic_event_mask_changed(); nkeynes@594: break; nkeynes@244: case SYSRESET: nkeynes@244: if( val == 0x7611 ) { nkeynes@244: dreamcast_reset(); nkeynes@244: } else { nkeynes@244: WARN( "Unknown value %08X written to SYSRESET port", val ); nkeynes@244: } nkeynes@244: break; nkeynes@56: case MAPLE_STATE: nkeynes@56: MMIO_WRITE( ASIC, reg, val ); nkeynes@56: if( val & 1 ) { nkeynes@56: uint32_t maple_addr = MMIO_READ( ASIC, MAPLE_DMA) &0x1FFFFFE0; nkeynes@56: maple_handle_buffer( maple_addr ); nkeynes@56: MMIO_WRITE( ASIC, reg, 0 ); nkeynes@56: } nkeynes@56: break; nkeynes@325: case PVRDMADEST: nkeynes@325: MMIO_WRITE( ASIC, reg, (val & 0x03FFFFE0) | 0x10000000 ); nkeynes@325: break; nkeynes@325: case PVRDMACNT: nkeynes@325: MMIO_WRITE( ASIC, reg, val & 0x00FFFFE0 ); nkeynes@325: break; nkeynes@56: case PVRDMACTL: /* Initiate PVR DMA transfer */ nkeynes@325: val = val & 0x01; nkeynes@94: MMIO_WRITE( ASIC, reg, val ); nkeynes@325: if( val == 1 ) { nkeynes@325: pvr_dma_transfer(); nkeynes@56: } nkeynes@56: break; nkeynes@549: nkeynes@325: case MAPLE_DMA: nkeynes@158: MMIO_WRITE( ASIC, reg, val ); nkeynes@158: break; nkeynes@56: default: nkeynes@56: MMIO_WRITE( ASIC, reg, val ); nkeynes@1: } nkeynes@1: } nkeynes@1: nkeynes@1: int32_t mmio_region_ASIC_read( uint32_t reg ) nkeynes@1: { nkeynes@1: int32_t val; nkeynes@1: switch( reg ) { nkeynes@94: case PIRQ0: nkeynes@94: case PIRQ1: nkeynes@94: case PIRQ2: nkeynes@94: case IRQA0: nkeynes@94: case IRQA1: nkeynes@94: case IRQA2: nkeynes@94: case IRQB0: nkeynes@94: case IRQB1: nkeynes@94: case IRQB2: nkeynes@94: case IRQC0: nkeynes@94: case IRQC1: nkeynes@94: case IRQC2: nkeynes@158: case MAPLE_STATE: nkeynes@94: val = MMIO_READ(ASIC, reg); nkeynes@94: return val; nkeynes@94: case G2STATUS: nkeynes@137: return g2_read_status(); nkeynes@94: default: nkeynes@94: val = MMIO_READ(ASIC, reg); nkeynes@94: return val; nkeynes@1: } nkeynes@94: nkeynes@1: } nkeynes@1: nkeynes@1: MMIO_REGION_WRITE_FN( EXTDMA, reg, val ) nkeynes@1: { nkeynes@244: if( !idereg.interface_enabled && IS_IDE_REGISTER(reg) ) { nkeynes@244: return; /* disabled */ nkeynes@244: } nkeynes@244: nkeynes@2: switch( reg ) { nkeynes@125: case IDEALTSTATUS: /* Device control */ nkeynes@125: ide_write_control( val ); nkeynes@125: break; nkeynes@125: case IDEDATA: nkeynes@125: ide_write_data_pio( val ); nkeynes@125: break; nkeynes@125: case IDEFEAT: nkeynes@125: if( ide_can_write_regs() ) nkeynes@125: idereg.feature = (uint8_t)val; nkeynes@125: break; nkeynes@125: case IDECOUNT: nkeynes@125: if( ide_can_write_regs() ) nkeynes@125: idereg.count = (uint8_t)val; nkeynes@125: break; nkeynes@125: case IDELBA0: nkeynes@125: if( ide_can_write_regs() ) nkeynes@125: idereg.lba0 = (uint8_t)val; nkeynes@125: break; nkeynes@125: case IDELBA1: nkeynes@125: if( ide_can_write_regs() ) nkeynes@125: idereg.lba1 = (uint8_t)val; nkeynes@125: break; nkeynes@125: case IDELBA2: nkeynes@125: if( ide_can_write_regs() ) nkeynes@125: idereg.lba2 = (uint8_t)val; nkeynes@125: break; nkeynes@125: case IDEDEV: nkeynes@125: if( ide_can_write_regs() ) nkeynes@125: idereg.device = (uint8_t)val; nkeynes@125: break; nkeynes@125: case IDECMD: nkeynes@240: if( ide_can_write_regs() || val == IDE_CMD_NOP ) { nkeynes@125: ide_write_command( (uint8_t)val ); nkeynes@125: } nkeynes@125: break; nkeynes@334: case IDEDMASH4: nkeynes@334: MMIO_WRITE( EXTDMA, reg, val & 0x1FFFFFE0 ); nkeynes@334: break; nkeynes@334: case IDEDMASIZ: nkeynes@334: MMIO_WRITE( EXTDMA, reg, val & 0x01FFFFFE ); nkeynes@334: break; nkeynes@549: case IDEDMADIR: nkeynes@549: MMIO_WRITE( EXTDMA, reg, val & 1 ); nkeynes@549: break; nkeynes@125: case IDEDMACTL1: nkeynes@125: case IDEDMACTL2: nkeynes@334: MMIO_WRITE( EXTDMA, reg, val & 0x01 ); nkeynes@155: asic_ide_dma_transfer( ); nkeynes@125: break; nkeynes@244: case IDEACTIVATE: nkeynes@244: if( val == 0x001FFFFF ) { nkeynes@244: idereg.interface_enabled = TRUE; nkeynes@244: /* Conventional wisdom says that this is necessary but not nkeynes@244: * sufficient to enable the IDE interface. nkeynes@244: */ nkeynes@244: } else if( val == 0x000042FE ) { nkeynes@244: idereg.interface_enabled = FALSE; nkeynes@244: } nkeynes@279: break; nkeynes@549: case G2DMA0EXT: case G2DMA0SH4: case G2DMA0SIZ: nkeynes@549: case G2DMA1EXT: case G2DMA1SH4: case G2DMA1SIZ: nkeynes@549: case G2DMA2EXT: case G2DMA2SH4: case G2DMA2SIZ: nkeynes@549: case G2DMA3EXT: case G2DMA3SH4: case G2DMA3SIZ: nkeynes@549: MMIO_WRITE( EXTDMA, reg, val & 0x9FFFFFE0 ); nkeynes@549: break; nkeynes@549: case G2DMA0MOD: case G2DMA1MOD: case G2DMA2MOD: case G2DMA3MOD: nkeynes@549: MMIO_WRITE( EXTDMA, reg, val & 0x07 ); nkeynes@549: break; nkeynes@549: case G2DMA0DIR: case G2DMA1DIR: case G2DMA2DIR: case G2DMA3DIR: nkeynes@549: MMIO_WRITE( EXTDMA, reg, val & 0x01 ); nkeynes@549: break; nkeynes@302: case G2DMA0CTL1: nkeynes@302: case G2DMA0CTL2: nkeynes@549: MMIO_WRITE( EXTDMA, reg, val & 1); nkeynes@279: g2_dma_transfer( 0 ); nkeynes@279: break; nkeynes@302: case G2DMA0STOP: nkeynes@549: MMIO_WRITE( EXTDMA, reg, val & 0x37 ); nkeynes@279: break; nkeynes@302: case G2DMA1CTL1: nkeynes@302: case G2DMA1CTL2: nkeynes@549: MMIO_WRITE( EXTDMA, reg, val & 1); nkeynes@279: g2_dma_transfer( 1 ); nkeynes@279: break; nkeynes@279: nkeynes@302: case G2DMA1STOP: nkeynes@549: MMIO_WRITE( EXTDMA, reg, val & 0x37 ); nkeynes@279: break; nkeynes@302: case G2DMA2CTL1: nkeynes@302: case G2DMA2CTL2: nkeynes@549: MMIO_WRITE( EXTDMA, reg, val &1 ); nkeynes@279: g2_dma_transfer( 2 ); nkeynes@279: break; nkeynes@302: case G2DMA2STOP: nkeynes@549: MMIO_WRITE( EXTDMA, reg, val & 0x37 ); nkeynes@279: break; nkeynes@302: case G2DMA3CTL1: nkeynes@302: case G2DMA3CTL2: nkeynes@549: MMIO_WRITE( EXTDMA, reg, val &1 ); nkeynes@279: g2_dma_transfer( 3 ); nkeynes@279: break; nkeynes@302: case G2DMA3STOP: nkeynes@549: MMIO_WRITE( EXTDMA, reg, val & 0x37 ); nkeynes@279: break; nkeynes@279: case PVRDMA2CTL1: nkeynes@279: case PVRDMA2CTL2: nkeynes@279: if( val != 0 ) { nkeynes@279: ERROR( "Write to unimplemented DMA control register %08X", reg ); nkeynes@279: } nkeynes@279: break; nkeynes@125: default: nkeynes@2: MMIO_WRITE( EXTDMA, reg, val ); nkeynes@2: } nkeynes@1: } nkeynes@1: nkeynes@1: MMIO_REGION_READ_FN( EXTDMA, reg ) nkeynes@1: { nkeynes@56: uint32_t val; nkeynes@244: if( !idereg.interface_enabled && IS_IDE_REGISTER(reg) ) { nkeynes@244: return 0xFFFFFFFF; /* disabled */ nkeynes@244: } nkeynes@244: nkeynes@1: switch( reg ) { nkeynes@158: case IDEALTSTATUS: nkeynes@158: val = idereg.status; nkeynes@158: return val; nkeynes@158: case IDEDATA: return ide_read_data_pio( ); nkeynes@158: case IDEFEAT: return idereg.error; nkeynes@158: case IDECOUNT:return idereg.count; nkeynes@342: case IDELBA0: return ide_get_drive_status(); nkeynes@158: case IDELBA1: return idereg.lba1; nkeynes@158: case IDELBA2: return idereg.lba2; nkeynes@158: case IDEDEV: return idereg.device; nkeynes@158: case IDECMD: nkeynes@158: val = ide_read_status(); nkeynes@158: return val; nkeynes@158: default: nkeynes@158: val = MMIO_READ( EXTDMA, reg ); nkeynes@158: return val; nkeynes@1: } nkeynes@1: } nkeynes@1: