/[gxemul]/upstream/0.3.6/src/devices/dev_ps2_stuff.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/0.3.6/src/devices/dev_ps2_stuff.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (show annotations)
Mon Oct 8 16:18:56 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 9914 byte(s)
0.3.6
1 /*
2 * Copyright (C) 2003-2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: dev_ps2_stuff.c,v 1.23 2005/04/11 22:55:42 debug Exp $
29 *
30 * Playstation 2 misc. stuff:
31 *
32 * offset 0x0000 timer control
33 * offset 0x8000 DMA controller
34 * offset 0xf000 Interrupt register
35 */
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include "cpu.h"
42 #include "devices.h"
43 #include "machine.h"
44 #include "memory.h"
45 #include "misc.h"
46
47 #include "ee_timerreg.h"
48 #include "ps2_dmacreg.h"
49
50 #define TICK_STEPS_SHIFT 14
51
52 /* NOTE/TODO: This should be the same as in ps2_gs: */
53 #define DEV_PS2_GIF_FAKE_BASE 0x50000000
54
55
56 /*
57 * dev_ps2_stuff_tick():
58 */
59 void dev_ps2_stuff_tick(struct cpu *cpu, void *extra)
60 {
61 struct ps2_data *d = extra;
62 int i;
63
64 /*
65 * Right now this interrupts every now and then.
66 * The main interrupt in NetBSD should be 100 Hz. TODO.
67 */
68 for (i=0; i<N_PS2_TIMERS; i++) {
69 /* Count-up Enable: TODO: by how much? */
70 if (d->timer_mode[i] & T_MODE_CUE)
71 d->timer_count[i] ++;
72
73 if (d->timer_mode[i] & (T_MODE_CMPE | T_MODE_OVFE)) {
74 /* Zero return: */
75 if (d->timer_mode[i] & T_MODE_ZRET)
76 d->timer_count[i] = 0;
77
78 /* irq 9 is timer0, etc. */
79 cpu_interrupt(cpu, 8 + 9 + i);
80
81 /* timer 1..3 are "single-shot"? TODO */
82 if (i > 0)
83 d->timer_mode[i] &= ~(T_MODE_CMPE | T_MODE_OVFF);
84 }
85 }
86 }
87
88
89 /*
90 * dev_ps2_stuff_access():
91 */
92 int dev_ps2_stuff_access(struct cpu *cpu, struct memory *mem,
93 uint64_t relative_addr, unsigned char *data, size_t len,
94 int writeflag, void *extra)
95 {
96 uint64_t idata = 0, odata = 0;
97 int regnr = 0;
98 struct ps2_data *d = extra;
99 int timer_nr = 0;
100
101 idata = memory_readmax64(cpu, data, len);
102
103 if (relative_addr >= 0x8000 && relative_addr < 0x8000 + DMAC_REGSIZE) {
104 regnr = (relative_addr - 0x8000) / 16;
105 if (writeflag == MEM_READ)
106 odata = d->dmac_reg[regnr];
107 else
108 d->dmac_reg[regnr] = idata;
109 }
110
111 /*
112 * Timer control:
113 * The four timers are at offsets 0, 0x800, 0x1000, and 0x1800.
114 */
115 if (relative_addr < TIMER_REGSIZE) {
116 /* 0, 1, 2, or 3 */
117 timer_nr = (relative_addr & 0x1800) >> 11;
118 relative_addr &= (TIMER_OFS-1);
119 }
120
121 switch (relative_addr) {
122 case 0x0000: /* timer count */
123 if (writeflag == MEM_READ) {
124 odata = d->timer_count[timer_nr];
125 if (timer_nr == 0) {
126 /* :-) TODO: remove this? */
127 d->timer_count[timer_nr] ++;
128 }
129 debug("[ ps2_stuff: read timer %i count: 0x%llx ]\n",
130 timer_nr, (long long)odata);
131 } else {
132 d->timer_count[timer_nr] = idata;
133 debug("[ ps2_stuff: write timer %i count: 0x%llx ]\n",
134 timer_nr, (long long)idata);
135 }
136 break;
137 case 0x0010: /* timer mode */
138 if (writeflag == MEM_READ) {
139 odata = d->timer_mode[timer_nr];
140 debug("[ ps2_stuff: read timer %i mode: 0x%llx ]\n",
141 timer_nr, (long long)odata);
142 } else {
143 d->timer_mode[timer_nr] = idata;
144 debug("[ ps2_stuff: write timer %i mode: 0x%llx ]\n",
145 timer_nr, (long long)idata);
146 }
147 break;
148 case 0x0020: /* timer comp */
149 if (writeflag == MEM_READ) {
150 odata = d->timer_comp[timer_nr];
151 debug("[ ps2_stuff: read timer %i comp: 0x%llx ]\n",
152 timer_nr, (long long)odata);
153 } else {
154 d->timer_comp[timer_nr] = idata;
155 debug("[ ps2_stuff: write timer %i comp: 0x%llx ]\n",
156 timer_nr, (long long)idata);
157 }
158 break;
159 case 0x0030: /* timer hold */
160 if (writeflag == MEM_READ) {
161 odata = d->timer_hold[timer_nr];
162 debug("[ ps2_stuff: read timer %i hold: 0x%llx ]\n",
163 timer_nr, (long long)odata);
164 if (timer_nr >= 2)
165 fatal("[ WARNING: ps2_stuff: read from non-"
166 "existant timer %i hold register ]\n");
167 } else {
168 d->timer_hold[timer_nr] = idata;
169 debug("[ ps2_stuff: write timer %i hold: 0x%llx ]\n",
170 timer_nr, (long long)idata);
171 if (timer_nr >= 2)
172 fatal("[ WARNING: ps2_stuff: write to "
173 "non-existant timer %i hold register ]\n",
174 timer_nr);
175 }
176 break;
177
178 case 0x8000 + D2_CHCR_REG:
179 if (writeflag==MEM_READ) {
180 odata = d->dmac_reg[regnr];
181 /* debug("[ ps2_stuff: dmac read from D2_CHCR "
182 "(0x%llx) ]\n", (long long)d->dmac_reg[regnr]); */
183 } else {
184 /* debug("[ ps2_stuff: dmac write to D2_CHCR, "
185 "data 0x%016llx ]\n", (long long) idata); */
186 if (idata & D_CHCR_STR) {
187 int length = d->dmac_reg[D2_QWC_REG/0x10] * 16;
188 uint64_t from_addr = d->dmac_reg[
189 D2_MADR_REG/0x10];
190 uint64_t to_addr = d->dmac_reg[
191 D2_TADR_REG/0x10];
192 unsigned char *copy_buf;
193
194 debug("[ ps2_stuff: dmac [ch2] transfer addr="
195 "0x%016llx len=0x%lx ]\n", (long long)
196 d->dmac_reg[D2_MADR_REG/0x10],
197 (long)length);
198
199 copy_buf = malloc(length);
200 if (copy_buf == NULL) {
201 fprintf(stderr, "out of memory in "
202 "dev_ps2_stuff_access()\n");
203 exit(1);
204 }
205 cpu->memory_rw(cpu, cpu->mem, from_addr,
206 copy_buf, length, MEM_READ,
207 CACHE_NONE | PHYSICAL);
208 cpu->memory_rw(cpu, cpu->mem,
209 d->other_memory_base[DMA_CH_GIF] + to_addr,
210 copy_buf, length, MEM_WRITE,
211 CACHE_NONE | PHYSICAL);
212 free(copy_buf);
213
214 /* Done with the transfer: */
215 d->dmac_reg[D2_QWC_REG/0x10] = 0;
216 idata &= ~D_CHCR_STR;
217
218 /* interrupt DMA channel 2 */
219 cpu_interrupt(cpu, 8 + 16 + 2);
220 } else
221 debug("[ ps2_stuff: dmac [ch2] stopping "
222 "transfer ]\n");
223 d->dmac_reg[regnr] = idata;
224 return 1;
225 }
226 break;
227
228 case 0x8000 + D2_QWC_REG:
229 case 0x8000 + D2_MADR_REG:
230 case 0x8000 + D2_TADR_REG:
231 /* no debug output */
232 break;
233
234 case 0xe010: /* dmac interrupt status (and mask, */
235 /* the upper 16 bits) */
236 if (writeflag == MEM_WRITE) {
237 uint32_t oldmask = d->dmac_reg[regnr] & 0xffff0000;
238 /* Clear out those bits that are set in idata: */
239 d->dmac_reg[regnr] &= ~idata;
240 d->dmac_reg[regnr] &= 0xffff;
241 d->dmac_reg[regnr] |= oldmask;
242 if (((d->dmac_reg[regnr] & 0xffff) &
243 ((d->dmac_reg[regnr]>>16) & 0xffff)) == 0) {
244 /* irq 3 is the DMAC */
245 cpu_interrupt_ack(cpu, 3);
246 }
247 } else {
248 /* Hm... make it seem like the mask bits are (at
249 least as much as) the interrupt assertions: */
250 odata = d->dmac_reg[regnr];
251 odata |= (odata << 16);
252 }
253 break;
254
255 case 0xf000: /* interrupt register */
256 if (writeflag == MEM_READ) {
257 odata = d->intr;
258 debug("[ ps2_stuff: read from Interrupt Register:"
259 " 0x%llx ]\n", (long long)odata);
260
261 /* TODO: This is _NOT_ correct behavior: */
262 d->intr = 0;
263 cpu_interrupt_ack(cpu, 2);
264 } else {
265 debug("[ ps2_stuff: write to Interrupt Register: "
266 "0x%llx ]\n", (long long)idata);
267 /* Clear out bits that are set in idata: */
268 d->intr &= ~idata;
269
270 if ((d->intr & d->imask) == 0)
271 cpu_interrupt_ack(cpu, 2);
272 }
273 break;
274
275 case 0xf010: /* interrupt mask */
276 if (writeflag == MEM_READ) {
277 odata = d->imask;
278 /* debug("[ ps2_stuff: read from Interrupt Mask "
279 "Register: 0x%llx ]\n", (long long)odata); */
280 } else {
281 /* debug("[ ps2_stuff: write to Interrupt Mask "
282 "Register: 0x%llx ]\n", (long long)idata); */
283 d->imask = idata;
284 }
285 break;
286
287 case 0xf230: /* sbus interrupt register? */
288 if (writeflag == MEM_READ) {
289 odata = d->sbus_smflg;
290 debug("[ ps2_stuff: read from SBUS SMFLG:"
291 " 0x%llx ]\n", (long long)odata);
292 } else {
293 /* Clear bits on write: */
294 debug("[ ps2_stuff: write to SBUS SMFLG:"
295 " 0x%llx ]\n", (long long)idata);
296 d->sbus_smflg &= ~idata;
297 /* irq 1 is SBUS */
298 if (d->sbus_smflg == 0)
299 cpu_interrupt_ack(cpu, 8 + 1);
300 }
301 break;
302 default:
303 if (writeflag==MEM_READ) {
304 debug("[ ps2_stuff: read from addr 0x%x: 0x%llx ]\n",
305 (int)relative_addr, (long long)odata);
306 } else {
307 debug("[ ps2_stuff: write to addr 0x%x: 0x%llx ]\n",
308 (int)relative_addr, (long long)idata);
309 }
310 }
311
312 if (writeflag == MEM_READ)
313 memory_writemax64(cpu, data, len, odata);
314
315 return 1;
316 }
317
318
319 /*
320 * dev_ps2_stuff_init():
321 */
322 struct ps2_data *dev_ps2_stuff_init(struct machine *machine,
323 struct memory *mem, uint64_t baseaddr)
324 {
325 struct ps2_data *d;
326
327 d = malloc(sizeof(struct ps2_data));
328 if (d == NULL) {
329 fprintf(stderr, "out of memory\n");
330 exit(1);
331 }
332 memset(d, 0, sizeof(struct ps2_data));
333
334 d->other_memory_base[DMA_CH_GIF] = DEV_PS2_GIF_FAKE_BASE;
335
336 memory_device_register(mem, "ps2_stuff", baseaddr,
337 DEV_PS2_STUFF_LENGTH, dev_ps2_stuff_access, d, MEM_DEFAULT, NULL);
338 machine_add_tickfunction(machine,
339 dev_ps2_stuff_tick, d, TICK_STEPS_SHIFT);
340
341 return d;
342 }
343

  ViewVC Help
Powered by ViewVC 1.1.26