# HG changeset patch # User nkeynes # Date 1143037742 0 # Node ID 49bf45f8210afa0c27d9416a1c0d0aa2af5e568c # Parent ceb38f08619aaf48e9437f2b366139d5694419e7 Rename IDE DMA registers appropriately Remove forced irq hack Add correct irq handling for IDE Miscellaneous WIP for the GD-rom drive --- a/src/asic.c Wed Mar 22 14:27:40 2006 +0000 +++ b/src/asic.c Wed Mar 22 14:29:02 2006 +0000 @@ -1,5 +1,5 @@ /** - * $Id: asic.c,v 1.12 2006-02-15 13:11:42 nkeynes Exp $ + * $Id: asic.c,v 1.13 2006-03-22 14:29:00 nkeynes Exp $ * * Support for the miscellaneous ASIC functions (Primarily event multiplexing, * and DMA). @@ -50,14 +50,15 @@ register_io_region( &mmio_region_ASIC ); register_io_region( &mmio_region_EXTDMA ); mmio_region_ASIC.trace_flag = 0; /* Because this is called so often */ - asic_event( EVENT_GDROM_CMD ); } void mmio_region_ASIC_write( uint32_t reg, uint32_t val ) { switch( reg ) { + case PIRQ1: + val = val & 0xFFFFFFFE; /* Prevent the IDE event from clearing */ + /* fallthrough */ case PIRQ0: - case PIRQ1: case PIRQ2: /* Clear any interrupts */ MMIO_WRITE( ASIC, reg, MMIO_READ(ASIC, reg)&~val ); @@ -143,6 +144,14 @@ intc_raise_interrupt( INT_IRQ9 ); } +void asic_clear_event( int event ) { + int offset = ((event&0x60)>>3); + uint32_t result = MMIO_READ(ASIC, PIRQ0 + offset) & (~(1<<(event&0x1F))); + MMIO_WRITE( ASIC, PIRQ0 + offset, result ); + + asic_check_cleared_events(); +} + void asic_check_cleared_events( ) { int i, setA = 0, setB = 0, setC = 0; @@ -164,46 +173,55 @@ MMIO_REGION_WRITE_FN( EXTDMA, reg, val ) { + WARN( "EXTDMA write %08X <= %08X", reg, val ); + switch( reg ) { - case IDEALTSTATUS: /* Device control */ - ide_write_control( val ); - break; - case IDEDATA: - ide_write_data_pio( val ); - break; - case IDEFEAT: - if( ide_can_write_regs() ) - idereg.feature = (uint8_t)val; - break; - case IDECOUNT: - if( ide_can_write_regs() ) - idereg.count = (uint8_t)val; - break; - case IDELBA0: - if( ide_can_write_regs() ) - idereg.lba0 = (uint8_t)val; - break; - case IDELBA1: - if( ide_can_write_regs() ) - idereg.lba1 = (uint8_t)val; - break; - case IDELBA2: - if( ide_can_write_regs() ) - idereg.lba2 = (uint8_t)val; - break; - case IDEDEV: - if( ide_can_write_regs() ) - idereg.device = (uint8_t)val; - break; - case IDECMD: - if( ide_can_write_regs() ) { - ide_clear_interrupt(); - ide_write_command( (uint8_t)val ); - } - break; - default: - WARN( "EXTDMA write %08X <= %08X", reg, val ); - + case IDEALTSTATUS: /* Device control */ + ide_write_control( val ); + break; + case IDEDATA: + ide_write_data_pio( val ); + break; + case IDEFEAT: + if( ide_can_write_regs() ) + idereg.feature = (uint8_t)val; + break; + case IDECOUNT: + if( ide_can_write_regs() ) + idereg.count = (uint8_t)val; + break; + case IDELBA0: + if( ide_can_write_regs() ) + idereg.lba0 = (uint8_t)val; + break; + case IDELBA1: + if( ide_can_write_regs() ) + idereg.lba1 = (uint8_t)val; + break; + case IDELBA2: + if( ide_can_write_regs() ) + idereg.lba2 = (uint8_t)val; + break; + case IDEDEV: + if( ide_can_write_regs() ) + idereg.device = (uint8_t)val; + break; + case IDECMD: + if( ide_can_write_regs() ) { + ide_write_command( (uint8_t)val ); + } + break; + case IDEDMACTL1: + case IDEDMACTL2: + MMIO_WRITE( EXTDMA, reg, val ); + if( MMIO_READ( EXTDMA, IDEDMACTL1 ) == 1 && + MMIO_READ( EXTDMA, IDEDMACTL2 ) == 1 ) { + uint32_t target_addr = MMIO_READ( EXTDMA, IDEDMASH4 ); + uint32_t length = MMIO_READ( EXTDMA, IDEDMASIZ ); + int dir = MMIO_READ( EXTDMA, IDEDMADIR ); + } + break; + default: MMIO_WRITE( EXTDMA, reg, val ); } } @@ -221,8 +239,7 @@ case IDELBA2: return idereg.lba2; case IDEDEV: return idereg.device; case IDECMD: - ide_clear_interrupt(); - return idereg.status; + return ide_read_status(); default: val = MMIO_READ( EXTDMA, reg ); //DEBUG( "EXTDMA read %08X => %08X", reg, val ); --- a/src/asic.h Wed Mar 22 14:27:40 2006 +0000 +++ b/src/asic.h Wed Mar 22 14:29:02 2006 +0000 @@ -1,5 +1,5 @@ /** - * $Id: asic.h,v 1.5 2006-01-03 12:21:45 nkeynes Exp $ + * $Id: asic.h,v 1.6 2006-03-22 14:29:00 nkeynes Exp $ * * Support for the miscellaneous ASIC functions (Primarily event multiplexing, * and DMA). Includes MMIO definitions for the 5f6000 and 5f7000 regions, @@ -94,11 +94,11 @@ BYTE_PORT( 0x094, IDELBA2, PORT_RW, 0, "IDE LBA hi" ) /* AKA Cyl hi */ BYTE_PORT( 0x098, IDEDEV, PORT_RW, 0, "IDE Device" ) BYTE_PORT( 0x09C, IDECMD, PORT_RW, 0, "IDE Command/Status" ) - LONG_PORT( 0x404, EXTDMASH4, PORT_MRW, 0, "Ext DMA SH4 address" ) - LONG_PORT( 0x408, EXTDMASIZ, PORT_MRW, 0, "Ext DMA Size" ) - LONG_PORT( 0x40C, EXTDMADIR, PORT_MRW, 0, "Ext DMA Direction" ) - LONG_PORT( 0x414, EXTDMACTL1, PORT_MRW, 0, "Ext DMA Control 1" ) - LONG_PORT( 0x418, EXTDMACTL2, PORT_MRW, 0, "Ext DMA Control 2" ) + LONG_PORT( 0x404, IDEDMASH4, PORT_MRW, 0, "IDE DMA SH4 address" ) + LONG_PORT( 0x408, IDEDMASIZ, PORT_MRW, 0, "IDE DMA Size" ) + LONG_PORT( 0x40C, IDEDMADIR, PORT_MRW, 0, "IDE DMA Direction" ) + LONG_PORT( 0x414, IDEDMACTL1, PORT_MRW, 0, "IDE DMA Control 1" ) + LONG_PORT( 0x418, IDEDMACTL2, PORT_MRW, 0, "IDE DMA Control 2" ) WORD_PORT( 0x480, EXTDMAUNK0, PORT_MRW, 0, "Ext DMA " ) LONG_PORT( 0x484, EXTDMAUNK1, PORT_MRW, 0, "Ext DMA " ) LONG_PORT( 0x488, EXTDMAUNK2, PORT_MRW, 0, "Ext DMA " ) @@ -176,7 +176,7 @@ #define EVENT_PVR_TRANSMOD_DONE 10 #define EVENT_MAPLE_DMA 12 #define EVENT_MAPLE_ERR 13 /* ??? */ -#define EVENT_GDROM_DMA 14 +#define EVENT_IDE_DMA 14 #define EVENT_SPU_DMA0 15 #define EVENT_SPU_DMA1 16 #define EVENT_SPU_DMA2 17 @@ -184,8 +184,18 @@ #define EVENT_PVR_DMA 19 #define EVENT_PVR_PUNCHOUT_DONE 21 -#define EVENT_GDROM_CMD 32 +#define EVENT_IDE 32 #define EVENT_AICA 33 +/** + * Raise an ASIC event + */ void asic_event( int event ); + +/** + * Clear an ASIC event. Currently only the IDE controller is known to use + * this functionality. + */ +void asic_clear_event( int event ); + void asic_init( void ); --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gdrom/gdrom.h Wed Mar 22 14:29:02 2006 +0000 @@ -0,0 +1,44 @@ +/** + * $Id: gdrom.h,v 1.1 2006-03-22 14:29:02 nkeynes Exp $ + * + * This file defines the structures and functions used by the GD-Rom + * disc driver. (ie, the modules that supply a CD image to be used by the + * system). + * + * Copyright (c) 2005 Nathan Keynes. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef dream_gdrom_H +#define dream_gdrom_H 1 + +#include "dream.h" + +typedef struct gdrom_toc { + uint32_t tracks[99]; + uint32_t first, last, leadout; +} *gdrom_toc_t; + + +typedef struct gdrom_disc { + + gboolean (*read_toc)( gdrom_toc_t toc ); + + gboolean (*read_data_sectors)( uint32_t lba, uint32_t sector_count, + char *buf ); +} *gdrom_disc_t; + +void gdrom_mount( gdrom_disc_t disc ); + +void gdrom_unmount( void ); + +#endif --- a/src/gdrom/ide.c Wed Mar 22 14:27:40 2006 +0000 +++ b/src/gdrom/ide.c Wed Mar 22 14:29:02 2006 +0000 @@ -1,5 +1,5 @@ /** - * $Id: ide.c,v 1.7 2005-12-27 12:41:33 nkeynes Exp $ + * $Id: ide.c,v 1.8 2006-03-22 14:29:02 nkeynes Exp $ * * IDE interface implementation * @@ -20,7 +20,9 @@ #include #include "dream.h" +#include "asic.h" #include "gdrom/ide.h" +#include "gdrom/gdrom.h" #define MAX_WRITE_BUF 4096; @@ -32,16 +34,18 @@ struct ide_registers idereg; -static char command_buffer[12]; +static unsigned char command_buffer[12]; /* "\0\0\0\0\xb4\x19\0\0\x08SE REV 6.42990316" */ -char gdrom_ident[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00, +unsigned char gdrom_ident[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00, 0x00, 0x08, 0x53, 0x45, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x52, 0x65, 0x76, 0x20, 0x36, 0x2e, 0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36 }; -void set_write_buffer( char *buf, int len ) +gdrom_disc_t gdrom_disc = NULL; + +static void ide_set_write_buffer( unsigned char *buf, int len ) { idereg.status |= IDE_ST_DATA; idereg.data = buf; @@ -50,7 +54,7 @@ idereg.readptr = NULL; } -void set_read_buffer( char *buf, int len ) +static void ide_set_read_buffer( unsigned char *buf, int len, int blocksize ) { idereg.status |= IDE_ST_DATA; idereg.data = buf; @@ -59,11 +63,31 @@ idereg.writeptr = NULL; idereg.lba1 = len&0xFF; idereg.lba2 = len>>8; + idereg.blocksize = idereg.blockleft = blocksize; } -void ide_clear_interrupt( void ) +static void ide_raise_interrupt( void ) { - /* TODO */ + if( idereg.intrq_pending == 0 ) { + idereg.intrq_pending = 1; + if( IS_IDE_IRQ_ENABLED() ) + asic_event( EVENT_IDE ); + } +} + +static void ide_clear_interrupt( void ) +{ + if( idereg.intrq_pending != 0 ) { + idereg.intrq_pending = 0; + if( IS_IDE_IRQ_ENABLED() ) + asic_clear_event( EVENT_IDE ); + } +} + +static void ide_set_error( int error_code ) +{ + idereg.status = 0x51; + idereg.error = error_code; } void ide_init( void ) @@ -76,13 +100,20 @@ ide_clear_interrupt(); idereg.error = 0x01; idereg.count = 0x01; - idereg.lba0 = 0x21; + idereg.lba0 = /* 0x21; */ 0x81; idereg.lba1 = 0x14; idereg.lba2 = 0xeb; idereg.feature = 0; /* Indeterminate really */ idereg.status = 0x00; idereg.device = 0x00; - idereg.disc = IDE_DISC_GDROM | IDE_DISC_READY; + idereg.disc = (gdrom_disc == NULL ? IDE_DISC_NONE : (IDE_DISC_CDROM|IDE_DISC_READY)); +} + +uint8_t ide_read_status( void ) +{ + if( (idereg.status & IDE_ST_BUSY) == 0 ) + ide_clear_interrupt(); + return idereg.status; } uint16_t ide_read_data_pio( void ) { @@ -90,9 +121,13 @@ return 0xFFFF; uint16_t rv = *idereg.readptr++; idereg.datalen-=2; + idereg.blockleft-=2; if( idereg.datalen <=0 ) { idereg.readptr = NULL; idereg.status &= ~IDE_ST_DATA; + } else if( idereg.blockleft <= 0 ) { + ide_raise_interrupt(); + idereg.blockleft = idereg.blocksize; } return rv; } @@ -103,26 +138,33 @@ *idereg.writeptr++ = val; idereg.datalen-=2; if( idereg.datalen <= 0 ) { + int len = ((unsigned char *)idereg.writeptr) - idereg.data; idereg.writeptr = NULL; idereg.status &= ~IDE_ST_DATA; - ide_write_buffer( idereg.data ); + ide_write_buffer( idereg.data, len ); } } void ide_write_control( uint8_t val ) { - /* TODO: In theory we can cause a soft-reset here, but the DC doesn't - * appear to support it. - */ + if( IS_IDE_IRQ_ENABLED() ) { + if( (val & 0x02) != 0 && idereg.intrq_pending != 0 ) + asic_clear_event( EVENT_IDE ); + } else { + if( (val & 0x02) == 0 && idereg.intrq_pending != 0 ) + asic_event( EVENT_IDE ); + } + idereg.control = val; } void ide_write_command( uint8_t val ) { + ide_clear_interrupt(); idereg.command = val; switch( val ) { case IDE_CMD_RESET_DEVICE: ide_reset(); break; case IDE_CMD_PACKET: - set_write_buffer(command_buffer,12); + ide_set_write_buffer(command_buffer,12); break; case IDE_CMD_SET_FEATURE: switch( idereg.feature ) { @@ -148,6 +190,7 @@ default: WARN( "IDE: unimplemented feature: %02X", idereg.feature ); } + ide_raise_interrupt( ); break; default: WARN( "IDE: Unimplemented command: %02X", val ); @@ -155,24 +198,65 @@ idereg.status |= IDE_ST_READY | IDE_ST_SERV; } -void ide_write_buffer( char *data ) { - uint16_t length; +void ide_packet_command( unsigned char *cmd ) +{ + uint32_t length; + uint32_t lba; + int blocksize = idereg.lba1 + (idereg.lba2<<8); + + ide_raise_interrupt( ); + /* Okay we have the packet in the command buffer */ + WARN( "ATAPI: Received Packet command: %02X", cmd[0] ); + fwrite_dump( (unsigned char *)cmd, 12, stderr ); + switch( cmd[0] ) { + case PKT_CMD_IDENTIFY: + /* NB: Bios sets cmd[4] = 0x08, no idea what this is for; + * different values here appear to have no effect. + */ + length = *((uint16_t*)(cmd+2)); + if( length > sizeof(gdrom_ident) ) + length = sizeof(gdrom_ident); + ide_set_read_buffer(gdrom_ident, length, blocksize); + break; + case PKT_CMD_READ_TOC: + + break; + case PKT_CMD_READ_SECTOR: + lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4]; + length = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */ + if( gdrom_disc == NULL ) { + ide_set_error( 0x50 ); + return; + } + /* + if( gdrom_disc->read_data_sectors( lba, length ) == FALSE ) { + ide_set_error( 0x50 ); + return; + } + + */ + break; + } +} + +void ide_write_buffer( unsigned char *data, int datalen ) { switch( idereg.command ) { case IDE_CMD_PACKET: - /* Okay we have the packet in the command buffer */ - WARN( "ATAPI: Received Packet command: %02X", data[0] ); - - switch( command_buffer[0] ) { - case PKT_CMD_IDENTIFY: - /* NB: Bios sets data[4] = 0x08, no idea what this is for; - * different values here appear to have no effect. - */ - length = *((uint16_t*)(data+2)); - if( length > sizeof(gdrom_ident) ) - length = sizeof(gdrom_ident); - set_read_buffer(gdrom_ident, length); - break; - } + ide_packet_command( data ); break; } } + +/** + * DMA read request + * + * This method is called from the ASIC side when a DMA read request is + * initiated. If there is a pending DMA transfer already, we copy the + * data immediately, otherwise we record the DMA buffer for use when we + * get to actually doing the transfer. + */ +void ide_dma_read_req( uint32_t addr, uint32_t length ) +{ + + +} --- a/src/gdrom/ide.h Wed Mar 22 14:27:40 2006 +0000 +++ b/src/gdrom/ide.h Wed Mar 22 14:29:02 2006 +0000 @@ -1,5 +1,5 @@ /** - * $Id: ide.h,v 1.3 2005-12-27 12:41:33 nkeynes Exp $ + * $Id: ide.h,v 1.4 2006-03-22 14:29:02 nkeynes Exp $ * * This file defines the interface and structures of the dreamcast's IDE * port. Note that the register definitions are in asic.h, as the registers @@ -37,15 +37,18 @@ uint8_t lba2; /* A05F7094 Read/Write 10101 */ uint8_t device; /* A05F7098 Read/Write 10110 */ uint8_t command; /* A05F709C Write-only 10111 */ - + /* We don't keep the data register per se, rather the currently pending * data is kept here and read out a byte at a time (in PIO mode) or all at * once (in DMA mode). The IDE routines are responsible for managing this * memory. If dataptr == NULL, there is no data available. */ - char *data; + unsigned char *data; uint16_t *readptr, *writeptr; int datalen; + int blocksize; /* Used to determine the transfer unit size */ + int blockleft; /* Bytes remaining in the current block */ + uint8_t intrq_pending; /* Flag to indicate if the INTRQ line is active */ }; #define IDE_ST_BUSY 0x80 @@ -82,6 +85,9 @@ #define PKT_CMD_RESET 0x00 /* Wild-ass guess */ #define PKT_CMD_IDENTIFY 0x11 +#define PKT_CMD_SENSE 0x13 +#define PKT_CMD_READ_TOC 0x14 +#define PKT_CMD_READ_SECTOR 0x30 extern struct ide_registers idereg; @@ -89,19 +95,14 @@ * only when ide_can_write_regs() is true */ #define ide_can_write_regs() ((idereg.status&0x88)==0) - -/* Called upon: - * a) Writing the command register - * b) Reading the status (but not altstatus) register - * (whether this actually has any effect an the ASIC event is TBD) - */ -void ide_clear_interrupt(void); +#define IS_IDE_IRQ_ENABLED() ((idereg.control&0x02)==0) void ide_reset(void); uint16_t ide_read_data_pio(void); +uint8_t ide_read_status(void); void ide_write_data_pio( uint16_t value ); -void ide_write_buffer( char * ); +void ide_write_buffer( unsigned char *data, int length ); void ide_write_command( uint8_t command ); void ide_write_control( uint8_t value );