/[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 42 - (hide annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 31282 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26