nkeynes@1: #include nkeynes@1: #include "dream.h" nkeynes@1: #include "mem.h" nkeynes@1: #include "sh4/intc.h" nkeynes@1: #include "asic.h" nkeynes@2: #include "dreamcast.h" nkeynes@1: #include "maple.h" nkeynes@2: #include "ide.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: * 2) If the pending register is not cleared after an interrupt, does nkeynes@1: * the interrupt line remain high? (ie does the IRQ reoccur?) 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@1: void asic_init( void ) nkeynes@1: { nkeynes@1: register_io_region( &mmio_region_ASIC ); nkeynes@1: register_io_region( &mmio_region_EXTDMA ); nkeynes@1: mmio_region_ASIC.trace_flag = 0; /* Because this is called so often */ nkeynes@1: asic_event( EVENT_GDROM_CMD ); nkeynes@1: } nkeynes@1: nkeynes@1: void mmio_region_ASIC_write( uint32_t reg, uint32_t val ) nkeynes@1: { nkeynes@1: switch( reg ) { nkeynes@1: case PIRQ0: nkeynes@1: case PIRQ1: nkeynes@1: case PIRQ2: nkeynes@1: /* Clear any interrupts */ nkeynes@1: MMIO_WRITE( ASIC, reg, MMIO_READ(ASIC, reg)&~val ); nkeynes@1: break; nkeynes@1: case MAPLE_STATE: nkeynes@1: MMIO_WRITE( ASIC, reg, val ); nkeynes@1: if( val & 1 ) { nkeynes@1: uint32_t maple_addr = MMIO_READ( ASIC, MAPLE_DMA) &0x1FFFFFE0; nkeynes@2: WARN( "Maple request initiated at %08X, halting", maple_addr ); nkeynes@2: maple_handle_buffer( maple_addr ); nkeynes@1: MMIO_WRITE( ASIC, reg, 0 ); nkeynes@2: // dreamcast_stop(); nkeynes@1: } nkeynes@1: break; nkeynes@1: default: nkeynes@1: MMIO_WRITE( ASIC, reg, val ); nkeynes@1: WARN( "Write to ASIC (%03X <= %08X) [%s: %s]", nkeynes@1: reg, val, MMIO_REGID(ASIC,reg), MMIO_REGDESC(ASIC,reg) ); 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@2: /* nkeynes@2: case 0x89C: nkeynes@2: sh4_stop(); nkeynes@2: return 0x000000B; nkeynes@2: */ nkeynes@1: case PIRQ0: nkeynes@1: case PIRQ1: nkeynes@1: case PIRQ2: nkeynes@1: val = MMIO_READ(ASIC, reg); nkeynes@1: // WARN( "Read from ASIC (%03X => %08X) [%s: %s]", nkeynes@1: // reg, val, MMIO_REGID(ASIC,reg), MMIO_REGDESC(ASIC,reg) ); nkeynes@1: return val; nkeynes@1: case G2STATUS: nkeynes@1: return 0; /* find out later if there's any cases we actually need to care about */ nkeynes@1: default: nkeynes@1: val = MMIO_READ(ASIC, reg); nkeynes@1: WARN( "Read from ASIC (%03X => %08X) [%s: %s]", nkeynes@1: reg, val, MMIO_REGID(ASIC,reg), MMIO_REGDESC(ASIC,reg) ); nkeynes@1: return val; nkeynes@1: } nkeynes@1: nkeynes@1: } nkeynes@1: nkeynes@1: void asic_event( int event ) nkeynes@1: { nkeynes@1: int offset = ((event&0x60)>>3); nkeynes@1: int result = (MMIO_READ(ASIC, PIRQ0 + offset)) |= (1<<(event&0x1F)); nkeynes@1: nkeynes@1: if( result & MMIO_READ(ASIC, IRQA0 + offset) ) nkeynes@1: intc_raise_interrupt( INT_IRQ13 ); nkeynes@1: if( result & MMIO_READ(ASIC, IRQB0 + offset) ) nkeynes@1: intc_raise_interrupt( INT_IRQ11 ); nkeynes@1: if( result & MMIO_READ(ASIC, IRQC0 + offset) ) nkeynes@1: intc_raise_interrupt( INT_IRQ9 ); nkeynes@1: } nkeynes@1: nkeynes@1: nkeynes@1: nkeynes@1: MMIO_REGION_WRITE_FN( EXTDMA, reg, val ) nkeynes@1: { nkeynes@2: switch( reg ) { nkeynes@2: case IDEALTSTATUS: /* Device control */ nkeynes@2: ide_write_control( val ); nkeynes@2: break; nkeynes@2: case IDEDATA: nkeynes@2: ide_write_data_pio( val ); nkeynes@2: break; nkeynes@2: case IDEFEAT: nkeynes@2: if( ide_can_write_regs() ) nkeynes@2: idereg.feature = (uint8_t)val; nkeynes@2: break; nkeynes@2: case IDECOUNT: nkeynes@2: if( ide_can_write_regs() ) nkeynes@2: idereg.count = (uint8_t)val; nkeynes@2: break; nkeynes@2: case IDELBA0: nkeynes@2: if( ide_can_write_regs() ) nkeynes@2: idereg.lba0 = (uint8_t)val; nkeynes@2: break; nkeynes@2: case IDELBA1: nkeynes@2: if( ide_can_write_regs() ) nkeynes@2: idereg.lba1 = (uint8_t)val; nkeynes@2: break; nkeynes@2: case IDELBA2: nkeynes@2: if( ide_can_write_regs() ) nkeynes@2: idereg.lba2 = (uint8_t)val; nkeynes@2: break; nkeynes@2: case IDEDEV: nkeynes@2: if( ide_can_write_regs() ) nkeynes@2: idereg.device = (uint8_t)val; nkeynes@2: break; nkeynes@2: case IDECMD: nkeynes@2: if( ide_can_write_regs() ) { nkeynes@2: ide_clear_interrupt(); nkeynes@2: ide_write_command( (uint8_t)val ); nkeynes@2: } nkeynes@2: break; nkeynes@2: nkeynes@2: 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@1: switch( reg ) { nkeynes@2: case IDEALTSTATUS: return idereg.status; nkeynes@2: case IDEDATA: return ide_read_data_pio( ); nkeynes@2: case IDEFEAT: return idereg.error; nkeynes@2: case IDECOUNT:return idereg.count; nkeynes@2: case IDELBA0: return idereg.disc; nkeynes@2: case IDELBA1: return idereg.lba1; nkeynes@2: case IDELBA2: return idereg.lba2; nkeynes@2: case IDEDEV: return idereg.device; nkeynes@2: case IDECMD: nkeynes@2: ide_clear_interrupt(); nkeynes@2: return idereg.status; nkeynes@1: default: nkeynes@1: return MMIO_READ( EXTDMA, reg ); nkeynes@1: } nkeynes@1: } nkeynes@1: