/[gxemul]/trunk/src/devices/dev_wdsc.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 /trunk/src/devices/dev_wdsc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 18 - (hide annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 10141 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

==============  RELEASE 0.3.6.2  ==============


1 dpavlin 4 /*
2     * Copyright (C) 2004-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 dpavlin 18 * $Id: dev_wdsc.c,v 1.27 2005/10/26 14:37:05 debug Exp $
29 dpavlin 4 *
30     * WDSC SCSI (WD33C93) controller.
31     * (For SGI-IP22. See sys/arch/sgimips/hpc/sbic* in NetBSD for details.)
32     *
33     * TODO: This device doesn't do much yet.
34     */
35    
36     #include <stdio.h>
37     #include <stdlib.h>
38     #include <string.h>
39    
40     #include "cpu.h"
41     #include "devices.h"
42     #include "diskimage.h"
43     #include "machine.h"
44     #include "memory.h"
45     #include "misc.h"
46    
47     #include "wdsc_sbicreg.h"
48    
49    
50     struct wdsc_data {
51     int irq_nr;
52     int controller_nr;
53    
54     int register_select;
55     unsigned char reg[DEV_WDSC_NREGS];
56    
57     int irq_pending;
58    
59     int buf_allocatedlen;
60     int buf_curptr;
61     unsigned char *buf;
62    
63     int current_phase;
64    
65     struct scsi_transfer *xfer;
66     };
67    
68    
69     /*
70     * dev_wdsc_tick():
71     */
72     void dev_wdsc_tick(struct cpu *cpu, void *extra)
73     {
74     struct wdsc_data *d = extra;
75    
76     if (d->irq_pending)
77     cpu_interrupt(cpu, d->irq_nr);
78     else
79     cpu_interrupt_ack(cpu, d->irq_nr);
80     }
81    
82    
83     /*
84     * dev_wdsc_regwrite():
85     *
86     * Handle writes to WDSC registers.
87     */
88     static void dev_wdsc_regwrite(struct cpu *cpu, struct wdsc_data *d, int idata)
89     {
90     d->reg[d->register_select] = idata & 0xff;
91    
92     debug("[ wdsc: write to register %i", d->register_select);
93    
94     switch (d->register_select) {
95    
96     case SBIC_myid:
97     debug(" (myid): 0x%02x => ", (int)idata);
98     if (idata & SBIC_ID_FS_16_20)
99     debug("16-20MHz, ");
100     if (idata & SBIC_ID_FS_12_15)
101     debug("12-15MHz, ");
102     if (idata & SBIC_ID_RAF)
103     debug("RAF(?), ");
104     if (idata & SBIC_ID_EHP)
105     debug("Parity, ");
106     if (idata & SBIC_ID_EAF)
107     debug("EnableAdvancedFeatures, ");
108     debug("ID=%i", idata & SBIC_ID_MASK);
109     break;
110    
111     case SBIC_control:
112     debug(" (control): 0x%02x =>", (int)idata);
113     if (idata & SBIC_CTL_DMA)
114     debug(" SingleByteDMA");
115     if (idata & SBIC_CTL_DBA_DMA)
116     debug(" DirectBufferAccess");
117     if (idata & SBIC_CTL_BURST_DMA)
118     debug(" BurstDMA");
119     if (idata & SBIC_CTL_HHP)
120     debug(" HaltOnParity");
121     if (idata & SBIC_CTL_EDI)
122     debug(" EndDisconIntr");
123     if (idata & SBIC_CTL_IDI)
124     debug(" IntermediateDisconIntr");
125     if (idata & SBIC_CTL_HA)
126     debug(" HaltOnATN");
127     if (idata & SBIC_CTL_HSP)
128     debug(" HaltOnParityError");
129    
130     if (idata == SBIC_CTL_NO_DMA)
131     debug(" PIO");
132    
133     /* TODO: When/how are interrupts acknowledged? */
134     if (idata & SBIC_CTL_EDI)
135     d->irq_pending = 0;
136    
137     break;
138    
139     case SBIC_count_hi:
140     debug(" (count_hi): 0x%02x", (int)idata);
141     break;
142    
143     case SBIC_count_med:
144     debug(" (count_med): 0x%02x", (int)idata);
145     break;
146    
147     case SBIC_count_lo:
148     debug(" (count_lo): 0x%02x", (int)idata);
149     break;
150    
151     case SBIC_selid:
152     debug(" (selid): 0x%02x => ", (int)idata);
153    
154     if (idata & SBIC_SID_SCC)
155     debug("SelectCommandChaining, ");
156     if (idata & SBIC_SID_FROM_SCSI)
157     debug("FromSCSI, ");
158     else
159     debug("ToSCSI, ");
160    
161     debug("id %i", idata & SBIC_SID_IDMASK);
162     break;
163    
164     case SBIC_rselid:
165     debug(" (rselid): 0x%02x => ", (int)idata);
166    
167     if (idata & SBIC_RID_ER)
168     debug("EnableReselection, ");
169     if (idata & SBIC_RID_ES)
170     debug("EnableSelection, ");
171     if (idata & SBIC_RID_DSP)
172     debug("DisableSelectParity, ");
173     if (idata & SBIC_RID_SIV)
174     debug("SourceIDValid, ");
175    
176     debug("id %i", idata & SBIC_RID_MASK);
177     break;
178    
179     case SBIC_cmd:
180     debug(" (cmd): 0x%02x => ", (int)idata);
181    
182     /* SBT = Single Byte Transfer */
183     if (idata & SBIC_CMD_SBT)
184     debug("SBT, ");
185    
186     /* Handle commands: */
187     switch (idata & SBIC_CMD_MASK) {
188     case SBIC_CMD_RESET:
189     debug("RESET");
190     d->irq_pending = 1;
191     d->reg[SBIC_csr] = SBIC_CSR_RESET;
192     break;
193     case SBIC_CMD_ABORT:
194     debug("ABORT");
195     break;
196     case SBIC_CMD_SEL_ATN:
197     debug("SEL_ATN");
198     d->irq_pending = 1;
199     d->reg[SBIC_csr] = SBIC_CSR_SEL_TIMEO;
200     if (d->controller_nr == 0 && diskimage_exist(
201     cpu->machine, d->reg[SBIC_selid] &
202 dpavlin 6 SBIC_SID_IDMASK, DISKIMAGE_SCSI)) {
203 dpavlin 4 if (d->xfer != NULL)
204     scsi_transfer_free(d->xfer);
205     d->xfer = scsi_transfer_alloc();
206    
207     /* According to NetBSD, we can go either to
208     SBIC_CSR_MIS_2 | CMD_PHASE, or
209     SBIC_CSR_MIS_2 | MESG_OUT_PHASE. */
210    
211     d->reg[SBIC_csr] = SBIC_CSR_MIS_2 | CMD_PHASE;
212    
213     d->current_phase = CMD_PHASE;
214     }
215     break;
216     case SBIC_CMD_XFER_INFO:
217     debug("XFER_INFO");
218    
219     if (d->buf != NULL)
220     free(d->buf);
221    
222     d->buf_allocatedlen = (d->reg[SBIC_count_hi] << 16)
223     + (d->reg[SBIC_count_med] << 8) +
224     d->reg[SBIC_count_lo];
225    
226     d->buf = malloc(d->buf_allocatedlen);
227     if (d->buf == NULL) {
228     fprintf(stderr, "out of memory in wdsc\n");
229     exit(1);
230     }
231    
232     d->buf_curptr = 0;
233     d->irq_pending = 0;
234     break;
235     default:
236     debug("unimplemented command");
237     }
238     break;
239    
240     case SBIC_data:
241     debug(" (data): 0x%02x", (int)idata);
242    
243     switch (d->reg[SBIC_cmd] & ~SBIC_CMD_SBT) {
244     case SBIC_CMD_XFER_INFO:
245     if (d->buf == NULL || d->buf_curptr >=
246     d->buf_allocatedlen) {
247     fprintf(stderr, "fatal error in wdsc\n");
248     exit(1);
249     }
250    
251     d->buf[d->buf_curptr++] = idata;
252    
253     if (d->buf_curptr >= d->buf_allocatedlen) {
254     int res;
255    
256     /*
257     * Transfer buf to/from the SCSI unit:
258     */
259    
260     switch (d->current_phase) {
261     case CMD_PHASE:
262     scsi_transfer_allocbuf(
263     &d->xfer->cmd_len, &d->xfer->cmd,
264     d->buf_allocatedlen, 1);
265     memcpy(d->xfer->cmd, d->buf,
266     d->buf_allocatedlen);
267     break;
268     default:
269     fatal("wdsc: unimplemented phase %i!\n",
270     d->current_phase);
271     }
272    
273     res = diskimage_scsicommand(cpu,
274     d->reg[SBIC_selid] & SBIC_SID_IDMASK,
275 dpavlin 6 DISKIMAGE_SCSI, d->xfer);
276 dpavlin 4 debug("{ res = %i }", res);
277    
278     d->irq_pending = 1;
279    
280     if (res == 2)
281     d->reg[SBIC_csr] = SBIC_CSR_XFERRED |
282     DATA_OUT_PHASE;
283     else
284     d->reg[SBIC_csr] = SBIC_CSR_XFERRED |
285     DATA_IN_PHASE;
286    
287     /* status phase? msg in and msg out? */
288     }
289     break;
290     default:
291     fatal("[ wdsc: don't know how to handle data for "
292     "cmd = 0x%02x ]\n", d->reg[SBIC_cmd]);
293     }
294    
295     break;
296    
297     default:
298     debug(" (TODO): 0x%02x", (int)idata);
299     }
300    
301     debug(" ]\n");
302    
303     /* After writing to a register, advance to the next: */
304     d->register_select ++;
305     }
306    
307    
308     /*
309     * dev_wdsc_access():
310     */
311     int dev_wdsc_access(struct cpu *cpu, struct memory *mem,
312     uint64_t relative_addr, unsigned char *data, size_t len,
313     int writeflag, void *extra)
314     {
315     int i;
316     struct wdsc_data *d = extra;
317     uint64_t idata = 0, odata = 0;
318    
319 dpavlin 18 if (writeflag == MEM_WRITE)
320     idata = memory_readmax64(cpu, data, len);
321 dpavlin 4
322     /*
323     * All registers on the WDSC seem to be accessed by writing the
324     * register number to one address (SBIC_ADDR), and then reading/
325     * writing another address (SBIC_VAL).
326     *
327     * On SGI-IP22, these are at offset 3 and 7, respectively.
328     *
329     * TODO: If this device is to be used by other machine types, then
330     * this needs to be conditionalized.
331     */
332     relative_addr = (relative_addr - 3) / 4;
333    
334     switch (relative_addr) {
335    
336     case SBIC_ADDR:
337     /*
338     * Reading the combined ADDR/ASR returns the Status
339     * Register, writing selects which register to access
340     * via SBIC_VAL.
341     */
342     if (writeflag == MEM_READ) {
343     odata = SBIC_ASR_DBR;
344     if (d->irq_pending)
345     odata |= SBIC_ASR_INT;
346    
347     debug("[ wdsc: read from Status Register: %02x ]\n",
348     (int)odata);
349     } else {
350     d->register_select = idata & (DEV_WDSC_NREGS - 1);
351     }
352     break;
353    
354     case SBIC_VAL:
355     if (writeflag == MEM_READ) {
356     odata = d->reg[d->register_select];
357    
358     if (d->register_select == SBIC_csr) {
359     /* TODO: when should interrupts actually be
360     ack:ed? */
361     d->irq_pending = 0;
362     }
363    
364     debug("[ wdsc: read from register %i: 0x%02x ]\n",
365     d->register_select, (int)odata);
366     } else {
367     dev_wdsc_regwrite(cpu, d, idata & 0xff);
368     }
369     break;
370    
371     default:
372     /* These should never occur: */
373     if (writeflag==MEM_READ) {
374     fatal("[ wdsc: read from 0x%x:", (int)relative_addr);
375     for (i=0; i<len; i++)
376     fatal(" %02x", data[i]);
377     fatal(" (len=%i) ]\n", len);
378     } else {
379     fatal("[ wdsc: write to 0x%x:", (int)relative_addr);
380     for (i=0; i<len; i++)
381     fatal(" %02x", data[i]);
382     fatal(" (len=%i) ]\n", len);
383     }
384     }
385    
386     if (writeflag == MEM_READ)
387     memory_writemax64(cpu, data, len, odata);
388    
389     dev_wdsc_tick(cpu, extra);
390    
391     return 1;
392     }
393    
394    
395     /*
396     * dev_wdsc_init():
397     */
398     void dev_wdsc_init(struct machine *machine, struct memory *mem,
399     uint64_t baseaddr, int controller_nr, int irq_nr)
400     {
401     struct wdsc_data *d;
402    
403     d = malloc(sizeof(struct wdsc_data));
404     if (d == NULL) {
405     fprintf(stderr, "out of memory\n");
406     exit(1);
407     }
408     memset(d, 0, sizeof(struct wdsc_data));
409     d->irq_nr = irq_nr;
410     d->controller_nr = controller_nr;
411    
412     memory_device_register(mem, "wdsc", baseaddr, DEV_WDSC_LENGTH,
413     dev_wdsc_access, d, MEM_DEFAULT, NULL);
414    
415     machine_add_tickfunction(machine, dev_wdsc_tick, d, 14);
416     }
417    

  ViewVC Help
Powered by ViewVC 1.1.26