/[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 22 - (show annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 31646 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26