/[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 34 - (hide annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 31519 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1480 2007/02/19 01:34:42 debug Exp $
20061029	Changing usleep(1) calls in the debugger to usleep(10000)
20061107	Adding a new disk image option (-d o...) which sets the ISO9660
		filesystem base offset; also making some other hacks to allow
		NetBSD/dreamcast and homebrew demos/games to boot directly
		from a filesystem image.
		Moving Dreamcast-specific stuff in the documentation to its
		own page (dreamcast.html).
		Adding a border to the Dreamcast PVR framebuffer.
20061108	Adding a -T command line option (again?), for halting the
		emulator on unimplemented memory accesses.
20061109	Continuing on various SH4 and Dreamcast related things.
		The emulator should now halt on more unimplemented device
		accesses, instead of just printing a warning, forcing me to
		actually implement missing stuff :)
20061111	Continuing on SH4 and Dreamcast stuff.
		Adding a bogus Landisk (SH4) machine mode.
20061112	Implementing some parts of the Dreamcast GDROM device. With
		some ugly hacks, NetBSD can (barely) mount an ISO image.
20061113	NetBSD/dreamcast now starts booting from the Live CD image,
		but crashes randomly quite early on in the boot process.
20061122	Beginning on a skeleton interrupt.h and interrupt.c for the
		new interrupt subsystem.
20061124	Continuing on the new interrupt system; taking the first steps
		to attempt to connect CPUs (SuperH and MIPS) and devices
		(dev_cons and SH4 timer interrupts) to it. Many things will
		probably break from now on.
20061125	Converting dev_ns16550, dev_8253 to the new interrupt system.
		Attempting to begin to convert the ISA bus.
20061130	Incorporating a patch from Brian Foley for the configure
		script, which checks for X11 libs in /usr/X11R6/lib64 (which
		is used on some Linux systems).
20061227	Adding a note in the man page about booting from Dreamcast
		CDROM images (i.e. that no external kernel is needed).
20061229	Continuing on the interrupt system rewrite: beginning to
		convert more devices, adding abort() calls for legacy interrupt
		system calls so that everything now _has_ to be rewritten!
		Almost all machine modes are now completely broken.
20061230	More progress on removing old interrupt code, mostly related
		to the ISA bus + devices, the LCA bus (on AlphaBook1), and
		the Footbridge bus (for CATS). And some minor PCI stuff.
		Connecting the ARM cpu to the new interrupt system.
		The CATS, NetWinder, and QEMU_MIPS machine modes now work with
		the new interrupt system :)
20061231	Connecting PowerPC CPUs to the new interrupt system.
		Making PReP machines (IBM 6050) work again.
		Beginning to convert the GT PCI controller (for e.g. Malta
		and Cobalt emulation). Some things work, but not everything.
		Updating Copyright notices for 2007.
20070101	Converting dev_kn02 from legacy style to devinit; the 3max
		machine mode now works with the new interrupt system :-]
20070105	Beginning to convert the SGI O2 machine to the new interrupt
		system; finally converting O2 (IP32) devices to devinit, etc.
20070106	Continuing on the interrupt system redesign/rewrite; KN01
		(PMAX), KN230, and Dreamcast ASIC interrupts should work again,
		moving out stuff from machine.h and devices.h into the
		corresponding devices, beginning the rewrite of i80321
		interrupts, etc.
20070107	Beginning on the rewrite of Eagle interrupt stuff (PReP, etc).
20070117	Beginning the rewrite of Algor (V3) interrupts (finally
		changing dev_v3 into devinit style).
20070118	Removing the "bus" registry concept from machine.h, because
		it was practically meaningless.
		Continuing on the rewrite of Algor V3 ISA interrupts.
20070121	More work on Algor interrupts; they are now working again,
		well enough to run NetBSD/algor. :-)
20070122	Converting VR41xx (HPCmips) interrupts. NetBSD/hpcmips
		can be installed using the new interrupt system :-)
20070123	Making the testmips mode work with the new interrupt system.
20070127	Beginning to convert DEC5800 devices to devinit, and to the
		new interrupt system.
		Converting Playstation 2 devices to devinit, and converting
		the interrupt system. Also fixing a severe bug: the interrupt
		mask register on Playstation 2 is bitwise _toggled_ on writes.
20070128	Removing the dummy NetGear machine mode and the 8250 device
		(which was only used by the NetGear machine).
		Beginning to convert the MacPPC GC (Grand Central) interrupt
		controller to the new interrupt system.
		Converting Jazz interrupts (PICA61 etc.) to the new interrupt
		system. NetBSD/arc can be installed again :-)
		Fixing the JAZZ timer (hardcoding it at 100 Hz, works with
		NetBSD and it is better than a completely dummy timer as it
		was before).
		Converting dev_mp to the new interrupt system, although I
		haven't had time to actually test it yet.
		Completely removing src/machines/interrupts.c, cpu_interrupt
		and cpu_interrupt_ack in src/cpu.c, and
		src/include/machine_interrupts.h! Adding fatal error messages
		+ abort() in the few places that are left to fix.
		Converting dev_z8530 to the new interrupt system.
		FINALLY removing the md_int struct completely from the
		machine struct.
		SH4 fixes (adding a PADDR invalidation in the ITLB replacement
		code in memory_sh.c); the NetBSD/dreamcast LiveCD now runs
		all the way to the login prompt, and can be interacted with :-)
		Converting the CPC700 controller (PCI and interrupt controller
		for PM/PPC) to the new interrupt system.
20070129	Fixing MACE ISA interrupts (SGI IP32 emulation). Both NetBSD/
		sgimips' and OpenBSD/sgi's ramdisk kernels can now be
		interacted with again.
20070130	Moving out the MIPS multi_lw and _sw instruction combinations
		so that they are auto-generated at compile time instead.
20070131	Adding detection of amd64/x86_64 hosts in the configure script,
		for doing initial experiments (again :-) with native code
		generation.
		Adding a -k command line option to set the size of the dyntrans
		cache, and a -B command line option to disable native code
		generation, even if GXemul was compiled with support for
		native code generation for the specific host CPU architecture.
20070201	Experimenting with a skeleton for native code generation.
		Changing the default behaviour, so that native code generation
		is now disabled by default, and has to be enabled by using
		-b on the command line.
20070202	Continuing the native code generation experiments.
		Making PCI interrupts work for Footbridge again.
20070203	More native code generation experiments.
		Removing most of the native code generation experimental code,
		it does not make sense to include any quick hacks like this.
		Minor cleanup/removal of some more legacy MIPS interrupt code.
20070204	Making i80321 interrupts work again (for NetBSD/evbarm etc.),
		and fixing the timer at 100 Hz.
20070206	Experimenting with removing the wdc interrupt slowness hack.
20070207	Lowering the number of dyntrans TLB entries for MIPS from
		192 to 128, resulting in a minor speed improvement.
		Minor optimization to the code invalidation routine in
		cpu_dyntrans.c.
20070208	Increasing (experimentally) the nr of dyntrans instructions per
		loop from 60 to 120.
20070210	Commenting out (experimentally) the dyntrans_device_danger
		detection in memory_rw.c.
		Changing the testmips and baremips machines to use a revision 2
		MIPS64 CPU by default, instead of revision 1.
		Removing the dummy i960, IA64, x86, AVR32, and HP PA-RISC
		files, the PC bios emulation, and the Olivetti M700 (ARC) and
		db64360 emulation modes.
20070211	Adding an "mp" demo to the demos directory, which tests the
		SMP functionality of the testmips machine.
		Fixing PReP interrupts some more. NetBSD/prep now boots again.
20070216	Adding a "nop workaround" for booting Mach/PMAX to the
		documentation; thanks to Artur Bujdoso for the values.
		Converting more of the MacPPC interrupt stuff to the new
		system.
		Beginning to convert BeBox interrupts to the new system.
		PPC603e should NOT have the PPC_NO_DEC flag! Removing it.
		Correcting BeBox clock speed (it was set to 100 in the NetBSD
		bootinfo block, but should be 33000000/4), allowing NetBSD
		to start without using the (incorrect) PPC_NO_DEC hack.
20070217	Implementing (slow) AltiVec vector loads and stores, allowing
		NetBSD/macppc to finally boot using the GENERIC kernel :-)
		Updating the documentation with install instructions for
		NetBSD/macppc.
20070218-19	Regression testing for the release.

==============  RELEASE 0.4.4  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26