/[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 4 - (show annotations)
Mon Oct 8 16:18:00 2007 UTC (13 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 31427 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.707 2005/04/27 16:37:33 debug Exp $
20050408	Some minor updates to the wdc. Linux now doesn't complain
		anymore if a disk is non-present.
20050409	Various minor fixes (a bintrans bug, and some other things).
		The wdc seems to work with Playstation2 emulation, but there
		is a _long_ annoying delay when disks are detected.
		Fixing a really important bintrans bug (when devices and RAM
		are mixed within 4KB pages), which was triggered with
		NetBSD/playstation2 kernels.
20050410	Adding a dummy dev_ps2_ether (just so that NetBSD doesn't
		complain as much during bootup).
		Symbols starting with '$' are now ignored.
		Renaming dev_ps2_ohci.c to dev_ohci.c, etc.
20050411	Moving the bintrans-cache-isolation check from cpu_mips.c to
		cpu_mips_coproc.c. (I thought this would give a speedup, but
		it's not noticable.)
		Better playstation2 sbus interrupt code.
		Skip ahead many ticks if the count register is read manually.
		(This increases the speed of delay-loops that simply read
		the count register.)
20050412	Updates to the playstation2 timer/interrupt code.
		Some other minor updates.
20050413	NetBSD/cobalt runs from a disk image :-) including userland;
		updating the documentation on how to install NetBSD/cobalt
		using NetBSD/pmax (!).
		Some minor bintrans updates (no real speed improvement) and
		other minor updates (playstation2 now uses the -o options).
20050414	Adding a dummy x86 (and AMD64) mode.
20050415	Adding some (32-bit and 16-bit) x86 instructions.
		Adding some initial support for non-SCSI, non-IDE floppy
		images. (The x86 mode can boot from these, more or less.)
		Moving the devices/ and include/ directories to src/devices/
		and src/include/, respectively.
20050416	Continuing on the x86 stuff. (Adding pc_bios.c and some simple
		support for software interrupts in 16-bit mode.)
20050417	Ripping out most of the x86 instruction decoding stuff, trying
		to rewrite it in a cleaner way.
		Disabling some of the least working CPU families in the
		configure script (sparc, x86, alpha, hppa), so that they are
		not enabled by default.
20050418	Trying to fix the bug which caused problems when turning on
		and off bintrans interactively, by flushing the bintrans cache
		whenever bintrans is manually (re)enabled.
20050419	Adding the 'lswi' ppc instruction.
		Minor updates to the x86 instruction decoding.
20050420	Renaming x86 register name indices from R_xx to X86_R_xx (this
		makes building on Tru64 nicer).
20050422	Adding a check for duplicate MIPS TLB entries on tlbwr/tlbwi.
20050427	Adding screenshots to guestoses.html.
		Some minor fixes and testing for the next release.

==============  RELEASE 0.3.2  ==============


1 /*
2 * Copyright (C) 2003-2005 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.70 2005/03/23 08:45:49 debug Exp $
29 *
30 * 'asc' SCSI controller for some DECstation/DECsystem models, and
31 * for PICA-61.
32 *
33 * Supposed to support SCSI-1 and SCSI-2. I've not yet found any docs
34 * on NCR53C9X, so I'll try to implement this device from LSI53CF92A docs
35 * instead.
36 *
37 *
38 * Memory layout on DECstation:
39 *
40 * NCR53C94 registers at base + 0
41 * DMA address register at base + 0x40000
42 * 128K SRAM buffer at base + 0x80000
43 * ROM at base + 0xc0000
44 *
45 * Memory layout on PICA-61:
46 *
47 * I haven't had time to look this up yet, but length = 0x1000.
48 *
49 *
50 * TODO: This module needs a clean-up, and some testing to see that
51 * it works will all OSes that might use it (NetBSD, OpenBSD,
52 * Ultrix, Linux, Mach, OSF/1, Sprite, ...)
53 */
54
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58
59 #include "cpu.h"
60 #include "devices.h"
61 #include "diskimage.h"
62 #include "machine.h"
63 #include "memory.h"
64 #include "misc.h"
65
66 #include "ncr53c9xreg.h"
67
68
69 /* #define ASC_DEBUG */
70 /* #define debug fatal */
71 /* #define ASC_FULL_REGISTER_ACCESS_DEBUG */
72 /* static int quiet_mode = 0; */
73
74 extern int quiet_mode;
75
76
77 #define ASC_FIFO_LEN 16
78 #define STATE_DISCONNECTED 0
79 #define STATE_INITIATOR 1
80 #define STATE_TARGET 2
81
82 #define PHASE_DATA_OUT 0
83 #define PHASE_DATA_IN 1
84 #define PHASE_COMMAND 2
85 #define PHASE_STATUS 3
86 #define PHASE_MSG_OUT 6
87 #define PHASE_MSG_IN 7
88
89
90 /* The controller's SCSI id: */
91 #define ASC_SCSI_ID 7
92
93 struct asc_data {
94 int mode;
95
96 void *turbochannel;
97 int irq_nr;
98 int irq_caused_last_time;
99
100 /* Current state and transfer: */
101 int cur_state;
102 int cur_phase;
103 struct scsi_transfer *xferp;
104
105 /* FIFO: */
106 unsigned char fifo[ASC_FIFO_LEN];
107 int fifo_in;
108 int fifo_out;
109 int n_bytes_in_fifo; /* cached */
110
111 /* ATN signal: */
112 int atn;
113
114 /* Incoming dma data: */
115 unsigned char *incoming_data;
116 int incoming_len;
117 int incoming_data_addr;
118
119 /* Built-in DMA memory (for DECstation 5000/200): */
120 uint32_t dma_address_reg;
121 unsigned char dma_address_reg_memory[4096];
122 /* NOTE: full page, for bintrans */
123 unsigned char dma[128 * 1024];
124
125 void *dma_controller_data;
126 size_t (*dma_controller)(void *dma_controller_data,
127 unsigned char *data, size_t len, int writeflag);
128
129 /* Read registers and write registers: */
130 uint32_t reg_ro[0x10];
131 uint32_t reg_wo[0x10];
132 };
133
134 /* (READ/WRITE name, if split) */
135 char *asc_reg_names[0x10] = {
136 "NCR_TCL", "NCR_TCM", "NCR_FIFO", "NCR_CMD",
137 "NCR_STAT/NCR_SELID", "NCR_INTR/NCR_TIMEOUT",
138 "NCR_STEP/NCR_SYNCTP", "NCR_FFLAG/NCR_SYNCOFF",
139 "NCR_CFG1", "NCR_CCF", "NCR_TEST", "NCR_CFG2",
140 "NCR_CFG3", "reg_0xd", "NCR_TCH", "reg_0xf"
141 };
142
143
144 /* This is referenced below. */
145 static int dev_asc_select(struct cpu *cpu, struct asc_data *d, int from_id,
146 int to_id, int dmaflag, int n_messagebytes);
147
148
149 /*
150 * dev_asc_tick():
151 *
152 * This function is called "every now and then" from the CPU
153 * main loop.
154 */
155 void dev_asc_tick(struct cpu *cpu, void *extra)
156 {
157 struct asc_data *d = extra;
158
159 if (d->reg_ro[NCR_STAT] & NCRSTAT_INT)
160 cpu_interrupt(cpu, d->irq_nr);
161 }
162
163
164 /*
165 * dev_asc_fifo_flush():
166 *
167 * Flush the fifo.
168 */
169 static void dev_asc_fifo_flush(struct asc_data *d)
170 {
171 d->fifo[0] = 0x00;
172 d->fifo_in = 0;
173 d->fifo_out = 0;
174 d->n_bytes_in_fifo = 0;
175 }
176
177
178 /*
179 * dev_asc_reset():
180 *
181 * Reset the state of the asc.
182 */
183 static void dev_asc_reset(struct asc_data *d)
184 {
185 d->cur_state = STATE_DISCONNECTED;
186 d->atn = 0;
187
188 if (d->xferp != NULL)
189 scsi_transfer_free(d->xferp);
190 d->xferp = NULL;
191
192 dev_asc_fifo_flush(d);
193
194 /* According to table 4.1 in the LSI53CF92A manual: */
195 memset(d->reg_wo, 0, sizeof(d->reg_wo));
196 d->reg_wo[NCR_TCH] = 0x94;
197 d->reg_wo[NCR_CCF] = 2;
198 memcpy(d->reg_ro, d->reg_wo, sizeof(d->reg_ro));
199 d->reg_wo[NCR_SYNCTP] = 5;
200 }
201
202
203 /*
204 * dev_asc_fifo_read():
205 *
206 * Read a byte from the asc FIFO.
207 */
208 static int dev_asc_fifo_read(struct asc_data *d)
209 {
210 int res = d->fifo[d->fifo_out];
211
212 if (d->fifo_in == d->fifo_out)
213 fatal("dev_asc: WARNING! FIFO overrun!\n");
214
215 d->fifo_out = (d->fifo_out + 1) % ASC_FIFO_LEN;
216 d->n_bytes_in_fifo --;
217
218 return res;
219 }
220
221
222 /*
223 * dev_asc_fifo_write():
224 *
225 * Write a byte to the asc FIFO.
226 */
227 static void dev_asc_fifo_write(struct asc_data *d, unsigned char data)
228 {
229 d->fifo[d->fifo_in] = data;
230 d->fifo_in = (d->fifo_in + 1) % ASC_FIFO_LEN;
231 d->n_bytes_in_fifo ++;
232
233 if (d->fifo_in == d->fifo_out)
234 fatal("dev_asc: WARNING! FIFO overrun on write!\n");
235 }
236
237
238 /*
239 * dev_asc_newxfer():
240 *
241 * Allocate memory for a new transfer.
242 */
243 static void dev_asc_newxfer(struct asc_data *d)
244 {
245 if (d->xferp != NULL) {
246 printf("WARNING! dev_asc_newxfer(): freeing previous"
247 " transfer\n");
248 scsi_transfer_free(d->xferp);
249 d->xferp = NULL;
250 }
251
252 d->xferp = scsi_transfer_alloc();
253 #if 0
254 d->xferp->get_data_out = dev_asc_get_data_out;
255 d->xferp->gdo_extra = (void *) d;
256 #endif
257 }
258
259
260 /*
261 * dev_asc_transfer():
262 *
263 * Transfer data from a SCSI device to the controller (or vice versa),
264 * depending on the current phase.
265 *
266 * Returns 1 if ok, 0 on error.
267 */
268 static int dev_asc_transfer(struct cpu *cpu, struct asc_data *d, int dmaflag)
269 {
270 int res = 1, all_done = 1;
271 int len, i, ch;
272
273 if (!quiet_mode)
274 debug(" { TRANSFER to/from id %i: ", d->reg_wo[NCR_SELID] & 7);
275
276 if (d->cur_phase == PHASE_DATA_IN) {
277 /* Data coming into the controller from external device: */
278 if (!dmaflag) {
279 if (d->xferp->data_in == NULL) {
280 fatal("no incoming data?\n");
281 res = 0;
282 } else {
283 /* TODO */
284 fatal("TODO..............\n");
285 len = d->reg_wo[NCR_TCL] +
286 d->reg_wo[NCR_TCM] * 256;
287
288 len--;
289 ch = d->incoming_data[d->incoming_data_addr];
290 debug(" %02x", ch);
291
292 d->incoming_data_addr ++;
293 dev_asc_fifo_write(d, ch);
294
295 if (len == 0) {
296 free(d->incoming_data);
297 d->incoming_data = NULL;
298 }
299
300 d->reg_ro[NCR_TCL] = len & 255;
301 d->reg_ro[NCR_TCM] = (len >> 8) & 255;
302 }
303 } else {
304 /* Copy from the incoming data into dma memory: */
305 if (d->xferp->data_in == NULL) {
306 fatal("no incoming DMA data?\n");
307 res = 0;
308 } else {
309 int len = d->xferp->data_in_len;
310 int len2 = d->reg_wo[NCR_TCL] +
311 d->reg_wo[NCR_TCM] * 256;
312 if (len2 == 0)
313 len2 = 65536;
314
315 if (len < len2) {
316 fatal("{ asc: data in, len=%i len2=%i "
317 "}\n", len, len2);
318 }
319
320 /* TODO: check len2 in a similar way? */
321 if (len + (d->dma_address_reg &
322 ((sizeof(d->dma)-1))) > sizeof(d->dma))
323 len = sizeof(d->dma) -
324 (d->dma_address_reg &
325 ((sizeof(d->dma)-1)));
326
327 if (len2 > len) {
328 memset(d->dma + (d->dma_address_reg &
329 ((sizeof(d->dma)-1))), 0, len2);
330 len2 = len;
331 }
332
333 #ifdef ASC_DEBUG
334 if (!quiet_mode) {
335 int i;
336 for (i=0; i<len; i++)
337 debug(" %02x", d->xferp->
338 data_in[i]);
339 }
340 #endif
341
342 /*
343 * Are we using an external DMA controller?
344 * Then use it. Otherwise place the data in
345 * the DECstation 5000/200 built-in DMA
346 * region.
347 */
348 if (d->dma_controller != NULL)
349 d->dma_controller(
350 d->dma_controller_data,
351 d->xferp->data_in,
352 len2, 1);
353 else
354 memcpy(d->dma + (d->dma_address_reg &
355 ((sizeof(d->dma)-1))),
356 d->xferp->data_in, len2);
357
358 if (d->xferp->data_in_len > len2) {
359 unsigned char *n;
360
361 if (d->dma_controller != NULL)
362 printf("WARNING!!!!!!!!! BUG!!!! Unexpected stuff..."
363 "len2=%i d->xferp->data_in_len=%i\n", (int)len2,
364 (int)d->xferp->data_in_len);
365
366 all_done = 0;
367 /* fatal("{ asc: multi-transfer"
368 " data_in, len=%i len2=%i }\n",
369 (int)len, (int)len2); */
370
371 d->xferp->data_in_len -= len2;
372 n = malloc(d->xferp->data_in_len);
373 if (n == NULL) {
374 fprintf(stderr, "out of memory"
375 " in dev_asc\n");
376 exit(1);
377 }
378 memcpy(n, d->xferp->data_in + len2,
379 d->xferp->data_in_len);
380 free(d->xferp->data_in);
381 d->xferp->data_in = n;
382
383 len = len2;
384 }
385
386 len = 0;
387
388 d->reg_ro[NCR_TCL] = len & 255;
389 d->reg_ro[NCR_TCM] = (len >> 8) & 255;
390
391 /* Successful DMA transfer: */
392 d->reg_ro[NCR_STAT] |= NCRSTAT_TC;
393 }
394 }
395 } else if (d->cur_phase == PHASE_DATA_OUT) {
396 /* Data going from the controller to an external device: */
397 if (!dmaflag) {
398 fatal("TODO.......asdgasin\n");
399 } else {
400 /* Copy data from DMA to data_out: */
401 int len = d->xferp->data_out_len;
402 int len2 = d->reg_wo[NCR_TCL] +
403 d->reg_wo[NCR_TCM] * 256;
404 if (len2 == 0)
405 len2 = 65536;
406
407 if (len == 0) {
408 fprintf(stderr, "d->xferp->data_out_len == "
409 "0 ?\n");
410 exit(1);
411 }
412
413 /* TODO: Make sure that len2 doesn't go outside
414 of the dma memory? */
415
416 /* fatal(" data out offset=%5i len=%5i\n",
417 d->xferp->data_out_offset, len2); */
418
419 if (d->xferp->data_out_offset + len2 >
420 d->xferp->data_out_len) {
421 len2 = d->xferp->data_out_len -
422 d->xferp->data_out_offset;
423 }
424
425 /*
426 * Are we using an external DMA controller? Then use
427 * it. Otherwise place the data in the DECstation
428 * 5000/200 built-in DMA region.
429 */
430 if (d->xferp->data_out == NULL) {
431 scsi_transfer_allocbuf(&d->xferp->data_out_len,
432 &d->xferp->data_out, len, 0);
433
434 if (d->dma_controller != NULL)
435 d->dma_controller(
436 d->dma_controller_data,
437 d->xferp->data_out,
438 len2, 0);
439 else
440 memcpy(d->xferp->data_out,
441 d->dma + (d->dma_address_reg &
442 ((sizeof(d->dma)-1))), len2);
443 d->xferp->data_out_offset = len2;
444 } else {
445 /* Continuing a multi-transfer: */
446 if (d->dma_controller != NULL)
447 d->dma_controller(
448 d->dma_controller_data,
449 d->xferp->data_out +
450 d->xferp->data_out_offset,
451 len2, 0);
452 else
453 memcpy(d->xferp->data_out +
454 d->xferp->data_out_offset,
455 d->dma + (d->dma_address_reg &
456 ((sizeof(d->dma)-1))), len2);
457 d->xferp->data_out_offset += len2;
458 }
459
460 /* If the disk wants more than we're DMAing,
461 then this is a multitransfer: */
462 if (d->xferp->data_out_offset !=
463 d->xferp->data_out_len) {
464 if (!quiet_mode)
465 debug("[ asc: data_out, multitransfer "
466 "len = %i, len2 = %i ]\n",
467 (int)len, (int)len2);
468 if (d->xferp->data_out_offset >
469 d->xferp->data_out_len)
470 fatal("[ asc data_out dma: too much?"
471 " ]\n");
472 else
473 all_done = 0;
474 }
475
476 #ifdef ASC_DEBUG
477 if (!quiet_mode) {
478 int i;
479 for (i=0; i<len; i++)
480 debug(" %02x", d->xferp->data_out[i]);
481 }
482 #endif
483 len = 0;
484
485 d->reg_ro[NCR_TCL] = len & 255;
486 d->reg_ro[NCR_TCM] = (len >> 8) & 255;
487
488 /* Successful DMA transfer: */
489 d->reg_ro[NCR_STAT] |= NCRSTAT_TC;
490 }
491 } else if (d->cur_phase == PHASE_MSG_OUT) {
492 if (!quiet_mode)
493 debug("MSG OUT: ");
494 /* Data going from the controller to an external device: */
495 if (!dmaflag) {
496 /* There should already be one byte in msg_out, so we
497 just extend the message: */
498 int oldlen = d->xferp->msg_out_len;
499 int newlen;
500
501 if (oldlen != 1) {
502 fatal(" (PHASE OUT MSG len == %i, "
503 "should be 1)\n", oldlen);
504 }
505
506 newlen = oldlen + d->n_bytes_in_fifo;
507 d->xferp->msg_out = realloc(d->xferp->msg_out, newlen);
508 d->xferp->msg_out_len = newlen;
509 if (d->xferp->msg_out == NULL) {
510 fprintf(stderr, "out of memory realloc'ing "
511 "msg_out\n");
512 exit(1);
513 }
514
515 i = oldlen;
516 while (d->fifo_in != d->fifo_out) {
517 ch = dev_asc_fifo_read(d);
518 d->xferp->msg_out[i++] = ch;
519 #ifdef ASC_DEBUG
520 debug("0x%02x ", ch);
521 #endif
522 }
523
524 #ifdef MACH
525 /* Super-ugly hack for Mach/PMAX: TODO: make nicer */
526 if (d->xferp->msg_out_len == 6 &&
527 (d->xferp->msg_out[0] == 0x80 ||
528 d->xferp->msg_out[0] == 0xc0) &&
529 d->xferp->msg_out[1] == 0x01 &&
530 d->xferp->msg_out[2] == 0x03 &&
531 d->xferp->msg_out[3] == 0x01 &&
532 d->xferp->msg_out[4] == 0x32 &&
533 d->xferp->msg_out[5] == 0x0f) {
534 fatal(" !! Mach/PMAX hack !! ");
535 all_done = 0;
536 d->cur_phase = PHASE_MSG_IN;
537 }
538 #endif
539 } else {
540 /* Copy data from DMA to msg_out: */
541 fatal("[ DMA MSG OUT: xxx TODO! ]");
542 /* TODO */
543 res = 0;
544 }
545 } else if (d->cur_phase == PHASE_MSG_IN) {
546 if (!quiet_mode)
547 debug(" MSG IN");
548 fatal("[ MACH HACK! ]");
549 /* Super-ugly hack for Mach/PMAX: TODO: make nicer */
550 dev_asc_fifo_write(d, 0x07);
551 d->cur_phase = PHASE_COMMAND;
552 all_done = 0;
553 } else if (d->cur_phase == PHASE_COMMAND) {
554 if (!quiet_mode)
555 debug(" COMMAND ==> select ");
556 res = dev_asc_select(cpu, d, d->reg_ro[NCR_CFG1] & 7,
557 d->reg_wo[NCR_SELID] & 7, dmaflag, 0);
558 return res;
559 } else {
560 fatal("!!! TODO: unknown/unimplemented phase "
561 "in transfer: %i\n", d->cur_phase);
562 }
563
564 /* Redo the command if data was just sent using DATA_OUT: */
565 if (d->cur_phase == PHASE_DATA_OUT) {
566 res = diskimage_scsicommand(cpu,
567 d->reg_wo[NCR_SELID] & 7, d->xferp);
568 }
569
570 if (all_done) {
571 if (d->cur_phase == PHASE_MSG_OUT)
572 d->cur_phase = PHASE_COMMAND;
573 else
574 d->cur_phase = PHASE_STATUS;
575 }
576
577 /*
578 * Cause an interrupt after the transfer:
579 *
580 * NOTE: Earlier I had this in here as well:
581 * d->reg_ro[NCR_INTR] |= NCRINTR_FC;
582 * but Linux/DECstation and OpenBSD/pmax seems to choke on that.
583 */
584 d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
585 d->reg_ro[NCR_INTR] |= NCRINTR_BS;
586 d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | d->cur_phase;
587 d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 4; /* 4? */
588
589 if (!quiet_mode)
590 debug("}");
591 return res;
592 }
593
594
595 /*
596 * dev_asc_select():
597 *
598 * Select a SCSI device, send msg bytes (if any), and send command bytes.
599 * (Call diskimage_scsicommand() to handle the command.)
600 *
601 * Return value: 1 if ok, 0 on error.
602 */
603 static int dev_asc_select(struct cpu *cpu, struct asc_data *d, int from_id,
604 int to_id, int dmaflag, int n_messagebytes)
605 {
606 int ok, len, i, ch;
607
608 if (!quiet_mode)
609 debug(" { SELECT id %i: ", to_id);
610
611 /*
612 * Message bytes, if any:
613 */
614 if (!quiet_mode)
615 debug("msg:");
616
617 if (n_messagebytes > 0) {
618 scsi_transfer_allocbuf(&d->xferp->msg_out_len,
619 &d->xferp->msg_out, n_messagebytes, 0);
620
621 i = 0;
622 while (n_messagebytes-- > 0) {
623 int ch = dev_asc_fifo_read(d);
624 if (!quiet_mode)
625 debug(" %02x", ch);
626 d->xferp->msg_out[i++] = ch;
627 }
628
629 if ((d->xferp->msg_out[0] & 0x7) != 0x00) {
630 debug(" (LUNs not implemented yet: 0x%02x) }",
631 d->xferp->msg_out[0]);
632 return 0;
633 }
634
635 if (((d->xferp->msg_out[0] & ~0x7) != 0xc0) &&
636 ((d->xferp->msg_out[0] & ~0x7) != 0x80)) {
637 fatal(" (Unimplemented msg out: 0x%02x) }",
638 d->xferp->msg_out[0]);
639 return 0;
640 }
641
642 if (d->xferp->msg_out_len > 1) {
643 fatal(" (Long msg out, not implemented yet;"
644 " len=%i) }", d->xferp->msg_out_len);
645 return 0;
646 }
647 } else {
648 if (!quiet_mode)
649 debug(" none");
650 }
651
652 /* Special case: SELATNS (with STOP sequence): */
653 if (d->cur_phase == PHASE_MSG_OUT) {
654 if (!quiet_mode)
655 debug(" MSG OUT DEBUG");
656 if (d->xferp->msg_out_len != 1) {
657 fatal(" (SELATNS: msg out len == %i, should be 1)",
658 d->xferp->msg_out_len);
659 return 0;
660 }
661
662 /* d->cur_phase = PHASE_COMMAND; */
663
664 /* According to the LSI manual: */
665 d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
666 d->reg_ro[NCR_INTR] |= NCRINTR_FC;
667 d->reg_ro[NCR_INTR] |= NCRINTR_BS;
668 d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | d->cur_phase;
669 d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 1;
670
671 if (!quiet_mode)
672 debug("}");
673 return 1;
674 }
675
676 /*
677 * Command bytes:
678 */
679 if (!quiet_mode)
680 debug(", cmd: ");
681
682 if (!dmaflag) {
683 if (!quiet_mode)
684 debug("[non-DMA] ");
685
686 scsi_transfer_allocbuf(&d->xferp->cmd_len,
687 &d->xferp->cmd, d->n_bytes_in_fifo, 0);
688
689 i = 0;
690 while (d->fifo_in != d->fifo_out) {
691 ch = dev_asc_fifo_read(d);
692 d->xferp->cmd[i++] = ch;
693 if (!quiet_mode)
694 debug("%02x ", ch);
695 }
696 } else {
697 if (!quiet_mode)
698 debug("[DMA] ");
699 len = d->reg_wo[NCR_TCL] + d->reg_wo[NCR_TCM] * 256;
700 if (len == 0)
701 len = 65536;
702
703 scsi_transfer_allocbuf(&d->xferp->cmd_len,
704 &d->xferp->cmd, len, 0);
705
706 for (i=0; i<len; i++) {
707 int ofs = d->dma_address_reg + i;
708 ch = d->dma[ofs & (sizeof(d->dma)-1)];
709 d->xferp->cmd[i] = ch;
710 if (!quiet_mode)
711 debug("%02x ", ch);
712 }
713
714 d->reg_ro[NCR_TCL] = len & 255;
715 d->reg_ro[NCR_TCM] = (len >> 8) & 255;
716
717 d->reg_ro[NCR_STAT] |= NCRSTAT_TC;
718 }
719
720 /*
721 * Call the SCSI device to perform the command:
722 */
723 ok = diskimage_scsicommand(cpu, to_id, d->xferp);
724
725
726 /* Cause an interrupt: */
727 d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
728 d->reg_ro[NCR_INTR] |= NCRINTR_FC;
729 d->reg_ro[NCR_INTR] |= NCRINTR_BS;
730
731 if (ok == 2)
732 d->cur_phase = PHASE_DATA_OUT;
733 else if (d->xferp->data_in != NULL)
734 d->cur_phase = PHASE_DATA_IN;
735 else
736 d->cur_phase = PHASE_STATUS;
737
738 d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | d->cur_phase;
739 d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 4; /* DONE (?) */
740
741 if (!quiet_mode)
742 debug("}");
743
744 return ok;
745 }
746
747
748 /*
749 * dev_asc_address_reg_access():
750 */
751 int dev_asc_address_reg_access(struct cpu *cpu, struct memory *mem,
752 uint64_t relative_addr, unsigned char *data, size_t len,
753 int writeflag, void *extra)
754 {
755 struct asc_data *d = extra;
756
757 if (relative_addr + len > 4)
758 return 0;
759
760 if (writeflag==MEM_READ) {
761 memcpy(data, d->dma_address_reg_memory + relative_addr, len);
762 } else {
763 memcpy(d->dma_address_reg_memory + relative_addr, data, len);
764 }
765
766 return 1;
767 }
768
769
770 /*
771 * dev_asc_dma_access():
772 */
773 int dev_asc_dma_access(struct cpu *cpu, struct memory *mem,
774 uint64_t relative_addr, unsigned char *data, size_t len,
775 int writeflag, void *extra)
776 {
777 struct asc_data *d = extra;
778
779 if (writeflag==MEM_READ) {
780 memcpy(data, d->dma + relative_addr, len);
781 #ifdef ASC_DEBUG
782 {
783 int i;
784 debug("[ asc: read from DMA addr 0x%05x:",
785 (int) relative_addr);
786 for (i=0; i<len; i++)
787 debug(" %02x", data[i]);
788 debug(" ]\n");
789 }
790 #endif
791
792 /* Don't return the common way, as that
793 would overwrite data. */
794 return 1;
795 } else {
796 memcpy(d->dma + relative_addr, data, len);
797 #ifdef ASC_DEBUG
798 {
799 int i;
800 debug("[ asc: write to DMA addr 0x%05x:",
801 (int) relative_addr);
802 for (i=0; i<len; i++)
803 debug(" %02x", data[i]);
804 debug(" ]\n");
805 }
806 #endif
807 /* Quick return. */
808 return 1;
809 }
810 }
811
812
813 /*
814 * dev_asc_access():
815 */
816 int dev_asc_access(struct cpu *cpu, struct memory *mem,
817 uint64_t relative_addr, unsigned char *data, size_t len,
818 int writeflag, void *extra)
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
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);
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_controller = dma_controller;
1265 d->dma_controller_data = dma_controller_data;
1266
1267 memory_device_register(mem, "asc", baseaddr,
1268 mode == DEV_ASC_PICA?
1269 DEV_ASC_PICA_LENGTH : DEV_ASC_DEC_LENGTH,
1270 dev_asc_access, d, MEM_DEFAULT, NULL);
1271
1272 if (mode == DEV_ASC_DEC) {
1273 memory_device_register(mem, "asc_dma_address_reg",
1274 baseaddr + 0x40000, 4096, dev_asc_address_reg_access, d,
1275 MEM_BINTRANS_OK | MEM_BINTRANS_WRITE_OK,
1276 d->dma_address_reg_memory);
1277 memory_device_register(mem, "asc_dma", baseaddr + 0x80000,
1278 128*1024, dev_asc_dma_access, d,
1279 MEM_BINTRANS_OK | MEM_BINTRANS_WRITE_OK, d->dma);
1280 }
1281
1282 machine_add_tickfunction(machine, dev_asc_tick, d, 15);
1283 }
1284

  ViewVC Help
Powered by ViewVC 1.1.26