/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (hide 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 dpavlin 4 /*
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