Search
lxdream.org :: lxdream/src/asic.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/asic.c
changeset 255:ade289880b8d
prev244:4c2b7291d3b0
next279:7bb759c23271
author nkeynes
date Wed Jan 03 09:00:17 2007 +0000 (17 years ago)
permissions -rw-r--r--
last change Adjust timers when they're read rather than waiting until the next time
slice. Also temporarily cut the CPU time by 4.
Initialize the FRQCR register to 0x0E0A for convenience
view annotate diff log raw
     1 /**
     2  * $Id: asic.c,v 1.22 2006-12-21 11:12:19 nkeynes Exp $
     3  *
     4  * Support for the miscellaneous ASIC functions (Primarily event multiplexing,
     5  * and DMA). 
     6  *
     7  * Copyright (c) 2005 Nathan Keynes.
     8  *
     9  * This program is free software; you can redistribute it and/or modify
    10  * it under the terms of the GNU General Public License as published by
    11  * the Free Software Foundation; either version 2 of the License, or
    12  * (at your option) any later version.
    13  *
    14  * This program is distributed in the hope that it will be useful,
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    17  * GNU General Public License for more details.
    18  */
    20 #define MODULE asic_module
    22 #include <assert.h>
    23 #include <stdlib.h>
    24 #include "dream.h"
    25 #include "mem.h"
    26 #include "sh4/intc.h"
    27 #include "sh4/dmac.h"
    28 #include "dreamcast.h"
    29 #include "maple/maple.h"
    30 #include "gdrom/ide.h"
    31 #include "asic.h"
    32 #define MMIO_IMPL
    33 #include "asic.h"
    34 /*
    35  * Open questions:
    36  *   1) Does changing the mask after event occurance result in the
    37  *      interrupt being delivered immediately?
    38  * TODO: Logic diagram of ASIC event/interrupt logic.
    39  *
    40  * ... don't even get me started on the "EXTDMA" page, about which, apparently,
    41  * practically nothing is publicly known...
    42  */
    44 static void asic_check_cleared_events( void );
    45 static void asic_init( void );
    46 static void asic_reset( void );
    47 static void asic_save_state( FILE *f );
    48 static int asic_load_state( FILE *f );
    50 struct dreamcast_module asic_module = { "ASIC", asic_init, asic_reset, NULL, NULL,
    51 					NULL, asic_save_state, asic_load_state };
    53 #define G2_BIT5_TICKS 8
    54 #define G2_BIT4_TICKS 16
    55 #define G2_BIT0_ON_TICKS 24
    56 #define G2_BIT0_OFF_TICKS 24
    58 struct asic_g2_state {
    59     unsigned int last_update_time;
    60     unsigned int bit5_off_timer;
    61     unsigned int bit4_on_timer;
    62     unsigned int bit4_off_timer;
    63     unsigned int bit0_on_timer;
    64     unsigned int bit0_off_timer;
    65 };
    67 static struct asic_g2_state g2_state;
    69 static void asic_init( void )
    70 {
    71     register_io_region( &mmio_region_ASIC );
    72     register_io_region( &mmio_region_EXTDMA );
    73     asic_reset();
    74 }
    76 static void asic_reset( void )
    77 {
    78     memset( &g2_state, 0, sizeof(g2_state) );
    79 }    
    81 static void asic_save_state( FILE *f )
    82 {
    83     fwrite( &g2_state, sizeof(g2_state), 1, f );
    84 }
    86 static int asic_load_state( FILE *f )
    87 {
    88     if( fread( &g2_state, sizeof(g2_state), 1, f ) != 1 )
    89 	return 1;
    90     else
    91 	return 0;
    92 }
    95 /* FIXME: Handle rollover */
    96 void asic_g2_write_word()
    97 {
    98     g2_state.last_update_time = sh4r.icount;
    99     g2_state.bit5_off_timer = sh4r.icount + G2_BIT5_TICKS;
   100     if( g2_state.bit4_off_timer < sh4r.icount )
   101 	g2_state.bit4_on_timer = sh4r.icount + G2_BIT5_TICKS;
   102     g2_state.bit4_off_timer = max(sh4r.icount,g2_state.bit4_off_timer) + G2_BIT4_TICKS;
   103     if( g2_state.bit0_off_timer < sh4r.icount ) {
   104 	g2_state.bit0_on_timer = sh4r.icount + G2_BIT0_ON_TICKS;
   105 	g2_state.bit0_off_timer = g2_state.bit0_on_timer + G2_BIT0_OFF_TICKS;
   106     } else {
   107 	g2_state.bit0_off_timer += G2_BIT0_OFF_TICKS;
   108     }
   109     MMIO_WRITE( ASIC, G2STATUS, MMIO_READ(ASIC, G2STATUS) | 0x20 );
   110 }
   112 static uint32_t g2_read_status()
   113 {
   114     if( sh4r.icount < g2_state.last_update_time ) {
   115 	/* Rollover */
   116 	if( g2_state.last_update_time < g2_state.bit5_off_timer )
   117 	    g2_state.bit5_off_timer = 0;
   118 	if( g2_state.last_update_time < g2_state.bit4_off_timer )
   119 	    g2_state.bit4_off_timer = 0;
   120 	if( g2_state.last_update_time < g2_state.bit4_on_timer )
   121 	    g2_state.bit4_on_timer = 0;
   122 	if( g2_state.last_update_time < g2_state.bit0_off_timer )
   123 	    g2_state.bit0_off_timer = 0;
   124 	if( g2_state.last_update_time < g2_state.bit0_on_timer )
   125 	    g2_state.bit0_on_timer = 0;
   126     }
   127     uint32_t val = MMIO_READ( ASIC, G2STATUS );
   128     if( g2_state.bit5_off_timer <= sh4r.icount )
   129 	val = val & (~0x20);
   130     if( g2_state.bit4_off_timer <= sh4r.icount ||
   131 	(sh4r.icount + G2_BIT5_TICKS) < g2_state.bit4_off_timer )
   132 	val = val & (~0x10);
   133     else if( g2_state.bit4_on_timer <= sh4r.icount )
   134 	val = val | 0x10;
   135     if( g2_state.bit0_off_timer <= sh4r.icount )
   136 	val = val & (~0x01);
   137     else if( g2_state.bit0_on_timer <= sh4r.icount )
   138 	val = val | 0x01;
   139     return val | 0x0E;
   140 }   
   143 void asic_event( int event )
   144 {
   145     int offset = ((event&0x60)>>3);
   146     int result = (MMIO_READ(ASIC, PIRQ0 + offset))  |=  (1<<(event&0x1F));
   148     if( result & MMIO_READ(ASIC, IRQA0 + offset) )
   149         intc_raise_interrupt( INT_IRQ13 );
   150     if( result & MMIO_READ(ASIC, IRQB0 + offset) )
   151         intc_raise_interrupt( INT_IRQ11 );
   152     if( result & MMIO_READ(ASIC, IRQC0 + offset) )
   153         intc_raise_interrupt( INT_IRQ9 );
   154 }
   156 void asic_clear_event( int event ) {
   157     int offset = ((event&0x60)>>3);
   158     uint32_t result = MMIO_READ(ASIC, PIRQ0 + offset)  & (~(1<<(event&0x1F)));
   159     MMIO_WRITE( ASIC, PIRQ0 + offset, result );
   161     asic_check_cleared_events();
   162 }
   164 void asic_check_cleared_events( )
   165 {
   166     int i, setA = 0, setB = 0, setC = 0;
   167     uint32_t bits;
   168     for( i=0; i<3; i++ ) {
   169 	bits = MMIO_READ( ASIC, PIRQ0 + i );
   170 	setA |= (bits & MMIO_READ(ASIC, IRQA0 + i ));
   171 	setB |= (bits & MMIO_READ(ASIC, IRQB0 + i ));
   172 	setC |= (bits & MMIO_READ(ASIC, IRQC0 + i ));
   173     }
   174     if( setA == 0 )
   175 	intc_clear_interrupt( INT_IRQ13 );
   176     if( setB == 0 )
   177 	intc_clear_interrupt( INT_IRQ11 );
   178     if( setC == 0 )
   179 	intc_clear_interrupt( INT_IRQ9 );
   180 }
   183 void asic_ide_dma_transfer( )
   184 {	
   185     if( MMIO_READ( EXTDMA, IDEDMACTL2 ) == 1 ) {
   186 	if( MMIO_READ( EXTDMA, IDEDMACTL1 ) == 1 ) {
   187 	    MMIO_WRITE( EXTDMA, IDEDMATXSIZ, 0 );
   189 	    uint32_t addr = MMIO_READ( EXTDMA, IDEDMASH4 );
   190 	    uint32_t length = MMIO_READ( EXTDMA, IDEDMASIZ );
   191 	    int dir = MMIO_READ( EXTDMA, IDEDMADIR );
   193 	    uint32_t xfer = ide_read_data_dma( addr, length );
   194 	    MMIO_WRITE( EXTDMA, IDEDMATXSIZ, xfer );
   195 	    MMIO_WRITE( EXTDMA, IDEDMACTL2, 0 );
   196 	} else { /* 0 */
   197 	    MMIO_WRITE( EXTDMA, IDEDMACTL2, 0 );
   198 	}
   199     }
   201 }
   204 void mmio_region_ASIC_write( uint32_t reg, uint32_t val )
   205 {
   206     switch( reg ) {
   207     case PIRQ1:
   208 	val = val & 0xFFFFFFFE; /* Prevent the IDE event from clearing */
   209 	/* fallthrough */
   210     case PIRQ0:
   211     case PIRQ2:
   212 	/* Clear any interrupts */
   213 	MMIO_WRITE( ASIC, reg, MMIO_READ(ASIC, reg)&~val );
   214 	asic_check_cleared_events();
   215 	break;
   216     case SYSRESET:
   217 	if( val == 0x7611 ) {
   218 	    dreamcast_reset();
   219 	    sh4r.new_pc = sh4r.pc;
   220 	} else {
   221 	    WARN( "Unknown value %08X written to SYSRESET port", val );
   222 	}
   223 	break;
   224     case MAPLE_STATE:
   225 	MMIO_WRITE( ASIC, reg, val );
   226 	if( val & 1 ) {
   227 	    uint32_t maple_addr = MMIO_READ( ASIC, MAPLE_DMA) &0x1FFFFFE0;
   228 	    maple_handle_buffer( maple_addr );
   229 	    MMIO_WRITE( ASIC, reg, 0 );
   230 	}
   231 	break;
   232     case PVRDMACTL: /* Initiate PVR DMA transfer */
   233 	MMIO_WRITE( ASIC, reg, val );
   234 	if( val & 1 ) {
   235 	    uint32_t dest_addr = MMIO_READ( ASIC, PVRDMADEST) &0x1FFFFFE0;
   236 	    uint32_t count = MMIO_READ( ASIC, PVRDMACNT );
   237 	    char *data = alloca( count );
   238 	    uint32_t rcount = DMAC_get_buffer( 2, data, count );
   239 	    if( rcount != count )
   240 		WARN( "PVR received %08X bytes from DMA, expected %08X", rcount, count );
   241 	    mem_copy_to_sh4( dest_addr, data, rcount );
   242 	    asic_event( EVENT_PVR_DMA );
   243 	    MMIO_WRITE( ASIC, PVRDMACTL, 0 );
   244 	    MMIO_WRITE( ASIC, PVRDMACNT, 0 );
   245 	}
   246 	break;
   247     case PVRDMADEST: case PVRDMACNT: case MAPLE_DMA:
   248 	MMIO_WRITE( ASIC, reg, val );
   249 	break;
   250     default:
   251 	MMIO_WRITE( ASIC, reg, val );
   252     }
   253 }
   255 int32_t mmio_region_ASIC_read( uint32_t reg )
   256 {
   257     int32_t val;
   258     switch( reg ) {
   259         /*
   260         case 0x89C:
   261             sh4_stop();
   262             return 0x000000B;
   263         */     
   264     case PIRQ0:
   265     case PIRQ1:
   266     case PIRQ2:
   267     case IRQA0:
   268     case IRQA1:
   269     case IRQA2:
   270     case IRQB0:
   271     case IRQB1:
   272     case IRQB2:
   273     case IRQC0:
   274     case IRQC1:
   275     case IRQC2:
   276     case MAPLE_STATE:
   277 	val = MMIO_READ(ASIC, reg);
   278 	return val;            
   279     case G2STATUS:
   280 	return g2_read_status();
   281     default:
   282 	val = MMIO_READ(ASIC, reg);
   283 	return val;
   284     }
   286 }
   288 MMIO_REGION_WRITE_FN( EXTDMA, reg, val )
   289 {
   290     if( !idereg.interface_enabled && IS_IDE_REGISTER(reg) ) {
   291 	return; /* disabled */
   292     }
   294     switch( reg ) {
   295     case IDEALTSTATUS: /* Device control */
   296 	ide_write_control( val );
   297 	break;
   298     case IDEDATA:
   299 	ide_write_data_pio( val );
   300 	break;
   301     case IDEFEAT:
   302 	if( ide_can_write_regs() )
   303 	    idereg.feature = (uint8_t)val;
   304 	break;
   305     case IDECOUNT:
   306 	if( ide_can_write_regs() )
   307 	    idereg.count = (uint8_t)val;
   308 	break;
   309     case IDELBA0:
   310 	if( ide_can_write_regs() )
   311 	    idereg.lba0 = (uint8_t)val;
   312 	break;
   313     case IDELBA1:
   314 	if( ide_can_write_regs() )
   315 	    idereg.lba1 = (uint8_t)val;
   316 	break;
   317     case IDELBA2:
   318 	if( ide_can_write_regs() )
   319 	    idereg.lba2 = (uint8_t)val;
   320 	break;
   321     case IDEDEV:
   322 	if( ide_can_write_regs() )
   323 	    idereg.device = (uint8_t)val;
   324 	break;
   325     case IDECMD:
   326 	if( ide_can_write_regs() || val == IDE_CMD_NOP ) {
   327 	    ide_write_command( (uint8_t)val );
   328 	}
   329 	break;
   330     case IDEDMACTL1:
   331 	MMIO_WRITE( EXTDMA, reg, val );
   332     case IDEDMACTL2:
   333 	MMIO_WRITE( EXTDMA, reg, val );
   334 	asic_ide_dma_transfer( );
   335 	break;
   336     case IDEACTIVATE:
   337 	if( val == 0x001FFFFF ) {
   338 	    idereg.interface_enabled = TRUE;
   339 	    /* Conventional wisdom says that this is necessary but not
   340 	     * sufficient to enable the IDE interface.
   341 	     */
   342 	} else if( val == 0x000042FE ) {
   343 	    idereg.interface_enabled = FALSE;
   344 	}
   345     default:
   346             MMIO_WRITE( EXTDMA, reg, val );
   347     }
   348 }
   350 MMIO_REGION_READ_FN( EXTDMA, reg )
   351 {
   352     uint32_t val;
   353     if( !idereg.interface_enabled && IS_IDE_REGISTER(reg) ) {
   354 	return 0xFFFFFFFF; /* disabled */
   355     }
   357     switch( reg ) {
   358     case IDEALTSTATUS: 
   359 	val = idereg.status;
   360 	return val;
   361     case IDEDATA: return ide_read_data_pio( );
   362     case IDEFEAT: return idereg.error;
   363     case IDECOUNT:return idereg.count;
   364     case IDELBA0: return idereg.disc;
   365     case IDELBA1: return idereg.lba1;
   366     case IDELBA2: return idereg.lba2;
   367     case IDEDEV: return idereg.device;
   368     case IDECMD:
   369 	val = ide_read_status();
   370 	return val;
   371     default:
   372 	val = MMIO_READ( EXTDMA, reg );
   373 	return val;
   374     }
   375 }
.