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

Annotation of /upstream/0.3.1/devices/dev_ps2_stuff.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (hide annotations)
Mon Oct 8 16:17:52 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 9211 byte(s)
0.3.1
1 dpavlin 2 /*
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