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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (hide annotations)
Mon Oct 8 16:20:26 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 31410 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1298 2006/07/22 11:27:46 debug Exp $
20060626	Continuing on SPARC emulation (beginning on the 'save'
		instruction, register windows, etc).
20060629	Planning statistics gathering (new -s command line option),
		and renaming speed_tricks to allow_instruction_combinations.
20060630	Some minor manual page updates.
		Various cleanups.
		Implementing the -s command line option.
20060701	FINALLY found the bug which prevented Linux and Ultrix from
		running without the ugly hack in the R2000/R3000 cache isol
		code; it was the phystranslation hint array which was buggy.
		Removing the phystranslation hint code completely, for now.
20060702	Minor dyntrans cleanups; invalidation of physpages now only
		invalidate those parts of a page that have actually been
		translated. (32 parts per page.)
		Some MIPS non-R3000 speed fixes.
		Experimenting with MIPS instruction combination for some
		addiu+bne+sw loops, and sw+sw+sw.
		Adding support (again) for larger-than-4KB pages in MIPS tlbw*.
		Continuing on SPARC emulation: adding load/store instructions.
20060704	Fixing a virtual vs physical page shift bug in the new tlbw*
		implementation. Problem noticed by Jakub Jermar. (Many thanks.)
		Moving rfe and eret to cpu_mips_instr.c, since that is the
		only place that uses them nowadays.
20060705	Removing the BSD license from the "testmachine" include files,
		placing them in the public domain instead; this enables the
		testmachine stuff to be used from projects which are
		incompatible with the BSD license for some reason.
20060707	Adding instruction combinations for the R2000/R3000 L1
		I-cache invalidation code used by NetBSD/pmax 3.0, lui+addiu,
		various branches followed by addiu or nop, and jr ra followed
		by addiu. The time it takes to perform a full NetBSD/pmax R3000
		install on the laptop has dropped from 573 seconds to 539. :-)
20060708	Adding a framebuffer controller device (dev_fbctrl), which so
		far can be used to change the fb resolution during runtime, but
		in the future will also be useful for accelerated block fill/
		copy, and possibly also simplified character output.
		Adding an instruction combination for NetBSD/pmax' strlen.
20060709	Minor fixes: reading raw files in src/file.c wasn't memblock
		aligned, removing buggy multi_sw MIPS instruction combination,
		etc.
20060711	Adding a machine_qemu.c, which contains a "qemu_mips" machine.
		(It mimics QEMU's MIPS machine mode, so that a test kernel
		made for QEMU_MIPS also can run in GXemul... at least to some
		extent.)  Adding a short section about how to run this mode to
		doc/guestoses.html.
20060714	Misc. minor code cleanups.
20060715	Applying a patch which adds getchar() to promemul/yamon.c
		(from Oleksandr Tymoshenko).
		Adding yamon.h from NetBSD, and rewriting yamon.c to use it
		(instead of ugly hardcoded numbers) + some cleanup.
20060716	Found and fixed the bug which broke single-stepping of 64-bit
		programs between 0.4.0 and 0.4.0.1 (caused by too quick
		refactoring and no testing). Hopefully this fix will not
		break too many other things.
20060718	Continuing on the 8253 PIT; it now works with Linux/QEMU_MIPS.
		Re-adding the sw+sw+sw instr comb (the problem was that I had
		ignored endian issues); however, it doesn't seem to give any
		big performance gain.
20060720	Adding a dummy Transputer mode (T414, T800 etc) skeleton (only
		the 'j' and 'ldc' instructions are implemented so far). :-}
20060721	Adding gtreg.h from NetBSD, updating dev_gt.c to use it, plus
		misc. other updates to get Linux 2.6 for evbmips/malta working
		(thanks to Alec Voropay for the details).
		FINALLY found and fixed the bug which made tlbw* for non-R3000
		buggy; it was a reference count problem in the dyntrans core.
20060722	Testing stuff; things seem stable enough for a new release.

==============  RELEASE 0.4.1  ==============


1 dpavlin 4 /*
2 dpavlin 22 * Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
3 dpavlin 4 *
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 28 * $Id: dev_asc.c,v 1.81 2006/07/21 16:55:41 debug Exp $
29 dpavlin 4 *
30 dpavlin 22 * 'asc' SCSI controller for some DECstation/DECsystem models and PICA-61.
31 dpavlin 4 *
32     * Supposed to support SCSI-1 and SCSI-2. I've not yet found any docs
33     * on NCR53C9X, so I'll try to implement this device from LSI53CF92A docs
34     * instead.
35     *
36     *
37     * Memory layout on DECstation:
38     *
39     * NCR53C94 registers at base + 0
40     * DMA address register at base + 0x40000
41     * 128K SRAM buffer at base + 0x80000
42     * ROM at base + 0xc0000
43     *
44     * Memory layout on PICA-61:
45     *
46     * I haven't had time to look this up yet, but length = 0x1000.
47     *
48     *
49     * TODO: This module needs a clean-up, and some testing to see that
50     * it works will all OSes that might use it (NetBSD, OpenBSD,
51     * Ultrix, Linux, Mach, OSF/1, Sprite, ...)
52 dpavlin 22 *
53     * Running Linux/DECstation 2.4.26 with no scsi disks attached causes
54     * a warning message to be printed by Linux. (Whether this is a bug,
55     * is is the way it works on real hardware, I don't know.)
56 dpavlin 4 */
57    
58     #include <stdio.h>
59     #include <stdlib.h>
60     #include <string.h>
61    
62     #include "cpu.h"
63     #include "devices.h"
64     #include "diskimage.h"
65     #include "machine.h"
66     #include "memory.h"
67     #include "misc.h"
68    
69     #include "ncr53c9xreg.h"
70    
71    
72     /* #define ASC_DEBUG */
73     /* #define debug fatal */
74     /* #define ASC_FULL_REGISTER_ACCESS_DEBUG */
75     /* static int quiet_mode = 0; */
76    
77 dpavlin 12 #define ASC_TICK_SHIFT 15
78    
79 dpavlin 4 extern int quiet_mode;
80    
81    
82     #define ASC_FIFO_LEN 16
83     #define STATE_DISCONNECTED 0
84     #define STATE_INITIATOR 1
85     #define STATE_TARGET 2
86    
87     #define PHASE_DATA_OUT 0
88     #define PHASE_DATA_IN 1
89     #define PHASE_COMMAND 2
90     #define PHASE_STATUS 3
91     #define PHASE_MSG_OUT 6
92     #define PHASE_MSG_IN 7
93    
94    
95     /* The controller's SCSI id: */
96     #define ASC_SCSI_ID 7
97    
98 dpavlin 12 #define ASC_DMA_SIZE (128*1024)
99    
100 dpavlin 4 struct asc_data {
101     int mode;
102    
103     void *turbochannel;
104     int irq_nr;
105     int irq_caused_last_time;
106    
107     /* Current state and transfer: */
108     int cur_state;
109     int cur_phase;
110     struct scsi_transfer *xferp;
111    
112     /* FIFO: */
113     unsigned char fifo[ASC_FIFO_LEN];
114     int fifo_in;
115     int fifo_out;
116     int n_bytes_in_fifo; /* cached */
117    
118     /* ATN signal: */
119     int atn;
120    
121     /* Incoming dma data: */
122     unsigned char *incoming_data;
123     int incoming_len;
124     int incoming_data_addr;
125    
126     /* Built-in DMA memory (for DECstation 5000/200): */
127     uint32_t dma_address_reg;
128 dpavlin 12 unsigned char *dma_address_reg_memory;
129     unsigned char *dma;
130 dpavlin 4
131     void *dma_controller_data;
132     size_t (*dma_controller)(void *dma_controller_data,
133     unsigned char *data, size_t len, int writeflag);
134    
135     /* Read registers and write registers: */
136     uint32_t reg_ro[0x10];
137     uint32_t reg_wo[0x10];
138     };
139    
140     /* (READ/WRITE name, if split) */
141     char *asc_reg_names[0x10] = {
142     "NCR_TCL", "NCR_TCM", "NCR_FIFO", "NCR_CMD",
143     "NCR_STAT/NCR_SELID", "NCR_INTR/NCR_TIMEOUT",
144     "NCR_STEP/NCR_SYNCTP", "NCR_FFLAG/NCR_SYNCOFF",
145     "NCR_CFG1", "NCR_CCF", "NCR_TEST", "NCR_CFG2",
146     "NCR_CFG3", "reg_0xd", "NCR_TCH", "reg_0xf"
147     };
148    
149    
150     /* This is referenced below. */
151     static int dev_asc_select(struct cpu *cpu, struct asc_data *d, int from_id,
152     int to_id, int dmaflag, int n_messagebytes);
153    
154    
155 dpavlin 28 DEVICE_TICK(asc)
156 dpavlin 4 {
157     struct asc_data *d = extra;
158    
159     if (d->reg_ro[NCR_STAT] & NCRSTAT_INT)
160     cpu_interrupt(cpu, d->irq_nr);
161     }
162    
163    
164     /*
165     * dev_asc_fifo_flush():
166     *
167     * Flush the fifo.
168     */
169     static void dev_asc_fifo_flush(struct asc_data *d)
170     {
171     d->fifo[0] = 0x00;
172     d->fifo_in = 0;
173     d->fifo_out = 0;
174     d->n_bytes_in_fifo = 0;
175     }
176    
177    
178     /*
179     * dev_asc_reset():
180     *
181     * Reset the state of the asc.
182     */
183     static void dev_asc_reset(struct asc_data *d)
184     {
185     d->cur_state = STATE_DISCONNECTED;
186     d->atn = 0;
187    
188     if (d->xferp != NULL)
189     scsi_transfer_free(d->xferp);
190     d->xferp = NULL;
191    
192     dev_asc_fifo_flush(d);
193    
194     /* According to table 4.1 in the LSI53CF92A manual: */
195     memset(d->reg_wo, 0, sizeof(d->reg_wo));
196     d->reg_wo[NCR_TCH] = 0x94;
197     d->reg_wo[NCR_CCF] = 2;
198     memcpy(d->reg_ro, d->reg_wo, sizeof(d->reg_ro));
199     d->reg_wo[NCR_SYNCTP] = 5;
200     }
201    
202    
203     /*
204     * dev_asc_fifo_read():
205     *
206     * Read a byte from the asc FIFO.
207     */
208     static int dev_asc_fifo_read(struct asc_data *d)
209     {
210     int res = d->fifo[d->fifo_out];
211    
212     if (d->fifo_in == d->fifo_out)
213     fatal("dev_asc: WARNING! FIFO overrun!\n");
214    
215     d->fifo_out = (d->fifo_out + 1) % ASC_FIFO_LEN;
216     d->n_bytes_in_fifo --;
217    
218     return res;
219     }
220    
221    
222     /*
223     * dev_asc_fifo_write():
224     *
225     * Write a byte to the asc FIFO.
226     */
227     static void dev_asc_fifo_write(struct asc_data *d, unsigned char data)
228     {
229     d->fifo[d->fifo_in] = data;
230     d->fifo_in = (d->fifo_in + 1) % ASC_FIFO_LEN;
231     d->n_bytes_in_fifo ++;
232    
233     if (d->fifo_in == d->fifo_out)
234     fatal("dev_asc: WARNING! FIFO overrun on write!\n");
235     }
236    
237    
238     /*
239     * dev_asc_newxfer():
240     *
241     * Allocate memory for a new transfer.
242     */
243     static void dev_asc_newxfer(struct asc_data *d)
244     {
245     if (d->xferp != NULL) {
246     printf("WARNING! dev_asc_newxfer(): freeing previous"
247     " transfer\n");
248     scsi_transfer_free(d->xferp);
249     d->xferp = NULL;
250     }
251    
252     d->xferp = scsi_transfer_alloc();
253     #if 0
254     d->xferp->get_data_out = dev_asc_get_data_out;
255     d->xferp->gdo_extra = (void *) d;
256     #endif
257     }
258    
259    
260     /*
261     * dev_asc_transfer():
262     *
263     * Transfer data from a SCSI device to the controller (or vice versa),
264     * depending on the current phase.
265     *
266     * Returns 1 if ok, 0 on error.
267     */
268     static int dev_asc_transfer(struct cpu *cpu, struct asc_data *d, int dmaflag)
269     {
270     int res = 1, all_done = 1;
271     int len, i, ch;
272    
273     if (!quiet_mode)
274     debug(" { TRANSFER to/from id %i: ", d->reg_wo[NCR_SELID] & 7);
275    
276     if (d->cur_phase == PHASE_DATA_IN) {
277     /* Data coming into the controller from external device: */
278     if (!dmaflag) {
279     if (d->xferp->data_in == NULL) {
280     fatal("no incoming data?\n");
281     res = 0;
282     } else {
283     /* TODO */
284     fatal("TODO..............\n");
285     len = d->reg_wo[NCR_TCL] +
286     d->reg_wo[NCR_TCM] * 256;
287    
288     len--;
289     ch = d->incoming_data[d->incoming_data_addr];
290     debug(" %02x", ch);
291    
292     d->incoming_data_addr ++;
293     dev_asc_fifo_write(d, ch);
294    
295     if (len == 0) {
296     free(d->incoming_data);
297     d->incoming_data = NULL;
298     }
299    
300     d->reg_ro[NCR_TCL] = len & 255;
301     d->reg_ro[NCR_TCM] = (len >> 8) & 255;
302     }
303     } else {
304     /* Copy from the incoming data into dma memory: */
305     if (d->xferp->data_in == NULL) {
306     fatal("no incoming DMA data?\n");
307     res = 0;
308     } else {
309 dpavlin 22 size_t len = d->xferp->data_in_len;
310     size_t len2 = d->reg_wo[NCR_TCL] +
311 dpavlin 4 d->reg_wo[NCR_TCM] * 256;
312     if (len2 == 0)
313     len2 = 65536;
314    
315     if (len < len2) {
316     fatal("{ asc: data in, len=%i len2=%i "
317     "}\n", len, len2);
318     }
319    
320     /* TODO: check len2 in a similar way? */
321     if (len + (d->dma_address_reg &
322 dpavlin 12 (ASC_DMA_SIZE-1)) > ASC_DMA_SIZE)
323     len = ASC_DMA_SIZE -
324 dpavlin 4 (d->dma_address_reg &
325 dpavlin 12 (ASC_DMA_SIZE-1));
326 dpavlin 4
327     if (len2 > len) {
328     memset(d->dma + (d->dma_address_reg &
329 dpavlin 12 (ASC_DMA_SIZE-1)), 0, len2);
330 dpavlin 4 len2 = len;
331     }
332    
333     #ifdef ASC_DEBUG
334     if (!quiet_mode) {
335     int i;
336     for (i=0; i<len; i++)
337     debug(" %02x", d->xferp->
338     data_in[i]);
339     }
340     #endif
341    
342     /*
343     * Are we using an external DMA controller?
344     * Then use it. Otherwise place the data in
345     * the DECstation 5000/200 built-in DMA
346     * region.
347     */
348     if (d->dma_controller != NULL)
349     d->dma_controller(
350     d->dma_controller_data,
351     d->xferp->data_in,
352     len2, 1);
353     else
354     memcpy(d->dma + (d->dma_address_reg &
355 dpavlin 12 (ASC_DMA_SIZE-1)),
356 dpavlin 4 d->xferp->data_in, len2);
357    
358     if (d->xferp->data_in_len > len2) {
359     unsigned char *n;
360    
361     if (d->dma_controller != NULL)
362     printf("WARNING!!!!!!!!! BUG!!!! Unexpected stuff..."
363     "len2=%i d->xferp->data_in_len=%i\n", (int)len2,
364     (int)d->xferp->data_in_len);
365    
366     all_done = 0;
367     /* fatal("{ asc: multi-transfer"
368     " data_in, len=%i len2=%i }\n",
369     (int)len, (int)len2); */
370    
371     d->xferp->data_in_len -= len2;
372     n = malloc(d->xferp->data_in_len);
373     if (n == NULL) {
374     fprintf(stderr, "out of memory"
375     " in dev_asc\n");
376     exit(1);
377     }
378     memcpy(n, d->xferp->data_in + len2,
379     d->xferp->data_in_len);
380     free(d->xferp->data_in);
381     d->xferp->data_in = n;
382    
383     len = len2;
384     }
385    
386     len = 0;
387    
388     d->reg_ro[NCR_TCL] = len & 255;
389     d->reg_ro[NCR_TCM] = (len >> 8) & 255;
390    
391     /* Successful DMA transfer: */
392     d->reg_ro[NCR_STAT] |= NCRSTAT_TC;
393     }
394     }
395     } else if (d->cur_phase == PHASE_DATA_OUT) {
396     /* Data going from the controller to an external device: */
397     if (!dmaflag) {
398     fatal("TODO.......asdgasin\n");
399     } else {
400     /* Copy data from DMA to data_out: */
401     int len = d->xferp->data_out_len;
402     int len2 = d->reg_wo[NCR_TCL] +
403     d->reg_wo[NCR_TCM] * 256;
404     if (len2 == 0)
405     len2 = 65536;
406    
407     if (len == 0) {
408     fprintf(stderr, "d->xferp->data_out_len == "
409     "0 ?\n");
410     exit(1);
411     }
412    
413     /* TODO: Make sure that len2 doesn't go outside
414     of the dma memory? */
415    
416     /* fatal(" data out offset=%5i len=%5i\n",
417     d->xferp->data_out_offset, len2); */
418    
419     if (d->xferp->data_out_offset + len2 >
420     d->xferp->data_out_len) {
421     len2 = d->xferp->data_out_len -
422     d->xferp->data_out_offset;
423     }
424    
425     /*
426     * Are we using an external DMA controller? Then use
427     * it. Otherwise place the data in the DECstation
428     * 5000/200 built-in DMA region.
429     */
430     if (d->xferp->data_out == NULL) {
431     scsi_transfer_allocbuf(&d->xferp->data_out_len,
432     &d->xferp->data_out, len, 0);
433    
434     if (d->dma_controller != NULL)
435     d->dma_controller(
436     d->dma_controller_data,
437     d->xferp->data_out,
438     len2, 0);
439     else
440     memcpy(d->xferp->data_out,
441     d->dma + (d->dma_address_reg &
442 dpavlin 12 (ASC_DMA_SIZE-1)), len2);
443 dpavlin 4 d->xferp->data_out_offset = len2;
444     } else {
445     /* Continuing a multi-transfer: */
446     if (d->dma_controller != NULL)
447     d->dma_controller(
448     d->dma_controller_data,
449     d->xferp->data_out +
450     d->xferp->data_out_offset,
451     len2, 0);
452     else
453     memcpy(d->xferp->data_out +
454     d->xferp->data_out_offset,
455     d->dma + (d->dma_address_reg &
456 dpavlin 12 (ASC_DMA_SIZE-1)), len2);
457 dpavlin 4 d->xferp->data_out_offset += len2;
458     }
459    
460     /* If the disk wants more than we're DMAing,
461     then this is a multitransfer: */
462     if (d->xferp->data_out_offset !=
463     d->xferp->data_out_len) {
464     if (!quiet_mode)
465     debug("[ asc: data_out, multitransfer "
466     "len = %i, len2 = %i ]\n",
467     (int)len, (int)len2);
468     if (d->xferp->data_out_offset >
469     d->xferp->data_out_len)
470     fatal("[ asc data_out dma: too much?"
471     " ]\n");
472     else
473     all_done = 0;
474     }
475    
476     #ifdef ASC_DEBUG
477     if (!quiet_mode) {
478     int i;
479     for (i=0; i<len; i++)
480     debug(" %02x", d->xferp->data_out[i]);
481     }
482     #endif
483     len = 0;
484    
485     d->reg_ro[NCR_TCL] = len & 255;
486     d->reg_ro[NCR_TCM] = (len >> 8) & 255;
487    
488     /* Successful DMA transfer: */
489     d->reg_ro[NCR_STAT] |= NCRSTAT_TC;
490     }
491     } else if (d->cur_phase == PHASE_MSG_OUT) {
492     if (!quiet_mode)
493     debug("MSG OUT: ");
494     /* Data going from the controller to an external device: */
495     if (!dmaflag) {
496     /* There should already be one byte in msg_out, so we
497     just extend the message: */
498     int oldlen = d->xferp->msg_out_len;
499     int newlen;
500    
501     if (oldlen != 1) {
502     fatal(" (PHASE OUT MSG len == %i, "
503     "should be 1)\n", oldlen);
504     }
505    
506     newlen = oldlen + d->n_bytes_in_fifo;
507     d->xferp->msg_out = realloc(d->xferp->msg_out, newlen);
508     d->xferp->msg_out_len = newlen;
509     if (d->xferp->msg_out == NULL) {
510     fprintf(stderr, "out of memory realloc'ing "
511     "msg_out\n");
512     exit(1);
513     }
514    
515     i = oldlen;
516     while (d->fifo_in != d->fifo_out) {
517     ch = dev_asc_fifo_read(d);
518     d->xferp->msg_out[i++] = ch;
519     #ifdef ASC_DEBUG
520     debug("0x%02x ", ch);
521     #endif
522     }
523    
524     #ifdef MACH
525     /* Super-ugly hack for Mach/PMAX: TODO: make nicer */
526     if (d->xferp->msg_out_len == 6 &&
527     (d->xferp->msg_out[0] == 0x80 ||
528     d->xferp->msg_out[0] == 0xc0) &&
529     d->xferp->msg_out[1] == 0x01 &&
530     d->xferp->msg_out[2] == 0x03 &&
531     d->xferp->msg_out[3] == 0x01 &&
532     d->xferp->msg_out[4] == 0x32 &&
533     d->xferp->msg_out[5] == 0x0f) {
534     fatal(" !! Mach/PMAX hack !! ");
535     all_done = 0;
536     d->cur_phase = PHASE_MSG_IN;
537     }
538     #endif
539     } else {
540     /* Copy data from DMA to msg_out: */
541     fatal("[ DMA MSG OUT: xxx TODO! ]");
542     /* TODO */
543     res = 0;
544     }
545     } else if (d->cur_phase == PHASE_MSG_IN) {
546     if (!quiet_mode)
547     debug(" MSG IN");
548     fatal("[ MACH HACK! ]");
549     /* Super-ugly hack for Mach/PMAX: TODO: make nicer */
550     dev_asc_fifo_write(d, 0x07);
551     d->cur_phase = PHASE_COMMAND;
552     all_done = 0;
553     } else if (d->cur_phase == PHASE_COMMAND) {
554     if (!quiet_mode)
555     debug(" COMMAND ==> select ");
556     res = dev_asc_select(cpu, d, d->reg_ro[NCR_CFG1] & 7,
557     d->reg_wo[NCR_SELID] & 7, dmaflag, 0);
558     return res;
559     } else {
560     fatal("!!! TODO: unknown/unimplemented phase "
561     "in transfer: %i\n", d->cur_phase);
562     }
563    
564     /* Redo the command if data was just sent using DATA_OUT: */
565     if (d->cur_phase == PHASE_DATA_OUT) {
566 dpavlin 6 res = diskimage_scsicommand(cpu, d->reg_wo[NCR_SELID] & 7,
567     DISKIMAGE_SCSI, d->xferp);
568 dpavlin 4 }
569    
570     if (all_done) {
571     if (d->cur_phase == PHASE_MSG_OUT)
572     d->cur_phase = PHASE_COMMAND;
573     else
574     d->cur_phase = PHASE_STATUS;
575     }
576    
577     /*
578     * Cause an interrupt after the transfer:
579     *
580     * NOTE: Earlier I had this in here as well:
581     * d->reg_ro[NCR_INTR] |= NCRINTR_FC;
582     * but Linux/DECstation and OpenBSD/pmax seems to choke on that.
583     */
584     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
585     d->reg_ro[NCR_INTR] |= NCRINTR_BS;
586     d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | d->cur_phase;
587     d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 4; /* 4? */
588    
589     if (!quiet_mode)
590     debug("}");
591     return res;
592     }
593    
594    
595     /*
596     * dev_asc_select():
597     *
598     * Select a SCSI device, send msg bytes (if any), and send command bytes.
599     * (Call diskimage_scsicommand() to handle the command.)
600     *
601     * Return value: 1 if ok, 0 on error.
602     */
603     static int dev_asc_select(struct cpu *cpu, struct asc_data *d, int from_id,
604     int to_id, int dmaflag, int n_messagebytes)
605     {
606     int ok, len, i, ch;
607    
608     if (!quiet_mode)
609     debug(" { SELECT id %i: ", to_id);
610    
611     /*
612     * Message bytes, if any:
613     */
614     if (!quiet_mode)
615     debug("msg:");
616    
617     if (n_messagebytes > 0) {
618     scsi_transfer_allocbuf(&d->xferp->msg_out_len,
619     &d->xferp->msg_out, n_messagebytes, 0);
620    
621     i = 0;
622     while (n_messagebytes-- > 0) {
623     int ch = dev_asc_fifo_read(d);
624     if (!quiet_mode)
625     debug(" %02x", ch);
626     d->xferp->msg_out[i++] = ch;
627     }
628    
629     if ((d->xferp->msg_out[0] & 0x7) != 0x00) {
630     debug(" (LUNs not implemented yet: 0x%02x) }",
631     d->xferp->msg_out[0]);
632     return 0;
633     }
634    
635     if (((d->xferp->msg_out[0] & ~0x7) != 0xc0) &&
636     ((d->xferp->msg_out[0] & ~0x7) != 0x80)) {
637     fatal(" (Unimplemented msg out: 0x%02x) }",
638     d->xferp->msg_out[0]);
639     return 0;
640     }
641    
642     if (d->xferp->msg_out_len > 1) {
643     fatal(" (Long msg out, not implemented yet;"
644     " len=%i) }", d->xferp->msg_out_len);
645     return 0;
646     }
647     } else {
648     if (!quiet_mode)
649     debug(" none");
650     }
651    
652     /* Special case: SELATNS (with STOP sequence): */
653     if (d->cur_phase == PHASE_MSG_OUT) {
654     if (!quiet_mode)
655     debug(" MSG OUT DEBUG");
656     if (d->xferp->msg_out_len != 1) {
657     fatal(" (SELATNS: msg out len == %i, should be 1)",
658     d->xferp->msg_out_len);
659     return 0;
660     }
661    
662     /* d->cur_phase = PHASE_COMMAND; */
663    
664     /* According to the LSI manual: */
665     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
666     d->reg_ro[NCR_INTR] |= NCRINTR_FC;
667     d->reg_ro[NCR_INTR] |= NCRINTR_BS;
668     d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | d->cur_phase;
669     d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 1;
670    
671     if (!quiet_mode)
672     debug("}");
673     return 1;
674     }
675    
676     /*
677     * Command bytes:
678     */
679     if (!quiet_mode)
680     debug(", cmd: ");
681    
682     if (!dmaflag) {
683     if (!quiet_mode)
684     debug("[non-DMA] ");
685    
686     scsi_transfer_allocbuf(&d->xferp->cmd_len,
687     &d->xferp->cmd, d->n_bytes_in_fifo, 0);
688    
689     i = 0;
690     while (d->fifo_in != d->fifo_out) {
691     ch = dev_asc_fifo_read(d);
692     d->xferp->cmd[i++] = ch;
693     if (!quiet_mode)
694     debug("%02x ", ch);
695     }
696     } else {
697     if (!quiet_mode)
698     debug("[DMA] ");
699     len = d->reg_wo[NCR_TCL] + d->reg_wo[NCR_TCM] * 256;
700     if (len == 0)
701     len = 65536;
702    
703     scsi_transfer_allocbuf(&d->xferp->cmd_len,
704     &d->xferp->cmd, len, 0);
705    
706     for (i=0; i<len; i++) {
707     int ofs = d->dma_address_reg + i;
708 dpavlin 12 ch = d->dma[ofs & (ASC_DMA_SIZE-1)];
709 dpavlin 4 d->xferp->cmd[i] = ch;
710     if (!quiet_mode)
711     debug("%02x ", ch);
712     }
713    
714     d->reg_ro[NCR_TCL] = len & 255;
715     d->reg_ro[NCR_TCM] = (len >> 8) & 255;
716    
717     d->reg_ro[NCR_STAT] |= NCRSTAT_TC;
718     }
719    
720     /*
721     * Call the SCSI device to perform the command:
722     */
723 dpavlin 6 ok = diskimage_scsicommand(cpu, to_id, DISKIMAGE_SCSI, d->xferp);
724 dpavlin 4
725    
726     /* Cause an interrupt: */
727     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
728     d->reg_ro[NCR_INTR] |= NCRINTR_FC;
729     d->reg_ro[NCR_INTR] |= NCRINTR_BS;
730    
731     if (ok == 2)
732     d->cur_phase = PHASE_DATA_OUT;
733     else if (d->xferp->data_in != NULL)
734     d->cur_phase = PHASE_DATA_IN;
735     else
736     d->cur_phase = PHASE_STATUS;
737    
738     d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | d->cur_phase;
739     d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 4; /* DONE (?) */
740    
741     if (!quiet_mode)
742     debug("}");
743    
744     return ok;
745     }
746    
747    
748 dpavlin 22 DEVICE_ACCESS(asc_address_reg)
749 dpavlin 4 {
750     struct asc_data *d = extra;
751    
752     if (relative_addr + len > 4)
753     return 0;
754    
755     if (writeflag==MEM_READ) {
756     memcpy(data, d->dma_address_reg_memory + relative_addr, len);
757     } else {
758     memcpy(d->dma_address_reg_memory + relative_addr, data, len);
759     }
760    
761     return 1;
762     }
763    
764    
765 dpavlin 22 DEVICE_ACCESS(asc_dma)
766 dpavlin 4 {
767     struct asc_data *d = extra;
768    
769     if (writeflag==MEM_READ) {
770     memcpy(data, d->dma + relative_addr, len);
771     #ifdef ASC_DEBUG
772     {
773     int i;
774     debug("[ asc: read from DMA addr 0x%05x:",
775     (int) relative_addr);
776     for (i=0; i<len; i++)
777     debug(" %02x", data[i]);
778     debug(" ]\n");
779     }
780     #endif
781    
782     /* Don't return the common way, as that
783     would overwrite data. */
784     return 1;
785     } else {
786     memcpy(d->dma + relative_addr, data, len);
787     #ifdef ASC_DEBUG
788     {
789     int i;
790     debug("[ asc: write to DMA addr 0x%05x:",
791     (int) relative_addr);
792     for (i=0; i<len; i++)
793     debug(" %02x", data[i]);
794     debug(" ]\n");
795     }
796     #endif
797     /* Quick return. */
798     return 1;
799     }
800     }
801    
802    
803 dpavlin 22 DEVICE_ACCESS(asc)
804 dpavlin 4 {
805     int regnr;
806     struct asc_data *d = extra;
807     int target_exists;
808     int n_messagebytes = 0;
809     uint64_t idata = 0, odata = 0;
810    
811 dpavlin 18 if (writeflag == MEM_WRITE)
812     idata = memory_readmax64(cpu, data, len);
813 dpavlin 4
814     #if 0
815     /* Debug stuff useful when trying to make dev_asc compatible
816     with the 'arc' emulation mode, which is different from
817     the DECstation mode. */
818     fatal("[ asc: writeflag=%i addr=%08x idata=%016llx ]\n",
819     writeflag, (int)relative_addr, (long long)idata);
820     #endif
821    
822     switch (d->mode) {
823     case DEV_ASC_DEC:
824     regnr = relative_addr / 4;
825     break;
826     case DEV_ASC_PICA:
827     default:
828     regnr = relative_addr;
829     }
830    
831     /* Controller's ID is fixed: */
832     d->reg_ro[NCR_CFG1] = (d->reg_ro[NCR_CFG1] & ~7) | ASC_SCSI_ID;
833    
834     d->reg_ro[NCR_FFLAG] = ((d->reg_ro[NCR_STEP] & 0x7) << 5)
835     + d->n_bytes_in_fifo;
836    
837     d->dma_address_reg =
838     d->dma_address_reg_memory[0] +
839     (d->dma_address_reg_memory[1] << 8) +
840     (d->dma_address_reg_memory[2] << 16) +
841     (d->dma_address_reg_memory[3] << 24);
842    
843     if (regnr < 0x10) {
844     if (regnr == NCR_FIFO) {
845     if (writeflag == MEM_WRITE)
846     dev_asc_fifo_write(d, idata);
847     else
848     odata = dev_asc_fifo_read(d);
849     } else {
850     if (writeflag==MEM_WRITE)
851     d->reg_wo[regnr] = idata;
852     else
853     odata = d->reg_ro[regnr];
854     }
855    
856     #ifdef ASC_FULL_REGISTER_ACCESS_DEBUG
857     if (!quiet_mode) {
858     if (writeflag==MEM_READ) {
859     debug("[ asc: read from %s: 0x%02x",
860     asc_reg_names[regnr], (int)odata);
861     } else {
862     debug("[ asc: write to %s: 0x%02x",
863     asc_reg_names[regnr], (int)idata);
864     }
865     }
866     #endif
867     } else if (relative_addr >= 0x300 && relative_addr < 0x600
868     && d->turbochannel != NULL) {
869     debug("[ asc: offset 0x%x, redirecting to turbochannel"
870     " access ]\n", relative_addr);
871     return dev_turbochannel_access(cpu, mem,
872     relative_addr, data, len, writeflag,
873     d->turbochannel);
874     } else {
875     if (writeflag==MEM_READ) {
876     fatal("[ asc: read from 0x%04x: 0x%02x ]\n",
877     relative_addr, (int)odata);
878     } else {
879     fatal("[ asc: write to 0x%04x: 0x%02x ]\n",
880     relative_addr, (int)idata);
881     }
882     }
883    
884     /*
885     * Some registers are read/write. Copy contents of
886     * reg_wo to reg_ro:
887     */
888     #if 0
889     d->reg_ro[ 0] = d->reg_wo[0]; /* Transfer count lo and */
890     d->reg_ro[ 1] = d->reg_wo[1]; /* middle */
891     #endif
892     d->reg_ro[ 2] = d->reg_wo[2];
893     d->reg_ro[ 3] = d->reg_wo[3];
894     d->reg_ro[ 8] = d->reg_wo[8];
895     d->reg_ro[ 9] = d->reg_wo[9];
896     d->reg_ro[10] = d->reg_wo[10];
897     d->reg_ro[11] = d->reg_wo[11];
898     d->reg_ro[12] = d->reg_wo[12];
899    
900     if (regnr == NCR_CMD && writeflag == MEM_WRITE) {
901     if (!quiet_mode)
902     debug(" ");
903    
904     /* TODO: Perhaps turn off others here too? */
905     d->reg_ro[NCR_INTR] &= ~NCRINTR_SBR;
906    
907     if (idata & NCRCMD_DMA) {
908     if (!quiet_mode)
909     debug("[DMA] ");
910    
911     /*
912     * DMA commands load the transfer count from the
913     * write-only registers to the read-only ones, and
914     * the Terminal Count bit is cleared.
915     */
916     d->reg_ro[NCR_TCL] = d->reg_wo[NCR_TCL];
917     d->reg_ro[NCR_TCM] = d->reg_wo[NCR_TCM];
918     d->reg_ro[NCR_TCH] = d->reg_wo[NCR_TCH];
919     d->reg_ro[NCR_STAT] &= ~NCRSTAT_TC;
920     }
921    
922     switch (idata & ~NCRCMD_DMA) {
923    
924     case NCRCMD_NOP:
925     if (!quiet_mode)
926     debug("NOP");
927     break;
928    
929     case NCRCMD_FLUSH:
930     if (!quiet_mode)
931     debug("FLUSH");
932     /* Flush the FIFO: */
933     dev_asc_fifo_flush(d);
934     break;
935    
936     case NCRCMD_RSTCHIP:
937     if (!quiet_mode)
938     debug("RSTCHIP");
939     /* Hardware reset. */
940     dev_asc_reset(d);
941     break;
942    
943     case NCRCMD_RSTSCSI:
944     if (!quiet_mode)
945     debug("RSTSCSI");
946     /* No interrupt if interrupts are disabled. */
947     if (!(d->reg_wo[NCR_CFG1] & NCRCFG1_SRR))
948     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
949     d->reg_ro[NCR_INTR] |= NCRINTR_SBR;
950     d->reg_ro[NCR_INTR] |= NCRINTR_FC;
951     d->cur_state = STATE_DISCONNECTED;
952     break;
953    
954     case NCRCMD_ENSEL:
955     if (!quiet_mode)
956     debug("ENSEL");
957     /* TODO */
958     break;
959    
960     case NCRCMD_ICCS:
961     if (!quiet_mode)
962     debug("ICCS");
963     /* Reveice a status byte + a message byte. */
964    
965     /* TODO: how about other status and message bytes? */
966     if (d->xferp != NULL && d->xferp->status != NULL)
967     dev_asc_fifo_write(d, d->xferp->status[0]);
968     else
969     dev_asc_fifo_write(d, 0x00);
970    
971     if (d->xferp != NULL && d->xferp->msg_in != NULL)
972     dev_asc_fifo_write(d, d->xferp->msg_in[0]);
973     else
974     dev_asc_fifo_write(d, 0x00);
975    
976     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
977     d->reg_ro[NCR_INTR] |= NCRINTR_FC;
978     /* d->reg_ro[NCR_INTR] |= NCRINTR_BS; */
979     d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | 7;
980     /* ? probably 7 */
981     d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 4;
982     /* ? */
983     break;
984    
985     case NCRCMD_MSGOK:
986     /* Message is being Rejected if ATN is set,
987     otherwise Accepted. */
988     if (!quiet_mode) {
989     debug("MSGOK");
990     if (d->atn)
991     debug("; Rejecting message");
992     else
993     debug("; Accepting message");
994     }
995     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
996     d->reg_ro[NCR_INTR] |= NCRINTR_DIS;
997    
998     d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) |
999     d->cur_phase; /* 6? */
1000     d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) |
1001     4; /* ? */
1002    
1003     d->cur_state = STATE_DISCONNECTED;
1004    
1005     if (d->xferp != NULL)
1006     scsi_transfer_free(d->xferp);
1007     d->xferp = NULL;
1008     break;
1009    
1010     case NCRCMD_SETATN:
1011     if (!quiet_mode)
1012     debug("SETATN");
1013     d->atn = 1;
1014     break;
1015    
1016     case NCRCMD_RSTATN:
1017     if (!quiet_mode)
1018     debug("RSTATN");
1019     d->atn = 0;
1020     break;
1021    
1022     case NCRCMD_SELNATN:
1023     case NCRCMD_SELATN:
1024     case NCRCMD_SELATNS:
1025     case NCRCMD_SELATN3:
1026     d->cur_phase = PHASE_COMMAND;
1027     switch (idata & ~NCRCMD_DMA) {
1028     case NCRCMD_SELATN:
1029     case NCRCMD_SELATNS:
1030     if ((idata & ~NCRCMD_DMA) == NCRCMD_SELATNS) {
1031     if (!quiet_mode)
1032     debug("SELATNS: select with "
1033     "atn and stop, id %i",
1034     d->reg_wo[NCR_SELID] & 7);
1035     d->cur_phase = PHASE_MSG_OUT;
1036     } else {
1037     if (!quiet_mode)
1038     debug("SELATN: select with atn"
1039     ", id %i",
1040     d->reg_wo[NCR_SELID] & 7);
1041     }
1042     n_messagebytes = 1;
1043     break;
1044     case NCRCMD_SELATN3:
1045     if (!quiet_mode)
1046     debug("SELNATN: select with atn3, "
1047     "id %i", d->reg_wo[NCR_SELID] & 7);
1048     n_messagebytes = 3;
1049     break;
1050     case NCRCMD_SELNATN:
1051     if (!quiet_mode)
1052     debug("SELNATN: select without atn, "
1053     "id %i", d->reg_wo[NCR_SELID] & 7);
1054     n_messagebytes = 0;
1055     }
1056    
1057     /* TODO: not just disk, but some generic
1058     SCSI device */
1059     target_exists = diskimage_exist(cpu->machine,
1060 dpavlin 6 d->reg_wo[NCR_SELID] & 7, DISKIMAGE_SCSI);
1061 dpavlin 4
1062     if (target_exists) {
1063     /*
1064     * Select a SCSI device, send message bytes
1065     * (if any) and command bytes to the target.
1066     */
1067     int ok;
1068    
1069     dev_asc_newxfer(d);
1070    
1071     ok = dev_asc_select(cpu, d,
1072     d->reg_ro[NCR_CFG1] & 7,
1073     d->reg_wo[NCR_SELID] & 7,
1074     idata & NCRCMD_DMA? 1 : 0,
1075     n_messagebytes);
1076    
1077     if (ok)
1078     d->cur_state = STATE_INITIATOR;
1079     else {
1080     d->cur_state = STATE_DISCONNECTED;
1081     d->reg_ro[NCR_INTR] |= NCRINTR_DIS;
1082     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
1083     d->reg_ro[NCR_STEP] =
1084     (d->reg_ro[NCR_STEP] & ~7) | 0;
1085     if (d->xferp != NULL)
1086     scsi_transfer_free(d->xferp);
1087     d->xferp = NULL;
1088     }
1089     } else {
1090     /*
1091     * Selection failed, non-existant scsi ID:
1092     *
1093     * This is good enough to fool Ultrix, NetBSD,
1094     * OpenBSD and Linux to continue detection of
1095     * other IDs, without giving any warnings.
1096     */
1097     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
1098     d->reg_ro[NCR_INTR] |= NCRINTR_DIS;
1099     d->reg_ro[NCR_STEP] &= ~7;
1100     d->reg_ro[NCR_STEP] |= 0;
1101     dev_asc_fifo_flush(d);
1102     d->cur_state = STATE_DISCONNECTED;
1103     }
1104     break;
1105    
1106     case NCRCMD_TRPAD:
1107     if (!quiet_mode)
1108     debug("TRPAD");
1109    
1110     dev_asc_newxfer(d);
1111     {
1112     int ok;
1113    
1114     ok = dev_asc_transfer(cpu, d,
1115     idata & NCRCMD_DMA? 1 : 0);
1116     if (!ok) {
1117     d->cur_state = STATE_DISCONNECTED;
1118     d->reg_ro[NCR_INTR] |= NCRINTR_DIS;
1119     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
1120     d->reg_ro[NCR_STEP] = (d->reg_ro[
1121     NCR_STEP] & ~7) | 0;
1122     if (d->xferp != NULL)
1123     scsi_transfer_free(d->xferp);
1124     d->xferp = NULL;
1125     }
1126     }
1127     break;
1128    
1129     /* Old code which didn't work with Mach: */
1130     #if 0
1131     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
1132     d->reg_ro[NCR_INTR] |= NCRINTR_BS;
1133     d->reg_ro[NCR_INTR] |= NCRINTR_FC;
1134     d->reg_ro[NCR_STAT] |= NCRSTAT_TC;
1135    
1136     d->reg_ro[NCR_TCL] = 0;
1137     d->reg_ro[NCR_TCM] = 0;
1138    
1139     d->reg_ro[NCR_STEP] &= ~7;
1140     #if 0
1141     d->reg_ro[NCR_STEP] |= 0;
1142     dev_asc_fifo_flush(d);
1143     #else
1144     d->reg_ro[NCR_STEP] |= 4;
1145     #endif
1146     break;
1147     #endif
1148    
1149     case NCRCMD_TRANS:
1150     if (!quiet_mode)
1151     debug("TRANS");
1152    
1153     {
1154     int ok;
1155    
1156     ok = dev_asc_transfer(cpu, d,
1157     idata & NCRCMD_DMA? 1 : 0);
1158     if (!ok) {
1159     d->cur_state = STATE_DISCONNECTED;
1160     d->reg_ro[NCR_INTR] |= NCRINTR_DIS;
1161     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
1162     d->reg_ro[NCR_STEP] = (d->reg_ro[
1163     NCR_STEP] & ~7) | 0;
1164     if (d->xferp != NULL)
1165     scsi_transfer_free(d->xferp);
1166     d->xferp = NULL;
1167     }
1168     }
1169     break;
1170    
1171     default:
1172     fatal("(unimplemented asc cmd 0x%02x)", (int)idata);
1173     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
1174     d->reg_ro[NCR_INTR] |= NCRINTR_ILL;
1175     /*
1176     * TODO: exit or continue with Illegal command
1177     * interrupt?
1178     */
1179     exit(1);
1180     }
1181     }
1182    
1183     if (regnr == NCR_INTR && writeflag == MEM_READ) {
1184     /*
1185     * Reading the interrupt register de-asserts the
1186     * interrupt pin. Also, INTR, STEP, and STAT are all
1187     * cleared, according to page 64 of the LSI53CF92A manual,
1188     * if "interrupt output is true".
1189     */
1190     if (d->reg_ro[NCR_STAT] & NCRSTAT_INT) {
1191     d->reg_ro[NCR_INTR] = 0;
1192     d->reg_ro[NCR_STEP] = 0;
1193     d->reg_ro[NCR_STAT] = 0;
1194    
1195     /* For Mach/PMAX? TODO */
1196     d->reg_ro[NCR_STAT] = PHASE_COMMAND;
1197     }
1198    
1199     cpu_interrupt_ack(cpu, d->irq_nr);
1200     }
1201    
1202     if (regnr == NCR_CFG1) {
1203     /* TODO: other bits */
1204     if (!quiet_mode) {
1205     debug(" parity %s,", d->reg_ro[regnr] &
1206     NCRCFG1_PARENB? "enabled" : "disabled");
1207     debug(" scsi_id %i", d->reg_ro[regnr] & 0x7);
1208     }
1209     }
1210    
1211     #ifdef ASC_FULL_REGISTER_ACCESS_DEBUG
1212     debug(" ]\n");
1213     #endif
1214     dev_asc_tick(cpu, extra);
1215    
1216     if (writeflag == MEM_READ)
1217     memory_writemax64(cpu, data, len, odata);
1218    
1219     return 1;
1220     }
1221    
1222    
1223     /*
1224     * dev_asc_init():
1225     *
1226     * Register an 'asc' device.
1227     */
1228     void dev_asc_init(struct machine *machine, struct memory *mem,
1229     uint64_t baseaddr, int irq_nr, void *turbochannel,
1230     int mode,
1231     size_t (*dma_controller)(void *dma_controller_data,
1232     unsigned char *data, size_t len, int writeflag),
1233     void *dma_controller_data)
1234     {
1235     struct asc_data *d;
1236    
1237     d = malloc(sizeof(struct asc_data));
1238     if (d == NULL) {
1239     fprintf(stderr, "out of memory\n");
1240     exit(1);
1241     }
1242     memset(d, 0, sizeof(struct asc_data));
1243     d->irq_nr = irq_nr;
1244     d->turbochannel = turbochannel;
1245     d->mode = mode;
1246    
1247     d->reg_ro[NCR_CFG3] = NCRF9XCFG3_CDB;
1248    
1249 dpavlin 12 d->dma_address_reg_memory = malloc(machine->arch_pagesize);
1250     d->dma = malloc(ASC_DMA_SIZE);
1251     if (d->dma == NULL || d->dma_address_reg_memory == NULL) {
1252     fprintf(stderr, "out of memory\n");
1253     exit(1);
1254     }
1255     memset(d->dma_address_reg_memory, 0, machine->arch_pagesize);
1256     memset(d->dma, 0, ASC_DMA_SIZE);
1257    
1258 dpavlin 4 d->dma_controller = dma_controller;
1259     d->dma_controller_data = dma_controller_data;
1260    
1261     memory_device_register(mem, "asc", baseaddr,
1262 dpavlin 22 mode == DEV_ASC_PICA? DEV_ASC_PICA_LENGTH : DEV_ASC_DEC_LENGTH,
1263 dpavlin 20 dev_asc_access, d, DM_DEFAULT, NULL);
1264 dpavlin 4
1265     if (mode == DEV_ASC_DEC) {
1266     memory_device_register(mem, "asc_dma_address_reg",
1267     baseaddr + 0x40000, 4096, dev_asc_address_reg_access, d,
1268 dpavlin 20 DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK,
1269 dpavlin 12 (unsigned char *)&d->dma_address_reg_memory[0]);
1270 dpavlin 4 memory_device_register(mem, "asc_dma", baseaddr + 0x80000,
1271 dpavlin 12 ASC_DMA_SIZE, dev_asc_dma_access, d,
1272 dpavlin 20 DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK, d->dma);
1273 dpavlin 4 }
1274    
1275 dpavlin 24 machine_add_tickfunction(machine, dev_asc_tick, d, ASC_TICK_SHIFT, 0.0);
1276 dpavlin 4 }
1277    

  ViewVC Help
Powered by ViewVC 1.1.26