filename | src/asic.c |
changeset | 125:49bf45f8210a |
prev | 100:995e42e96cc9 |
next | 137:41907543d890 |
author | nkeynes |
date | Thu Mar 30 11:30:59 2006 +0000 (18 years ago) |
permissions | -rw-r--r-- |
last change | Unfubar the pvr event generation Move state into pvr2_state structure for ease of save/load |
view | annotate | diff | log | raw |
1 /**
2 * $Id: asic.c,v 1.13 2006-03-22 14:29:00 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 "dream.h"
24 #include "mem.h"
25 #include "sh4/intc.h"
26 #include "sh4/dmac.h"
27 #include "dreamcast.h"
28 #include "maple/maple.h"
29 #include "gdrom/ide.h"
30 #include "asic.h"
31 #define MMIO_IMPL
32 #include "asic.h"
33 /*
34 * Open questions:
35 * 1) Does changing the mask after event occurance result in the
36 * interrupt being delivered immediately?
37 * TODO: Logic diagram of ASIC event/interrupt logic.
38 *
39 * ... don't even get me started on the "EXTDMA" page, about which, apparently,
40 * practically nothing is publicly known...
41 */
43 struct dreamcast_module asic_module = { "ASIC", asic_init, NULL, NULL, NULL,
44 NULL, NULL, NULL };
46 void asic_check_cleared_events( void );
48 void asic_init( void )
49 {
50 register_io_region( &mmio_region_ASIC );
51 register_io_region( &mmio_region_EXTDMA );
52 mmio_region_ASIC.trace_flag = 0; /* Because this is called so often */
53 }
55 void mmio_region_ASIC_write( uint32_t reg, uint32_t val )
56 {
57 switch( reg ) {
58 case PIRQ1:
59 val = val & 0xFFFFFFFE; /* Prevent the IDE event from clearing */
60 /* fallthrough */
61 case PIRQ0:
62 case PIRQ2:
63 /* Clear any interrupts */
64 MMIO_WRITE( ASIC, reg, MMIO_READ(ASIC, reg)&~val );
65 asic_check_cleared_events();
66 break;
67 case MAPLE_STATE:
68 MMIO_WRITE( ASIC, reg, val );
69 if( val & 1 ) {
70 uint32_t maple_addr = MMIO_READ( ASIC, MAPLE_DMA) &0x1FFFFFE0;
71 WARN( "Maple request initiated at %08X, halting", maple_addr );
72 maple_handle_buffer( maple_addr );
73 MMIO_WRITE( ASIC, reg, 0 );
74 }
75 break;
76 case PVRDMACTL: /* Initiate PVR DMA transfer */
77 MMIO_WRITE( ASIC, reg, val );
78 WARN( "Write to ASIC (%03X <= %08X) [%s: %s]",
79 reg, val, MMIO_REGID(ASIC,reg), MMIO_REGDESC(ASIC,reg) );
80 if( val & 1 ) {
81 uint32_t dest_addr = MMIO_READ( ASIC, PVRDMADEST) &0x1FFFFFE0;
82 uint32_t count = MMIO_READ( ASIC, PVRDMACNT );
83 char *data = alloca( count );
84 uint32_t rcount = DMAC_get_buffer( 2, data, count );
85 if( rcount != count )
86 WARN( "PVR received %08X bytes from DMA, expected %08X", rcount, count );
87 mem_copy_to_sh4( dest_addr, data, rcount );
88 asic_event( EVENT_PVR_DMA );
89 }
90 break;
91 default:
92 MMIO_WRITE( ASIC, reg, val );
93 WARN( "Write to ASIC (%03X <= %08X) [%s: %s]",
94 reg, val, MMIO_REGID(ASIC,reg), MMIO_REGDESC(ASIC,reg) );
95 }
96 }
98 int32_t mmio_region_ASIC_read( uint32_t reg )
99 {
100 int32_t val;
101 switch( reg ) {
102 /*
103 case 0x89C:
104 sh4_stop();
105 return 0x000000B;
106 */
107 case PIRQ0:
108 case PIRQ1:
109 case PIRQ2:
110 case IRQA0:
111 case IRQA1:
112 case IRQA2:
113 case IRQB0:
114 case IRQB1:
115 case IRQB2:
116 case IRQC0:
117 case IRQC1:
118 case IRQC2:
119 val = MMIO_READ(ASIC, reg);
120 // WARN( "Read from ASIC (%03X => %08X) [%s: %s]",
121 // reg, val, MMIO_REGID(ASIC,reg), MMIO_REGDESC(ASIC,reg) );
122 return val;
123 case G2STATUS:
124 return 0; /* find out later if there's any cases we actually need to care about */
125 default:
126 val = MMIO_READ(ASIC, reg);
127 WARN( "Read from ASIC (%03X => %08X) [%s: %s]",
128 reg, val, MMIO_REGID(ASIC,reg), MMIO_REGDESC(ASIC,reg) );
129 return val;
130 }
132 }
134 void asic_event( int event )
135 {
136 int offset = ((event&0x60)>>3);
137 int result = (MMIO_READ(ASIC, PIRQ0 + offset)) |= (1<<(event&0x1F));
139 if( result & MMIO_READ(ASIC, IRQA0 + offset) )
140 intc_raise_interrupt( INT_IRQ13 );
141 if( result & MMIO_READ(ASIC, IRQB0 + offset) )
142 intc_raise_interrupt( INT_IRQ11 );
143 if( result & MMIO_READ(ASIC, IRQC0 + offset) )
144 intc_raise_interrupt( INT_IRQ9 );
145 }
147 void asic_clear_event( int event ) {
148 int offset = ((event&0x60)>>3);
149 uint32_t result = MMIO_READ(ASIC, PIRQ0 + offset) & (~(1<<(event&0x1F)));
150 MMIO_WRITE( ASIC, PIRQ0 + offset, result );
152 asic_check_cleared_events();
153 }
155 void asic_check_cleared_events( )
156 {
157 int i, setA = 0, setB = 0, setC = 0;
158 uint32_t bits;
159 for( i=0; i<3; i++ ) {
160 bits = MMIO_READ( ASIC, PIRQ0 + i );
161 setA |= (bits & MMIO_READ(ASIC, IRQA0 + i ));
162 setB |= (bits & MMIO_READ(ASIC, IRQB0 + i ));
163 setC |= (bits & MMIO_READ(ASIC, IRQC0 + i ));
164 }
165 if( setA == 0 )
166 intc_clear_interrupt( INT_IRQ13 );
167 if( setB == 0 )
168 intc_clear_interrupt( INT_IRQ11 );
169 if( setC == 0 )
170 intc_clear_interrupt( INT_IRQ9 );
171 }
174 MMIO_REGION_WRITE_FN( EXTDMA, reg, val )
175 {
176 WARN( "EXTDMA write %08X <= %08X", reg, val );
178 switch( reg ) {
179 case IDEALTSTATUS: /* Device control */
180 ide_write_control( val );
181 break;
182 case IDEDATA:
183 ide_write_data_pio( val );
184 break;
185 case IDEFEAT:
186 if( ide_can_write_regs() )
187 idereg.feature = (uint8_t)val;
188 break;
189 case IDECOUNT:
190 if( ide_can_write_regs() )
191 idereg.count = (uint8_t)val;
192 break;
193 case IDELBA0:
194 if( ide_can_write_regs() )
195 idereg.lba0 = (uint8_t)val;
196 break;
197 case IDELBA1:
198 if( ide_can_write_regs() )
199 idereg.lba1 = (uint8_t)val;
200 break;
201 case IDELBA2:
202 if( ide_can_write_regs() )
203 idereg.lba2 = (uint8_t)val;
204 break;
205 case IDEDEV:
206 if( ide_can_write_regs() )
207 idereg.device = (uint8_t)val;
208 break;
209 case IDECMD:
210 if( ide_can_write_regs() ) {
211 ide_write_command( (uint8_t)val );
212 }
213 break;
214 case IDEDMACTL1:
215 case IDEDMACTL2:
216 MMIO_WRITE( EXTDMA, reg, val );
217 if( MMIO_READ( EXTDMA, IDEDMACTL1 ) == 1 &&
218 MMIO_READ( EXTDMA, IDEDMACTL2 ) == 1 ) {
219 uint32_t target_addr = MMIO_READ( EXTDMA, IDEDMASH4 );
220 uint32_t length = MMIO_READ( EXTDMA, IDEDMASIZ );
221 int dir = MMIO_READ( EXTDMA, IDEDMADIR );
222 }
223 break;
224 default:
225 MMIO_WRITE( EXTDMA, reg, val );
226 }
227 }
229 MMIO_REGION_READ_FN( EXTDMA, reg )
230 {
231 uint32_t val;
232 switch( reg ) {
233 case IDEALTSTATUS: return idereg.status;
234 case IDEDATA: return ide_read_data_pio( );
235 case IDEFEAT: return idereg.error;
236 case IDECOUNT:return idereg.count;
237 case IDELBA0: return idereg.disc;
238 case IDELBA1: return idereg.lba1;
239 case IDELBA2: return idereg.lba2;
240 case IDEDEV: return idereg.device;
241 case IDECMD:
242 return ide_read_status();
243 default:
244 val = MMIO_READ( EXTDMA, reg );
245 //DEBUG( "EXTDMA read %08X => %08X", reg, val );
246 return val;
247 }
248 }
.