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

Contents of /trunk/src/devices/dev_asc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (show 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 /*
2 * Copyright (C) 2003-2007 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: dev_asc.c,v 1.86 2007/06/15 18:44:19 debug Exp $
29 *
30 * COMMENT: NCR53C9X "ASC" SCSI controller
31 *
32 * This is the SCSI controller used in some DECstation/DECsystem models and
33 * the PICA-61 machine.
34 *
35 * 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 *
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 */
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 #define ASC_TICK_SHIFT 15
81
82 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 #define ASC_DMA_SIZE (128*1024)
102
103 struct asc_data {
104 int mode;
105
106 void *turbochannel;
107 struct interrupt irq;
108 int irq_asserted;
109
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 unsigned char *dma_address_reg_memory;
132 unsigned char *dma;
133
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 DEVICE_TICK(asc)
159 {
160 struct asc_data *d = extra;
161 int new_assert = d->reg_ro[NCR_STAT] & NCRSTAT_INT;
162
163 if (new_assert && !d->irq_asserted)
164 INTERRUPT_ASSERT(d->irq);
165
166 d->irq_asserted = new_assert;
167 }
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 size_t len = d->xferp->data_in_len;
316 size_t len2 = d->reg_wo[NCR_TCL] +
317 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 (ASC_DMA_SIZE-1)) > ASC_DMA_SIZE)
329 len = ASC_DMA_SIZE -
330 (d->dma_address_reg &
331 (ASC_DMA_SIZE-1));
332
333 if (len2 > len) {
334 memset(d->dma + (d->dma_address_reg &
335 (ASC_DMA_SIZE-1)), 0, len2);
336 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 (ASC_DMA_SIZE-1)),
362 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 CHECK_ALLOCATION(n =
379 malloc(d->xferp->data_in_len));
380 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 (ASC_DMA_SIZE-1)), len2);
445 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 (ASC_DMA_SIZE-1)), len2);
459 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 CHECK_ALLOCATION(d->xferp->msg_out =
510 realloc(d->xferp->msg_out, newlen));
511 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 res = diskimage_scsicommand(cpu, d->reg_wo[NCR_SELID] & 7,
565 DISKIMAGE_SCSI, d->xferp);
566 }
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 ch = d->dma[ofs & (ASC_DMA_SIZE-1)];
707 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 ok = diskimage_scsicommand(cpu, to_id, DISKIMAGE_SCSI, d->xferp);
722
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 DEVICE_ACCESS(asc_address_reg)
747 {
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 DEVICE_ACCESS(asc_dma)
764 {
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 DEVICE_ACCESS(asc)
802 {
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 if (writeflag == MEM_WRITE)
810 idata = memory_readmax64(cpu, data, len);
811
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 d->reg_wo[NCR_SELID] & 7, DISKIMAGE_SCSI);
1059
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 INTERRUPT_DEASSERT(d->irq);
1198 d->irq_asserted = 0;
1199 }
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 uint64_t baseaddr, char *irq_path, void *turbochannel, int mode,
1229 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 CHECK_ALLOCATION(d = malloc(sizeof(struct asc_data)));
1236 memset(d, 0, sizeof(struct asc_data));
1237
1238 INTERRUPT_CONNECT(irq_path, d->irq);
1239 d->turbochannel = turbochannel;
1240 d->mode = mode;
1241
1242 d->reg_ro[NCR_CFG3] = NCRF9XCFG3_CDB;
1243
1244 CHECK_ALLOCATION(d->dma_address_reg_memory =
1245 malloc(machine->arch_pagesize));
1246 memset(d->dma_address_reg_memory, 0, machine->arch_pagesize);
1247
1248 CHECK_ALLOCATION(d->dma = malloc(ASC_DMA_SIZE));
1249 memset(d->dma, 0, ASC_DMA_SIZE);
1250
1251 d->dma_controller = dma_controller;
1252 d->dma_controller_data = dma_controller_data;
1253
1254 memory_device_register(mem, "asc", baseaddr,
1255 mode == DEV_ASC_PICA? DEV_ASC_PICA_LENGTH : DEV_ASC_DEC_LENGTH,
1256 dev_asc_access, d, DM_DEFAULT, NULL);
1257
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 DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK,
1262 (unsigned char *)&d->dma_address_reg_memory[0]);
1263 memory_device_register(mem, "asc_dma", baseaddr + 0x80000,
1264 ASC_DMA_SIZE, dev_asc_dma_access, d,
1265 DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK, d->dma);
1266 }
1267
1268 machine_add_tickfunction(machine, dev_asc_tick, d, ASC_TICK_SHIFT);
1269 }
1270

  ViewVC Help
Powered by ViewVC 1.1.26