root / hw / gusemu_hal.c @ c4470b25
History | View | Annotate | Download (22.6 kB)
1 | 423d65f4 | balrog | /*
|
---|---|---|---|
2 | 423d65f4 | balrog | * GUSEMU32 - bus interface part
|
3 | 423d65f4 | balrog | *
|
4 | 423d65f4 | balrog | * Copyright (C) 2000-2007 Tibor "TS" Schütz
|
5 | 423d65f4 | balrog | *
|
6 | 423d65f4 | balrog | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | 423d65f4 | balrog | * of this software and associated documentation files (the "Software"), to deal
|
8 | 423d65f4 | balrog | * in the Software without restriction, including without limitation the rights
|
9 | 423d65f4 | balrog | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | 423d65f4 | balrog | * copies of the Software, and to permit persons to whom the Software is
|
11 | 423d65f4 | balrog | * furnished to do so, subject to the following conditions:
|
12 | 423d65f4 | balrog | *
|
13 | 423d65f4 | balrog | * The above copyright notice and this permission notice shall be included in
|
14 | 423d65f4 | balrog | * all copies or substantial portions of the Software.
|
15 | 423d65f4 | balrog | *
|
16 | 423d65f4 | balrog | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | 423d65f4 | balrog | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | 423d65f4 | balrog | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | 423d65f4 | balrog | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | 423d65f4 | balrog | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | 423d65f4 | balrog | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | 423d65f4 | balrog | * THE SOFTWARE.
|
23 | 423d65f4 | balrog | */
|
24 | 423d65f4 | balrog | |
25 | 423d65f4 | balrog | /*
|
26 | 423d65f4 | balrog | * TODO: check mixer: see 7.20 of sdk for panning pos (applies to all gus models?)?
|
27 | 423d65f4 | balrog | */
|
28 | 423d65f4 | balrog | |
29 | 423d65f4 | balrog | #include "gustate.h" |
30 | 423d65f4 | balrog | #include "gusemu.h" |
31 | 423d65f4 | balrog | |
32 | 423d65f4 | balrog | #define GUSregb(position) (* (gusptr+(position)))
|
33 | 423d65f4 | balrog | #define GUSregw(position) (*(GUSword *) (gusptr+(position)))
|
34 | 423d65f4 | balrog | #define GUSregd(position) (*(GUSdword *)(gusptr+(position)))
|
35 | 423d65f4 | balrog | |
36 | 423d65f4 | balrog | /* size given in bytes */
|
37 | 423d65f4 | balrog | unsigned int gus_read(GUSEmuState * state, int port, int size) |
38 | 423d65f4 | balrog | { |
39 | 423d65f4 | balrog | int value_read = 0; |
40 | 423d65f4 | balrog | |
41 | 423d65f4 | balrog | GUSbyte *gusptr; |
42 | 423d65f4 | balrog | gusptr = state->gusdatapos; |
43 | 423d65f4 | balrog | GUSregd(portaccesses)++; |
44 | 423d65f4 | balrog | |
45 | 423d65f4 | balrog | switch (port & 0xff0f) |
46 | 423d65f4 | balrog | { |
47 | 423d65f4 | balrog | /* MixerCtrlReg (read not supported on GUS classic) */
|
48 | 423d65f4 | balrog | /* case 0x200: return GUSregb(MixerCtrlReg2x0); */
|
49 | 423d65f4 | balrog | case 0x206: /* IRQstatReg / SB2x6IRQ */ |
50 | 423d65f4 | balrog | /* adlib/sb bits set in port handlers */
|
51 | 423d65f4 | balrog | /* timer/voice bits set in gus_irqgen() */
|
52 | 423d65f4 | balrog | /* dma bit set in gus_dma_transferdata */
|
53 | 423d65f4 | balrog | /* midi not implemented yet */
|
54 | 423d65f4 | balrog | return GUSregb(IRQStatReg2x6);
|
55 | 423d65f4 | balrog | /* case 0x308: */ /* AdLib388 */ |
56 | 423d65f4 | balrog | case 0x208: |
57 | 423d65f4 | balrog | if (GUSregb(GUS45TimerCtrl) & 1) |
58 | 423d65f4 | balrog | return GUSregb(TimerStatus2x8);
|
59 | 423d65f4 | balrog | return GUSregb(AdLibStatus2x8); /* AdLibStatus */ |
60 | 423d65f4 | balrog | case 0x309: /* AdLib389 */ |
61 | 423d65f4 | balrog | case 0x209: |
62 | 423d65f4 | balrog | return GUSregb(AdLibData2x9); /* AdLibData */ |
63 | 423d65f4 | balrog | case 0x20A: |
64 | 423d65f4 | balrog | return GUSregb(AdLibCommand2xA); /* AdLib2x8_2xA */ |
65 | 423d65f4 | balrog | |
66 | 423d65f4 | balrog | #if 0
|
67 | 423d65f4 | balrog | case 0x20B: /* GUS hidden registers (read not supported on GUS classic) */
|
68 | 423d65f4 | balrog | switch (GUSregb(RegCtrl_2xF) & 0x07)
|
69 | 423d65f4 | balrog | {
|
70 | 423d65f4 | balrog | case 0: /* IRQ/DMA select */
|
71 | 423d65f4 | balrog | if (GUSregb(MixerCtrlReg2x0) & 0x40)
|
72 | 423d65f4 | balrog | return GUSregb(IRQ_2xB); /* control register select bit */
|
73 | 423d65f4 | balrog | else
|
74 | 423d65f4 | balrog | return GUSregb(DMA_2xB);
|
75 | 423d65f4 | balrog | /* case 1-5: */ /* general purpose emulation regs */
|
76 | 423d65f4 | balrog | /* return ... */ /* + status reset reg (write only) */
|
77 | 423d65f4 | balrog | case 6:
|
78 | 423d65f4 | balrog | return GUSregb(Jumper_2xB); /* Joystick/MIDI enable (JumperReg) */
|
79 | 423d65f4 | balrog | default:;
|
80 | 423d65f4 | balrog | }
|
81 | 423d65f4 | balrog | break;
|
82 | 423d65f4 | balrog | #endif
|
83 | 423d65f4 | balrog | |
84 | 423d65f4 | balrog | case 0x20C: /* SB2xCd */ |
85 | 423d65f4 | balrog | value_read = GUSregb(SB2xCd); |
86 | 423d65f4 | balrog | if (GUSregb(StatRead_2xF) & 0x20) |
87 | 423d65f4 | balrog | GUSregb(SB2xCd) ^= 0x80; /* toggle MSB on read */ |
88 | 423d65f4 | balrog | return value_read;
|
89 | 423d65f4 | balrog | /* case 0x20D: */ /* SB2xD is write only -> 2xE writes to it*/ |
90 | 423d65f4 | balrog | case 0x20E: |
91 | 423d65f4 | balrog | if (GUSregb(RegCtrl_2xF) & 0x80) /* 2xE read IRQ enabled? */ |
92 | 423d65f4 | balrog | { |
93 | 423d65f4 | balrog | GUSregb(StatRead_2xF) |= 0x80;
|
94 | 423d65f4 | balrog | GUS_irqrequest(state, state->gusirq, 1);
|
95 | 423d65f4 | balrog | } |
96 | 423d65f4 | balrog | return GUSregb(SB2xE); /* SB2xE */ |
97 | 423d65f4 | balrog | case 0x20F: /* StatRead_2xF */ |
98 | 423d65f4 | balrog | /*set/clear fixed bits */
|
99 | 423d65f4 | balrog | /*value_read = (GUSregb(StatRead_2xF) & 0xf9)|1; */ /*(LSB not set on GUS classic!)*/ |
100 | 423d65f4 | balrog | value_read = (GUSregb(StatRead_2xF) & 0xf9);
|
101 | 423d65f4 | balrog | if (GUSregb(MixerCtrlReg2x0) & 0x08) |
102 | 423d65f4 | balrog | value_read |= 2; /* DMA/IRQ enabled flag */ |
103 | 423d65f4 | balrog | return value_read;
|
104 | 423d65f4 | balrog | /* case 0x300: */ /* MIDI (not implemented) */ |
105 | 423d65f4 | balrog | /* case 0x301: */ /* MIDI (not implemented) */ |
106 | 423d65f4 | balrog | case 0x302: |
107 | 423d65f4 | balrog | return GUSregb(VoiceSelReg3x2); /* VoiceSelReg */ |
108 | 423d65f4 | balrog | case 0x303: |
109 | 423d65f4 | balrog | return GUSregb(FunkSelReg3x3); /* FunkSelReg */ |
110 | 423d65f4 | balrog | case 0x304: /* DataRegLoByte3x4 + DataRegWord3x4 */ |
111 | 423d65f4 | balrog | case 0x305: /* DataRegHiByte3x5 */ |
112 | 423d65f4 | balrog | switch (GUSregb(FunkSelReg3x3))
|
113 | 423d65f4 | balrog | { |
114 | 423d65f4 | balrog | /* common functions */
|
115 | 423d65f4 | balrog | case 0x41: /* DramDMAContrReg */ |
116 | 423d65f4 | balrog | value_read = GUSregb(GUS41DMACtrl); /* &0xfb */
|
117 | 423d65f4 | balrog | GUSregb(GUS41DMACtrl) &= 0xbb;
|
118 | 423d65f4 | balrog | if (state->gusdma >= 4) |
119 | 423d65f4 | balrog | value_read |= 0x04;
|
120 | 423d65f4 | balrog | if (GUSregb(IRQStatReg2x6) & 0x80) |
121 | 423d65f4 | balrog | { |
122 | 423d65f4 | balrog | value_read |= 0x40;
|
123 | 423d65f4 | balrog | GUSregb(IRQStatReg2x6) &= 0x7f;
|
124 | 423d65f4 | balrog | if (!GUSregb(IRQStatReg2x6))
|
125 | 423d65f4 | balrog | GUS_irqclear(state, state->gusirq); |
126 | 423d65f4 | balrog | } |
127 | 423d65f4 | balrog | return (GUSbyte) value_read;
|
128 | 423d65f4 | balrog | /* DramDMAmemPosReg */
|
129 | 423d65f4 | balrog | /* case 0x42: value_read=GUSregw(GUS42DMAStart); break;*/
|
130 | 423d65f4 | balrog | /* 43h+44h write only */
|
131 | 423d65f4 | balrog | case 0x45: |
132 | 423d65f4 | balrog | return GUSregb(GUS45TimerCtrl); /* TimerCtrlReg */ |
133 | 423d65f4 | balrog | /* 46h+47h write only */
|
134 | 423d65f4 | balrog | /* 48h: samp freq - write only */
|
135 | 423d65f4 | balrog | case 0x49: |
136 | 423d65f4 | balrog | return GUSregb(GUS49SampCtrl) & 0xbf; /* SampCtrlReg */ |
137 | 423d65f4 | balrog | /* case 4bh: */ /* joystick trim not supported */ |
138 | 423d65f4 | balrog | /* case 0x4c: return GUSregb(GUS4cReset); */ /* GUSreset: write only*/ |
139 | 423d65f4 | balrog | /* voice specific functions */
|
140 | 423d65f4 | balrog | case 0x80: |
141 | 423d65f4 | balrog | case 0x81: |
142 | 423d65f4 | balrog | case 0x82: |
143 | 423d65f4 | balrog | case 0x83: |
144 | 423d65f4 | balrog | case 0x84: |
145 | 423d65f4 | balrog | case 0x85: |
146 | 423d65f4 | balrog | case 0x86: |
147 | 423d65f4 | balrog | case 0x87: |
148 | 423d65f4 | balrog | case 0x88: |
149 | 423d65f4 | balrog | case 0x89: |
150 | 423d65f4 | balrog | case 0x8a: |
151 | 423d65f4 | balrog | case 0x8b: |
152 | 423d65f4 | balrog | case 0x8c: |
153 | 423d65f4 | balrog | case 0x8d: |
154 | 423d65f4 | balrog | { |
155 | 423d65f4 | balrog | int offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f); |
156 | 423d65f4 | balrog | offset += ((int) GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Funktion*2 */ |
157 | 423d65f4 | balrog | value_read = GUSregw(offset); |
158 | 423d65f4 | balrog | } |
159 | 423d65f4 | balrog | break;
|
160 | 423d65f4 | balrog | /* voice unspecific functions */
|
161 | 423d65f4 | balrog | case 0x8e: /* NumVoice */ |
162 | 423d65f4 | balrog | return GUSregb(NumVoices);
|
163 | 423d65f4 | balrog | case 0x8f: /* irqstatreg */ |
164 | 423d65f4 | balrog | /* (pseudo IRQ-FIFO is processed during a gus_write(0x3X3,0x8f)) */
|
165 | 423d65f4 | balrog | return GUSregb(SynVoiceIRQ8f);
|
166 | 423d65f4 | balrog | default:
|
167 | 423d65f4 | balrog | return 0xffff; |
168 | 423d65f4 | balrog | } |
169 | 423d65f4 | balrog | if (size == 1) |
170 | 423d65f4 | balrog | { |
171 | 423d65f4 | balrog | if ((port & 0xff0f) == 0x305) |
172 | 423d65f4 | balrog | value_read = value_read >> 8;
|
173 | 423d65f4 | balrog | value_read &= 0xff;
|
174 | 423d65f4 | balrog | } |
175 | 423d65f4 | balrog | return (GUSword) value_read;
|
176 | 423d65f4 | balrog | /* case 0x306: */ /* Mixer/Version info */ |
177 | 423d65f4 | balrog | /* return 0xff; */ /* Pre 3.6 boards, ICS mixer NOT present */ |
178 | 423d65f4 | balrog | case 0x307: /* DRAMaccess */ |
179 | 423d65f4 | balrog | { |
180 | 423d65f4 | balrog | GUSbyte *adr; |
181 | 423d65f4 | balrog | adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
|
182 | 423d65f4 | balrog | return *adr;
|
183 | 423d65f4 | balrog | } |
184 | 423d65f4 | balrog | default:;
|
185 | 423d65f4 | balrog | } |
186 | 423d65f4 | balrog | return 0xffff; |
187 | 423d65f4 | balrog | } |
188 | 423d65f4 | balrog | |
189 | 423d65f4 | balrog | void gus_write(GUSEmuState * state, int port, int size, unsigned int data) |
190 | 423d65f4 | balrog | { |
191 | 423d65f4 | balrog | GUSbyte *gusptr; |
192 | 423d65f4 | balrog | gusptr = state->gusdatapos; |
193 | 423d65f4 | balrog | GUSregd(portaccesses)++; |
194 | 423d65f4 | balrog | |
195 | 423d65f4 | balrog | switch (port & 0xff0f) |
196 | 423d65f4 | balrog | { |
197 | 423d65f4 | balrog | case 0x200: /* MixerCtrlReg */ |
198 | 423d65f4 | balrog | GUSregb(MixerCtrlReg2x0) = (GUSbyte) data; |
199 | 423d65f4 | balrog | break;
|
200 | 423d65f4 | balrog | case 0x206: /* IRQstatReg / SB2x6IRQ */ |
201 | 423d65f4 | balrog | if (GUSregb(GUS45TimerCtrl) & 0x20) /* SB IRQ enabled? -> set 2x6IRQ bit */ |
202 | 423d65f4 | balrog | { |
203 | 423d65f4 | balrog | GUSregb(TimerStatus2x8) |= 0x08;
|
204 | 423d65f4 | balrog | GUSregb(IRQStatReg2x6) = 0x10;
|
205 | 423d65f4 | balrog | GUS_irqrequest(state, state->gusirq, 1);
|
206 | 423d65f4 | balrog | } |
207 | 423d65f4 | balrog | break;
|
208 | 423d65f4 | balrog | case 0x308: /* AdLib 388h */ |
209 | 423d65f4 | balrog | case 0x208: /* AdLibCommandReg */ |
210 | 423d65f4 | balrog | GUSregb(AdLibCommand2xA) = (GUSbyte) data; |
211 | 423d65f4 | balrog | break;
|
212 | 423d65f4 | balrog | case 0x309: /* AdLib 389h */ |
213 | 423d65f4 | balrog | case 0x209: /* AdLibDataReg */ |
214 | 423d65f4 | balrog | if ((GUSregb(AdLibCommand2xA) == 0x04) && (!(GUSregb(GUS45TimerCtrl) & 1))) /* GUS auto timer mode enabled? */ |
215 | 423d65f4 | balrog | { |
216 | 423d65f4 | balrog | if (data & 0x80) |
217 | 423d65f4 | balrog | GUSregb(TimerStatus2x8) &= 0x1f; /* AdLib IRQ reset? -> clear maskable adl. timer int regs */ |
218 | 423d65f4 | balrog | else
|
219 | 423d65f4 | balrog | GUSregb(TimerDataReg2x9) = (GUSbyte) data; |
220 | 423d65f4 | balrog | } |
221 | 423d65f4 | balrog | else
|
222 | 423d65f4 | balrog | { |
223 | 423d65f4 | balrog | GUSregb(AdLibData2x9) = (GUSbyte) data; |
224 | 423d65f4 | balrog | if (GUSregb(GUS45TimerCtrl) & 0x02) |
225 | 423d65f4 | balrog | { |
226 | 423d65f4 | balrog | GUSregb(TimerStatus2x8) |= 0x01;
|
227 | 423d65f4 | balrog | GUSregb(IRQStatReg2x6) = 0x10;
|
228 | 423d65f4 | balrog | GUS_irqrequest(state, state->gusirq, 1);
|
229 | 423d65f4 | balrog | } |
230 | 423d65f4 | balrog | } |
231 | 423d65f4 | balrog | break;
|
232 | 423d65f4 | balrog | case 0x20A: |
233 | 423d65f4 | balrog | GUSregb(AdLibStatus2x8) = (GUSbyte) data; |
234 | 423d65f4 | balrog | break; /* AdLibStatus2x8 */ |
235 | 423d65f4 | balrog | case 0x20B: /* GUS hidden registers */ |
236 | 423d65f4 | balrog | switch (GUSregb(RegCtrl_2xF) & 0x7) |
237 | 423d65f4 | balrog | { |
238 | 423d65f4 | balrog | case 0: |
239 | 423d65f4 | balrog | if (GUSregb(MixerCtrlReg2x0) & 0x40) |
240 | 423d65f4 | balrog | GUSregb(IRQ_2xB) = (GUSbyte) data; /* control register select bit */
|
241 | 423d65f4 | balrog | else
|
242 | 423d65f4 | balrog | GUSregb(DMA_2xB) = (GUSbyte) data; |
243 | 423d65f4 | balrog | break;
|
244 | 423d65f4 | balrog | /* case 1-4: general purpose emulation regs */
|
245 | 423d65f4 | balrog | case 5: /* clear stat reg 2xF */ |
246 | 423d65f4 | balrog | GUSregb(StatRead_2xF) = 0; /* ToDo: is this identical with GUS classic? */ |
247 | 423d65f4 | balrog | if (!GUSregb(IRQStatReg2x6))
|
248 | 423d65f4 | balrog | GUS_irqclear(state, state->gusirq); |
249 | 423d65f4 | balrog | break;
|
250 | 423d65f4 | balrog | case 6: /* Jumper reg (Joystick/MIDI enable) */ |
251 | 423d65f4 | balrog | GUSregb(Jumper_2xB) = (GUSbyte) data; |
252 | 423d65f4 | balrog | break;
|
253 | 423d65f4 | balrog | default:;
|
254 | 423d65f4 | balrog | } |
255 | 423d65f4 | balrog | break;
|
256 | 423d65f4 | balrog | case 0x20C: /* SB2xCd */ |
257 | 423d65f4 | balrog | if (GUSregb(GUS45TimerCtrl) & 0x20) |
258 | 423d65f4 | balrog | { |
259 | 423d65f4 | balrog | GUSregb(TimerStatus2x8) |= 0x10; /* SB IRQ enabled? -> set 2xCIRQ bit */ |
260 | 423d65f4 | balrog | GUSregb(IRQStatReg2x6) = 0x10;
|
261 | 423d65f4 | balrog | GUS_irqrequest(state, state->gusirq, 1);
|
262 | 423d65f4 | balrog | } |
263 | 423d65f4 | balrog | case 0x20D: /* SB2xCd no IRQ */ |
264 | 423d65f4 | balrog | GUSregb(SB2xCd) = (GUSbyte) data; |
265 | 423d65f4 | balrog | break;
|
266 | 423d65f4 | balrog | case 0x20E: /* SB2xE */ |
267 | 423d65f4 | balrog | GUSregb(SB2xE) = (GUSbyte) data; |
268 | 423d65f4 | balrog | break;
|
269 | 423d65f4 | balrog | case 0x20F: |
270 | 423d65f4 | balrog | GUSregb(RegCtrl_2xF) = (GUSbyte) data; |
271 | 423d65f4 | balrog | break; /* CtrlReg2xF */ |
272 | 423d65f4 | balrog | case 0x302: /* VoiceSelReg */ |
273 | 423d65f4 | balrog | GUSregb(VoiceSelReg3x2) = (GUSbyte) data; |
274 | 423d65f4 | balrog | break;
|
275 | 423d65f4 | balrog | case 0x303: /* FunkSelReg */ |
276 | 423d65f4 | balrog | GUSregb(FunkSelReg3x3) = (GUSbyte) data; |
277 | 423d65f4 | balrog | if ((GUSbyte) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */ |
278 | 423d65f4 | balrog | { |
279 | 423d65f4 | balrog | int voice;
|
280 | 423d65f4 | balrog | if (GUSregd(voicewavetableirq)) /* WavetableIRQ */ |
281 | 423d65f4 | balrog | { |
282 | 423d65f4 | balrog | for (voice = 0; voice < 31; voice++) |
283 | 423d65f4 | balrog | { |
284 | 423d65f4 | balrog | if (GUSregd(voicewavetableirq) & (1 << voice)) |
285 | 423d65f4 | balrog | { |
286 | 423d65f4 | balrog | GUSregd(voicewavetableirq) ^= (1 << voice); /* clear IRQ bit */ |
287 | 423d65f4 | balrog | GUSregb(voice << 5) &= 0x7f; /* clear voice reg irq bit */ |
288 | 423d65f4 | balrog | if (!GUSregd(voicewavetableirq))
|
289 | 423d65f4 | balrog | GUSregb(IRQStatReg2x6) &= 0xdf;
|
290 | 423d65f4 | balrog | if (!GUSregb(IRQStatReg2x6))
|
291 | 423d65f4 | balrog | GUS_irqclear(state, state->gusirq); |
292 | 423d65f4 | balrog | GUSregb(SynVoiceIRQ8f) = voice | 0x60; /* (bit==0 => IRQ wartend) */ |
293 | 423d65f4 | balrog | return;
|
294 | 423d65f4 | balrog | } |
295 | 423d65f4 | balrog | } |
296 | 423d65f4 | balrog | } |
297 | 423d65f4 | balrog | else if (GUSregd(voicevolrampirq)) /* VolRamp IRQ */ |
298 | 423d65f4 | balrog | { |
299 | 423d65f4 | balrog | for (voice = 0; voice < 31; voice++) |
300 | 423d65f4 | balrog | { |
301 | 423d65f4 | balrog | if (GUSregd(voicevolrampirq) & (1 << voice)) |
302 | 423d65f4 | balrog | { |
303 | 423d65f4 | balrog | GUSregd(voicevolrampirq) ^= (1 << voice); /* clear IRQ bit */ |
304 | 423d65f4 | balrog | GUSregb((voice << 5) + VSRVolRampControl) &= 0x7f; /* clear voice volume reg irq bit */ |
305 | 423d65f4 | balrog | if (!GUSregd(voicevolrampirq))
|
306 | 423d65f4 | balrog | GUSregb(IRQStatReg2x6) &= 0xbf;
|
307 | 423d65f4 | balrog | if (!GUSregb(IRQStatReg2x6))
|
308 | 423d65f4 | balrog | GUS_irqclear(state, state->gusirq); |
309 | 423d65f4 | balrog | GUSregb(SynVoiceIRQ8f) = voice | 0x80; /* (bit==0 => IRQ wartend) */ |
310 | 423d65f4 | balrog | return;
|
311 | 423d65f4 | balrog | } |
312 | 423d65f4 | balrog | } |
313 | 423d65f4 | balrog | } |
314 | 423d65f4 | balrog | GUSregb(SynVoiceIRQ8f) = 0xe8; /* kein IRQ wartet */ |
315 | 423d65f4 | balrog | } |
316 | 423d65f4 | balrog | break;
|
317 | 423d65f4 | balrog | case 0x304: |
318 | 423d65f4 | balrog | case 0x305: |
319 | 423d65f4 | balrog | { |
320 | 423d65f4 | balrog | GUSword writedata = (GUSword) data; |
321 | 423d65f4 | balrog | GUSword readmask = 0x0000;
|
322 | 423d65f4 | balrog | if (size == 1) |
323 | 423d65f4 | balrog | { |
324 | 423d65f4 | balrog | readmask = 0xff00;
|
325 | 423d65f4 | balrog | writedata &= 0xff;
|
326 | 423d65f4 | balrog | if ((port & 0xff0f) == 0x305) |
327 | 423d65f4 | balrog | { |
328 | 423d65f4 | balrog | writedata = (GUSword) (writedata << 8);
|
329 | 423d65f4 | balrog | readmask = 0x00ff;
|
330 | 423d65f4 | balrog | } |
331 | 423d65f4 | balrog | } |
332 | 423d65f4 | balrog | switch (GUSregb(FunkSelReg3x3))
|
333 | 423d65f4 | balrog | { |
334 | 423d65f4 | balrog | /* voice specific functions */
|
335 | 423d65f4 | balrog | case 0x00: |
336 | 423d65f4 | balrog | case 0x01: |
337 | 423d65f4 | balrog | case 0x02: |
338 | 423d65f4 | balrog | case 0x03: |
339 | 423d65f4 | balrog | case 0x04: |
340 | 423d65f4 | balrog | case 0x05: |
341 | 423d65f4 | balrog | case 0x06: |
342 | 423d65f4 | balrog | case 0x07: |
343 | 423d65f4 | balrog | case 0x08: |
344 | 423d65f4 | balrog | case 0x09: |
345 | 423d65f4 | balrog | case 0x0a: |
346 | 423d65f4 | balrog | case 0x0b: |
347 | 423d65f4 | balrog | case 0x0c: |
348 | 423d65f4 | balrog | case 0x0d: |
349 | 423d65f4 | balrog | { |
350 | 423d65f4 | balrog | int offset;
|
351 | 423d65f4 | balrog | if (!(GUSregb(GUS4cReset) & 0x01)) |
352 | 423d65f4 | balrog | break; /* reset flag active? */ |
353 | 423d65f4 | balrog | offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f); |
354 | 423d65f4 | balrog | offset += (GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Funktion*2 */ |
355 | 423d65f4 | balrog | GUSregw(offset) = (GUSword) ((GUSregw(offset) & readmask) | writedata); |
356 | 423d65f4 | balrog | } |
357 | 423d65f4 | balrog | break;
|
358 | 423d65f4 | balrog | /* voice unspecific functions */
|
359 | 423d65f4 | balrog | case 0x0e: /* NumVoices */ |
360 | 423d65f4 | balrog | GUSregb(NumVoices) = (GUSbyte) data; |
361 | 423d65f4 | balrog | break;
|
362 | 423d65f4 | balrog | /* case 0x0f: */ /* read only */ |
363 | 423d65f4 | balrog | /* common functions */
|
364 | 423d65f4 | balrog | case 0x41: /* DramDMAContrReg */ |
365 | 423d65f4 | balrog | GUSregb(GUS41DMACtrl) = (GUSbyte) data; |
366 | 423d65f4 | balrog | if (data & 0x01) |
367 | 423d65f4 | balrog | GUS_dmarequest(state); |
368 | 423d65f4 | balrog | break;
|
369 | 423d65f4 | balrog | case 0x42: /* DramDMAmemPosReg */ |
370 | 423d65f4 | balrog | GUSregw(GUS42DMAStart) = (GUSregw(GUS42DMAStart) & readmask) | writedata; |
371 | 423d65f4 | balrog | GUSregb(GUS50DMAHigh) &= 0xf; /* compatibility stuff... */ |
372 | 423d65f4 | balrog | break;
|
373 | 423d65f4 | balrog | case 0x43: /* DRAMaddrLo */ |
374 | 423d65f4 | balrog | GUSregd(GUSDRAMPOS24bit) = |
375 | 423d65f4 | balrog | (GUSregd(GUSDRAMPOS24bit) & (readmask | 0xff0000)) | writedata;
|
376 | 423d65f4 | balrog | break;
|
377 | 423d65f4 | balrog | case 0x44: /* DRAMaddrHi */ |
378 | 423d65f4 | balrog | GUSregd(GUSDRAMPOS24bit) = |
379 | 423d65f4 | balrog | (GUSregd(GUSDRAMPOS24bit) & 0xffff) | ((data & 0x0f) << 16); |
380 | 423d65f4 | balrog | break;
|
381 | 423d65f4 | balrog | case 0x45: /* TCtrlReg */ |
382 | 423d65f4 | balrog | GUSregb(GUS45TimerCtrl) = (GUSbyte) data; |
383 | 423d65f4 | balrog | if (!(data & 0x20)) |
384 | 423d65f4 | balrog | GUSregb(TimerStatus2x8) &= 0xe7; /* sb IRQ dis? -> clear 2x8/2xC sb IRQ flags */ |
385 | 423d65f4 | balrog | if (!(data & 0x02)) |
386 | 423d65f4 | balrog | GUSregb(TimerStatus2x8) &= 0xfe; /* adlib data IRQ dis? -> clear 2x8 adlib IRQ flag */ |
387 | 423d65f4 | balrog | if (!(GUSregb(TimerStatus2x8) & 0x19)) |
388 | 423d65f4 | balrog | GUSregb(IRQStatReg2x6) &= 0xef; /* 0xe6; $$clear IRQ if both IRQ bits are inactive or cleared */ |
389 | 423d65f4 | balrog | /* catch up delayed timer IRQs: */
|
390 | 423d65f4 | balrog | if ((GUSregw(TimerIRQs) > 1) && (GUSregb(TimerDataReg2x9) & 3)) |
391 | 423d65f4 | balrog | { |
392 | 423d65f4 | balrog | if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */ |
393 | 423d65f4 | balrog | { |
394 | 423d65f4 | balrog | if (!(GUSregb(TimerDataReg2x9) & 0x40)) |
395 | 423d65f4 | balrog | GUSregb(TimerStatus2x8) |= 0xc0; /* maskable bits */ |
396 | 423d65f4 | balrog | if (data & 4) /* timer1 irq enable */ |
397 | 423d65f4 | balrog | { |
398 | 423d65f4 | balrog | GUSregb(TimerStatus2x8) |= 4; /* nonmaskable bit */ |
399 | 423d65f4 | balrog | GUSregb(IRQStatReg2x6) |= 4; /* timer 1 irq pending */ |
400 | 423d65f4 | balrog | } |
401 | 423d65f4 | balrog | } |
402 | 423d65f4 | balrog | if (GUSregb(TimerDataReg2x9) & 2) /* start timer 2 (320us decrement rate) */ |
403 | 423d65f4 | balrog | { |
404 | 423d65f4 | balrog | if (!(GUSregb(TimerDataReg2x9) & 0x20)) |
405 | 423d65f4 | balrog | GUSregb(TimerStatus2x8) |= 0xa0; /* maskable bits */ |
406 | 423d65f4 | balrog | if (data & 8) /* timer2 irq enable */ |
407 | 423d65f4 | balrog | { |
408 | 423d65f4 | balrog | GUSregb(TimerStatus2x8) |= 2; /* nonmaskable bit */ |
409 | 423d65f4 | balrog | GUSregb(IRQStatReg2x6) |= 8; /* timer 2 irq pending */ |
410 | 423d65f4 | balrog | } |
411 | 423d65f4 | balrog | } |
412 | 423d65f4 | balrog | GUSregw(TimerIRQs)--; |
413 | 423d65f4 | balrog | if (GUSregw(BusyTimerIRQs) > 1) |
414 | 423d65f4 | balrog | GUSregw(BusyTimerIRQs)--; |
415 | 423d65f4 | balrog | else
|
416 | 423d65f4 | balrog | GUSregw(BusyTimerIRQs) = |
417 | 423d65f4 | balrog | GUS_irqrequest(state, state->gusirq, GUSregw(TimerIRQs)); |
418 | 423d65f4 | balrog | } |
419 | 423d65f4 | balrog | else
|
420 | 423d65f4 | balrog | GUSregw(TimerIRQs) = 0;
|
421 | 423d65f4 | balrog | |
422 | 423d65f4 | balrog | if (!(data & 0x04)) |
423 | 423d65f4 | balrog | { |
424 | 423d65f4 | balrog | GUSregb(TimerStatus2x8) &= 0xfb; /* clear non-maskable timer1 bit */ |
425 | 423d65f4 | balrog | GUSregb(IRQStatReg2x6) &= 0xfb;
|
426 | 423d65f4 | balrog | } |
427 | 423d65f4 | balrog | if (!(data & 0x08)) |
428 | 423d65f4 | balrog | { |
429 | 423d65f4 | balrog | GUSregb(TimerStatus2x8) &= 0xfd; /* clear non-maskable timer2 bit */ |
430 | 423d65f4 | balrog | GUSregb(IRQStatReg2x6) &= 0xf7;
|
431 | 423d65f4 | balrog | } |
432 | 423d65f4 | balrog | if (!GUSregb(IRQStatReg2x6))
|
433 | 423d65f4 | balrog | GUS_irqclear(state, state->gusirq); |
434 | 423d65f4 | balrog | break;
|
435 | 423d65f4 | balrog | case 0x46: /* Counter1 */ |
436 | 423d65f4 | balrog | GUSregb(GUS46Counter1) = (GUSbyte) data; |
437 | 423d65f4 | balrog | break;
|
438 | 423d65f4 | balrog | case 0x47: /* Counter2 */ |
439 | 423d65f4 | balrog | GUSregb(GUS47Counter2) = (GUSbyte) data; |
440 | 423d65f4 | balrog | break;
|
441 | 423d65f4 | balrog | /* case 0x48: */ /* sampling freq reg not emulated (same as interwave) */ |
442 | 423d65f4 | balrog | case 0x49: /* SampCtrlReg */ |
443 | 423d65f4 | balrog | GUSregb(GUS49SampCtrl) = (GUSbyte) data; |
444 | 423d65f4 | balrog | break;
|
445 | 423d65f4 | balrog | /* case 0x4b: */ /* joystick trim not emulated */ |
446 | 423d65f4 | balrog | case 0x4c: /* GUSreset */ |
447 | 423d65f4 | balrog | GUSregb(GUS4cReset) = (GUSbyte) data; |
448 | 423d65f4 | balrog | if (!(GUSregb(GUS4cReset) & 1)) /* reset... */ |
449 | 423d65f4 | balrog | { |
450 | 423d65f4 | balrog | GUSregd(voicewavetableirq) = 0;
|
451 | 423d65f4 | balrog | GUSregd(voicevolrampirq) = 0;
|
452 | 423d65f4 | balrog | GUSregw(TimerIRQs) = 0;
|
453 | 423d65f4 | balrog | GUSregw(BusyTimerIRQs) = 0;
|
454 | 423d65f4 | balrog | GUSregb(NumVoices) = 0xcd;
|
455 | 423d65f4 | balrog | GUSregb(IRQStatReg2x6) = 0;
|
456 | 423d65f4 | balrog | GUSregb(TimerStatus2x8) = 0;
|
457 | 423d65f4 | balrog | GUSregb(AdLibData2x9) = 0;
|
458 | 423d65f4 | balrog | GUSregb(TimerDataReg2x9) = 0;
|
459 | 423d65f4 | balrog | GUSregb(GUS41DMACtrl) = 0;
|
460 | 423d65f4 | balrog | GUSregb(GUS45TimerCtrl) = 0;
|
461 | 423d65f4 | balrog | GUSregb(GUS49SampCtrl) = 0;
|
462 | 423d65f4 | balrog | GUSregb(GUS4cReset) &= 0xf9; /* clear IRQ and DAC enable bits */ |
463 | 423d65f4 | balrog | GUS_irqclear(state, state->gusirq); |
464 | 423d65f4 | balrog | } |
465 | 423d65f4 | balrog | /* IRQ enable bit checked elsewhere */
|
466 | 423d65f4 | balrog | /* EnableDAC bit may be used by external callers */
|
467 | 423d65f4 | balrog | break;
|
468 | 423d65f4 | balrog | } |
469 | 423d65f4 | balrog | } |
470 | 423d65f4 | balrog | break;
|
471 | 423d65f4 | balrog | case 0x307: /* DRAMaccess */ |
472 | 423d65f4 | balrog | { |
473 | 423d65f4 | balrog | GUSbyte *adr; |
474 | 423d65f4 | balrog | adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
|
475 | 423d65f4 | balrog | *adr = (GUSbyte) data; |
476 | 423d65f4 | balrog | } |
477 | 423d65f4 | balrog | break;
|
478 | 423d65f4 | balrog | } |
479 | 423d65f4 | balrog | } |
480 | 423d65f4 | balrog | |
481 | 423d65f4 | balrog | /* Attention when breaking up a single DMA transfer to multiple ones:
|
482 | 423d65f4 | balrog | * it may lead to multiple terminal count interrupts and broken transfers:
|
483 | 423d65f4 | balrog | *
|
484 | 423d65f4 | balrog | * 1. Whenever you transfer a piece of data, the gusemu callback is invoked
|
485 | 423d65f4 | balrog | * 2. The callback may generate a TC irq (if the register was set up to do so)
|
486 | 423d65f4 | balrog | * 3. The irq may result in the program using the GUS to reprogram the GUS
|
487 | 423d65f4 | balrog | *
|
488 | 423d65f4 | balrog | * Some programs also decide to upload by just checking if TC occurs
|
489 | 423d65f4 | balrog | * (via interrupt or a cleared GUS dma flag)
|
490 | 423d65f4 | balrog | * and then start the next transfer, without checking DMA state
|
491 | 423d65f4 | balrog | *
|
492 | 423d65f4 | balrog | * Thus: Always make sure to set the TC flag correctly!
|
493 | 423d65f4 | balrog | *
|
494 | 423d65f4 | balrog | * Note that the genuine GUS had a granularity of 16 bytes/words for low/high DMA
|
495 | 423d65f4 | balrog | * while later cards had atomic granularity provided by an additional GUS50DMAHigh register
|
496 | 423d65f4 | balrog | * GUSemu also uses this register to support byte-granular transfers for better compatibility
|
497 | 423d65f4 | balrog | * with emulators other than GUSemu32
|
498 | 423d65f4 | balrog | */
|
499 | 423d65f4 | balrog | |
500 | 423d65f4 | balrog | void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int count, int TC) |
501 | 423d65f4 | balrog | { |
502 | 423d65f4 | balrog | /* this function gets called by the callback function as soon as a DMA transfer is about to start
|
503 | 423d65f4 | balrog | * dma_addr is a translated address within accessible memory, not the physical one,
|
504 | 423d65f4 | balrog | * count is (real dma count register)+1
|
505 | 423d65f4 | balrog | * note that the amount of bytes transfered is fully determined by values in the DMA registers
|
506 | 423d65f4 | balrog | * do not forget to update DMA states after transferring the entire block:
|
507 | 423d65f4 | balrog | * DREQ cleared & TC asserted after the _whole_ transfer */
|
508 | 423d65f4 | balrog | |
509 | 423d65f4 | balrog | char *srcaddr;
|
510 | 423d65f4 | balrog | char *destaddr;
|
511 | 423d65f4 | balrog | char msbmask = 0; |
512 | 423d65f4 | balrog | GUSbyte *gusptr; |
513 | 423d65f4 | balrog | gusptr = state->gusdatapos; |
514 | 423d65f4 | balrog | |
515 | 423d65f4 | balrog | srcaddr = dma_addr; /* system memory address */
|
516 | 423d65f4 | balrog | { |
517 | 423d65f4 | balrog | int offset = (GUSregw(GUS42DMAStart) << 4) + (GUSregb(GUS50DMAHigh) & 0xf); |
518 | 423d65f4 | balrog | if (state->gusdma >= 4) |
519 | 423d65f4 | balrog | offset = (offset & 0xc0000) + (2 * (offset & 0x1fff0)); /* 16 bit address translation */ |
520 | 423d65f4 | balrog | destaddr = (char *) state->himemaddr + offset; /* wavetable RAM adress */ |
521 | 423d65f4 | balrog | } |
522 | 423d65f4 | balrog | |
523 | 423d65f4 | balrog | GUSregw(GUS42DMAStart) += (GUSword) (count >> 4); /* ToDo: add 16bit GUS page limit? */ |
524 | 423d65f4 | balrog | GUSregb(GUS50DMAHigh) = (GUSbyte) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */ |
525 | 423d65f4 | balrog | |
526 | 423d65f4 | balrog | if (GUSregb(GUS41DMACtrl) & 0x02) /* direction, 0 := sysram->gusram */ |
527 | 423d65f4 | balrog | { |
528 | 423d65f4 | balrog | char *tmpaddr = destaddr;
|
529 | 423d65f4 | balrog | destaddr = srcaddr; |
530 | 423d65f4 | balrog | srcaddr = tmpaddr; |
531 | 423d65f4 | balrog | } |
532 | 423d65f4 | balrog | |
533 | 423d65f4 | balrog | if ((GUSregb(GUS41DMACtrl) & 0x80) && (!(GUSregb(GUS41DMACtrl) & 0x02))) |
534 | 423d65f4 | balrog | msbmask = (const char) 0x80; /* invert MSB */ |
535 | 423d65f4 | balrog | for (; count > 0; count--) |
536 | 423d65f4 | balrog | { |
537 | 423d65f4 | balrog | if (GUSregb(GUS41DMACtrl) & 0x40) |
538 | 423d65f4 | balrog | *(destaddr++) = *(srcaddr++); /* 16 bit lobyte */
|
539 | 423d65f4 | balrog | else
|
540 | 423d65f4 | balrog | *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 8 bit */
|
541 | 423d65f4 | balrog | if (state->gusdma >= 4) |
542 | 423d65f4 | balrog | *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 16 bit hibyte */
|
543 | 423d65f4 | balrog | } |
544 | 423d65f4 | balrog | |
545 | 423d65f4 | balrog | if (TC)
|
546 | 423d65f4 | balrog | { |
547 | 423d65f4 | balrog | (GUSregb(GUS41DMACtrl)) &= 0xfe; /* clear DMA request bit */ |
548 | 423d65f4 | balrog | if (GUSregb(GUS41DMACtrl) & 0x20) /* DMA terminal count IRQ */ |
549 | 423d65f4 | balrog | { |
550 | 423d65f4 | balrog | GUSregb(IRQStatReg2x6) |= 0x80;
|
551 | 423d65f4 | balrog | GUS_irqrequest(state, state->gusirq, 1);
|
552 | 423d65f4 | balrog | } |
553 | 423d65f4 | balrog | } |
554 | 423d65f4 | balrog | } |