/[gxemul]/upstream/0.3.1/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.1/devices/dev_ps2_stuff.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (show annotations)
Mon Oct 8 16:17:52 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 9211 byte(s)
0.3.1
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.18 2005/02/26 10:51:01 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 16
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
63 /* Count-up Enable: TODO: by how much? */
64 if (d->timer_mode[0] & T_MODE_CUE)
65 d->timer_count[0] ++;
66
67 /* TODO: right now this interrupts every now and then, this should
68 be 100 Hz in NetBSD, but isn't */
69 if (d->timer_mode[0] & (T_MODE_CMPE | T_MODE_OVFE)) {
70 /* Zero return: */
71 if (d->timer_mode[0] & T_MODE_ZRET)
72 d->timer_count[0] = 0;
73
74 cpu_interrupt(cpu, 0x200 +8); /* 0x200 is timer0 */
75 }
76 }
77
78
79 /*
80 * dev_ps2_stuff_access():
81 */
82 int dev_ps2_stuff_access(struct cpu *cpu, struct memory *mem,
83 uint64_t relative_addr, unsigned char *data, size_t len,
84 int writeflag, void *extra)
85 {
86 uint64_t idata = 0, odata = 0;
87 int regnr = 0;
88 struct ps2_data *d = extra;
89 int timer_nr = 0;
90
91 idata = memory_readmax64(cpu, data, len);
92
93 if (relative_addr >= 0x8000 && relative_addr < 0x8000 + DMAC_REGSIZE) {
94 regnr = (relative_addr - 0x8000) / 16;
95 if (writeflag == MEM_READ)
96 odata = d->dmac_reg[regnr];
97 else
98 d->dmac_reg[regnr] = idata;
99 }
100
101 /*
102 * Timer control:
103 * The four timers are at offsets 0, 0x800, 0x1000, and 0x1800.
104 */
105 if (relative_addr < TIMER_REGSIZE) {
106 /* 0, 1, 2, or 3 */
107 timer_nr = (relative_addr & 0x1800) >> 11;
108 relative_addr &= (TIMER_OFS-1);
109 }
110
111 switch (relative_addr) {
112 case 0x0000: /* timer count */
113 if (writeflag == MEM_READ) {
114 odata = d->timer_count[timer_nr];
115 if (timer_nr == 0) {
116 /* :-) TODO: remove this? */
117 d->timer_count[timer_nr] ++;
118 }
119 debug("[ ps2_stuff: read timer %i count: 0x%llx ]\n",
120 timer_nr, (long long)odata);
121 } else {
122 d->timer_count[timer_nr] = idata;
123 debug("[ ps2_stuff: write timer %i count: 0x%llx ]\n",
124 timer_nr, (long long)idata);
125 }
126 break;
127 case 0x0010: /* timer mode */
128 if (writeflag == MEM_READ) {
129 odata = d->timer_mode[timer_nr];
130 debug("[ ps2_stuff: read timer %i mode: 0x%llx ]\n",
131 timer_nr, (long long)odata);
132 } else {
133 d->timer_mode[timer_nr] = idata;
134 debug("[ ps2_stuff: write timer %i mode: 0x%llx ]\n",
135 timer_nr, (long long)idata);
136 }
137 break;
138 case 0x0020: /* timer comp */
139 if (writeflag == MEM_READ) {
140 odata = d->timer_comp[timer_nr];
141 debug("[ ps2_stuff: read timer %i comp: 0x%llx ]\n",
142 timer_nr, (long long)odata);
143 } else {
144 d->timer_comp[timer_nr] = idata;
145 debug("[ ps2_stuff: write timer %i comp: 0x%llx ]\n",
146 timer_nr, (long long)idata);
147 }
148 break;
149 case 0x0030: /* timer hold */
150 if (writeflag == MEM_READ) {
151 odata = d->timer_hold[timer_nr];
152 debug("[ ps2_stuff: read timer %i hold: 0x%llx ]\n",
153 timer_nr, (long long)odata);
154 if (timer_nr >= 2)
155 fatal("[ WARNING: ps2_stuff: read from non-"
156 "existant timer %i hold register ]\n");
157 } else {
158 d->timer_hold[timer_nr] = idata;
159 debug("[ ps2_stuff: write timer %i hold: 0x%llx ]\n",
160 timer_nr, (long long)idata);
161 if (timer_nr >= 2)
162 fatal("[ WARNING: ps2_stuff: write to "
163 "non-existant timer %i hold register ]\n",
164 timer_nr);
165 }
166 break;
167
168 case 0x8000 + D2_CHCR_REG:
169 if (writeflag==MEM_READ) {
170 odata = d->dmac_reg[regnr];
171 /* debug("[ ps2_stuff: dmac read from D2_CHCR "
172 "(0x%llx) ]\n", (long long)d->dmac_reg[regnr]); */
173 } else {
174 /* debug("[ ps2_stuff: dmac write to D2_CHCR, "
175 "data 0x%016llx ]\n", (long long) idata); */
176 if (idata & D_CHCR_STR) {
177 int length = d->dmac_reg[D2_QWC_REG/0x10] * 16;
178 uint64_t from_addr = d->dmac_reg[
179 D2_MADR_REG/0x10];
180 uint64_t to_addr = d->dmac_reg[
181 D2_TADR_REG/0x10];
182 unsigned char *copy_buf;
183
184 debug("[ ps2_stuff: dmac [ch2] transfer addr="
185 "0x%016llx len=0x%lx ]\n", (long long)
186 d->dmac_reg[D2_MADR_REG/0x10],
187 (long)length);
188
189 copy_buf = malloc(length);
190 if (copy_buf == NULL) {
191 fprintf(stderr, "out of memory in "
192 "dev_ps2_stuff_access()\n");
193 exit(1);
194 }
195 cpu->memory_rw(cpu, cpu->mem, from_addr,
196 copy_buf, length, MEM_READ,
197 CACHE_NONE | PHYSICAL);
198 cpu->memory_rw(cpu, cpu->mem,
199 d->other_memory_base[DMA_CH_GIF] + to_addr,
200 copy_buf, length, MEM_WRITE,
201 CACHE_NONE | PHYSICAL);
202 free(copy_buf);
203
204 /* Done with the transfer: */
205 d->dmac_reg[D2_QWC_REG/0x10] = 0;
206 idata &= ~D_CHCR_STR;
207
208 cpu_interrupt(cpu, (1 << 18) +8);
209 /* 1<<18 is dma2 */
210 } else
211 debug("[ ps2_stuff: dmac [ch2] stopping "
212 "transfer ]\n");
213 d->dmac_reg[regnr] = idata;
214 return 1;
215 }
216 break;
217
218 case 0x8000 + D2_QWC_REG:
219 case 0x8000 + D2_MADR_REG:
220 case 0x8000 + D2_TADR_REG:
221 /* no debug output */
222 break;
223
224 case 0xe010: /* dmac interrupt status (and mask, */
225 /* the upper 16 bits) */
226 if (writeflag == MEM_WRITE) {
227 uint32_t oldmask = d->dmac_reg[regnr] & 0xffff0000;
228 /* Clear out those bits that are set in idata: */
229 d->dmac_reg[regnr] &= ~idata;
230 d->dmac_reg[regnr] &= 0xffff;
231 d->dmac_reg[regnr] |= oldmask;
232 if (((d->dmac_reg[regnr] & 0xffff) &
233 ((d->dmac_reg[regnr]>>16) & 0xffff)) == 0) {
234 /* irq 3 is the DMAC */
235 cpu_interrupt_ack(cpu, 3);
236 }
237 } else {
238 /* Hm... make it seem like the mask bits are (at
239 least as much as) the interrupt assertions: */
240 odata = d->dmac_reg[regnr];
241 odata |= (odata << 16);
242 }
243 break;
244
245 case 0xf000: /* interrupt register */
246 if (writeflag == MEM_READ) {
247 odata = d->intr;
248 debug("[ ps2_stuff: read from Interrupt Register:"
249 " 0x%llx ]\n", (long long)odata);
250
251 /* TODO: these are possibly not correct,
252 but makes NetBSD run easier. */
253 d->intr = 0;
254 cpu_interrupt_ack(cpu, 2);
255 } else {
256 debug("[ ps2_stuff: write to Interrupt Register: "
257 "0x%llx ]\n", (long long)idata);
258 /* Clear out those bits that are set in idata: */
259 d->intr &= ~idata;
260 if (idata == 0)
261 d->intr = 0;
262 /* TODO: which of the above and below is best? */
263 if (d->intr == 0) {
264 /* Hm... idata +8); */
265 cpu_interrupt_ack(cpu, 2);
266 }
267 }
268 break;
269
270 case 0xf010: /* interrupt mask */
271 if (writeflag == MEM_READ)
272 odata = d->imask;
273 else {
274 d->imask = idata;
275 }
276 break;
277
278 default:
279 if (writeflag==MEM_READ) {
280 debug("[ ps2_stuff: read from addr 0x%x: 0x%llx ]\n",
281 (int)relative_addr, (long long)odata);
282 } else {
283 debug("[ ps2_stuff: write to addr 0x%x: 0x%llx ]\n",
284 (int)relative_addr, (long long)idata);
285 }
286 }
287
288 if (writeflag == MEM_READ)
289 memory_writemax64(cpu, data, len, odata);
290
291 return 1;
292 }
293
294
295 /*
296 * dev_ps2_stuff_init():
297 */
298 struct ps2_data *dev_ps2_stuff_init(struct machine *machine,
299 struct memory *mem, uint64_t baseaddr)
300 {
301 struct ps2_data *d;
302
303 d = malloc(sizeof(struct ps2_data));
304 if (d == NULL) {
305 fprintf(stderr, "out of memory\n");
306 exit(1);
307 }
308 memset(d, 0, sizeof(struct ps2_data));
309
310 d->other_memory_base[DMA_CH_GIF] = DEV_PS2_GIF_FAKE_BASE;
311
312 memory_device_register(mem, "ps2_stuff", baseaddr,
313 DEV_PS2_STUFF_LENGTH, dev_ps2_stuff_access, d, MEM_DEFAULT, NULL);
314 machine_add_tickfunction(machine,
315 dev_ps2_stuff_tick, d, TICK_STEPS_SHIFT);
316
317 return d;
318 }
319

  ViewVC Help
Powered by ViewVC 1.1.26