/[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 28 - (show annotations)
Mon Oct 8 16:20:26 2007 UTC (13 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 31410 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1298 2006/07/22 11:27:46 debug Exp $
20060626	Continuing on SPARC emulation (beginning on the 'save'
		instruction, register windows, etc).
20060629	Planning statistics gathering (new -s command line option),
		and renaming speed_tricks to allow_instruction_combinations.
20060630	Some minor manual page updates.
		Various cleanups.
		Implementing the -s command line option.
20060701	FINALLY found the bug which prevented Linux and Ultrix from
		running without the ugly hack in the R2000/R3000 cache isol
		code; it was the phystranslation hint array which was buggy.
		Removing the phystranslation hint code completely, for now.
20060702	Minor dyntrans cleanups; invalidation of physpages now only
		invalidate those parts of a page that have actually been
		translated. (32 parts per page.)
		Some MIPS non-R3000 speed fixes.
		Experimenting with MIPS instruction combination for some
		addiu+bne+sw loops, and sw+sw+sw.
		Adding support (again) for larger-than-4KB pages in MIPS tlbw*.
		Continuing on SPARC emulation: adding load/store instructions.
20060704	Fixing a virtual vs physical page shift bug in the new tlbw*
		implementation. Problem noticed by Jakub Jermar. (Many thanks.)
		Moving rfe and eret to cpu_mips_instr.c, since that is the
		only place that uses them nowadays.
20060705	Removing the BSD license from the "testmachine" include files,
		placing them in the public domain instead; this enables the
		testmachine stuff to be used from projects which are
		incompatible with the BSD license for some reason.
20060707	Adding instruction combinations for the R2000/R3000 L1
		I-cache invalidation code used by NetBSD/pmax 3.0, lui+addiu,
		various branches followed by addiu or nop, and jr ra followed
		by addiu. The time it takes to perform a full NetBSD/pmax R3000
		install on the laptop has dropped from 573 seconds to 539. :-)
20060708	Adding a framebuffer controller device (dev_fbctrl), which so
		far can be used to change the fb resolution during runtime, but
		in the future will also be useful for accelerated block fill/
		copy, and possibly also simplified character output.
		Adding an instruction combination for NetBSD/pmax' strlen.
20060709	Minor fixes: reading raw files in src/file.c wasn't memblock
		aligned, removing buggy multi_sw MIPS instruction combination,
		etc.
20060711	Adding a machine_qemu.c, which contains a "qemu_mips" machine.
		(It mimics QEMU's MIPS machine mode, so that a test kernel
		made for QEMU_MIPS also can run in GXemul... at least to some
		extent.)  Adding a short section about how to run this mode to
		doc/guestoses.html.
20060714	Misc. minor code cleanups.
20060715	Applying a patch which adds getchar() to promemul/yamon.c
		(from Oleksandr Tymoshenko).
		Adding yamon.h from NetBSD, and rewriting yamon.c to use it
		(instead of ugly hardcoded numbers) + some cleanup.
20060716	Found and fixed the bug which broke single-stepping of 64-bit
		programs between 0.4.0 and 0.4.0.1 (caused by too quick
		refactoring and no testing). Hopefully this fix will not
		break too many other things.
20060718	Continuing on the 8253 PIT; it now works with Linux/QEMU_MIPS.
		Re-adding the sw+sw+sw instr comb (the problem was that I had
		ignored endian issues); however, it doesn't seem to give any
		big performance gain.
20060720	Adding a dummy Transputer mode (T414, T800 etc) skeleton (only
		the 'j' and 'ldc' instructions are implemented so far). :-}
20060721	Adding gtreg.h from NetBSD, updating dev_gt.c to use it, plus
		misc. other updates to get Linux 2.6 for evbmips/malta working
		(thanks to Alec Voropay for the details).
		FINALLY found and fixed the bug which made tlbw* for non-R3000
		buggy; it was a reference count problem in the dyntrans core.
20060722	Testing stuff; things seem stable enough for a new release.

==============  RELEASE 0.4.1  ==============


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.81 2006/07/21 16:55:41 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 DEVICE_TICK(asc)
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 size_t len = d->xferp->data_in_len;
310 size_t 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 (ASC_DMA_SIZE-1)) > ASC_DMA_SIZE)
323 len = ASC_DMA_SIZE -
324 (d->dma_address_reg &
325 (ASC_DMA_SIZE-1));
326
327 if (len2 > len) {
328 memset(d->dma + (d->dma_address_reg &
329 (ASC_DMA_SIZE-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 (ASC_DMA_SIZE-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 (ASC_DMA_SIZE-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 (ASC_DMA_SIZE-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, d->reg_wo[NCR_SELID] & 7,
567 DISKIMAGE_SCSI, 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 & (ASC_DMA_SIZE-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, DISKIMAGE_SCSI, 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 DEVICE_ACCESS(asc_address_reg)
749 {
750 struct asc_data *d = extra;
751
752 if (relative_addr + len > 4)
753 return 0;
754
755 if (writeflag==MEM_READ) {
756 memcpy(data, d->dma_address_reg_memory + relative_addr, len);
757 } else {
758 memcpy(d->dma_address_reg_memory + relative_addr, data, len);
759 }
760
761 return 1;
762 }
763
764
765 DEVICE_ACCESS(asc_dma)
766 {
767 struct asc_data *d = extra;
768
769 if (writeflag==MEM_READ) {
770 memcpy(data, d->dma + relative_addr, len);
771 #ifdef ASC_DEBUG
772 {
773 int i;
774 debug("[ asc: read from DMA addr 0x%05x:",
775 (int) relative_addr);
776 for (i=0; i<len; i++)
777 debug(" %02x", data[i]);
778 debug(" ]\n");
779 }
780 #endif
781
782 /* Don't return the common way, as that
783 would overwrite data. */
784 return 1;
785 } else {
786 memcpy(d->dma + relative_addr, data, len);
787 #ifdef ASC_DEBUG
788 {
789 int i;
790 debug("[ asc: write to DMA addr 0x%05x:",
791 (int) relative_addr);
792 for (i=0; i<len; i++)
793 debug(" %02x", data[i]);
794 debug(" ]\n");
795 }
796 #endif
797 /* Quick return. */
798 return 1;
799 }
800 }
801
802
803 DEVICE_ACCESS(asc)
804 {
805 int regnr;
806 struct asc_data *d = extra;
807 int target_exists;
808 int n_messagebytes = 0;
809 uint64_t idata = 0, odata = 0;
810
811 if (writeflag == MEM_WRITE)
812 idata = memory_readmax64(cpu, data, len);
813
814 #if 0
815 /* Debug stuff useful when trying to make dev_asc compatible
816 with the 'arc' emulation mode, which is different from
817 the DECstation mode. */
818 fatal("[ asc: writeflag=%i addr=%08x idata=%016llx ]\n",
819 writeflag, (int)relative_addr, (long long)idata);
820 #endif
821
822 switch (d->mode) {
823 case DEV_ASC_DEC:
824 regnr = relative_addr / 4;
825 break;
826 case DEV_ASC_PICA:
827 default:
828 regnr = relative_addr;
829 }
830
831 /* Controller's ID is fixed: */
832 d->reg_ro[NCR_CFG1] = (d->reg_ro[NCR_CFG1] & ~7) | ASC_SCSI_ID;
833
834 d->reg_ro[NCR_FFLAG] = ((d->reg_ro[NCR_STEP] & 0x7) << 5)
835 + d->n_bytes_in_fifo;
836
837 d->dma_address_reg =
838 d->dma_address_reg_memory[0] +
839 (d->dma_address_reg_memory[1] << 8) +
840 (d->dma_address_reg_memory[2] << 16) +
841 (d->dma_address_reg_memory[3] << 24);
842
843 if (regnr < 0x10) {
844 if (regnr == NCR_FIFO) {
845 if (writeflag == MEM_WRITE)
846 dev_asc_fifo_write(d, idata);
847 else
848 odata = dev_asc_fifo_read(d);
849 } else {
850 if (writeflag==MEM_WRITE)
851 d->reg_wo[regnr] = idata;
852 else
853 odata = d->reg_ro[regnr];
854 }
855
856 #ifdef ASC_FULL_REGISTER_ACCESS_DEBUG
857 if (!quiet_mode) {
858 if (writeflag==MEM_READ) {
859 debug("[ asc: read from %s: 0x%02x",
860 asc_reg_names[regnr], (int)odata);
861 } else {
862 debug("[ asc: write to %s: 0x%02x",
863 asc_reg_names[regnr], (int)idata);
864 }
865 }
866 #endif
867 } else if (relative_addr >= 0x300 && relative_addr < 0x600
868 && d->turbochannel != NULL) {
869 debug("[ asc: offset 0x%x, redirecting to turbochannel"
870 " access ]\n", relative_addr);
871 return dev_turbochannel_access(cpu, mem,
872 relative_addr, data, len, writeflag,
873 d->turbochannel);
874 } else {
875 if (writeflag==MEM_READ) {
876 fatal("[ asc: read from 0x%04x: 0x%02x ]\n",
877 relative_addr, (int)odata);
878 } else {
879 fatal("[ asc: write to 0x%04x: 0x%02x ]\n",
880 relative_addr, (int)idata);
881 }
882 }
883
884 /*
885 * Some registers are read/write. Copy contents of
886 * reg_wo to reg_ro:
887 */
888 #if 0
889 d->reg_ro[ 0] = d->reg_wo[0]; /* Transfer count lo and */
890 d->reg_ro[ 1] = d->reg_wo[1]; /* middle */
891 #endif
892 d->reg_ro[ 2] = d->reg_wo[2];
893 d->reg_ro[ 3] = d->reg_wo[3];
894 d->reg_ro[ 8] = d->reg_wo[8];
895 d->reg_ro[ 9] = d->reg_wo[9];
896 d->reg_ro[10] = d->reg_wo[10];
897 d->reg_ro[11] = d->reg_wo[11];
898 d->reg_ro[12] = d->reg_wo[12];
899
900 if (regnr == NCR_CMD && writeflag == MEM_WRITE) {
901 if (!quiet_mode)
902 debug(" ");
903
904 /* TODO: Perhaps turn off others here too? */
905 d->reg_ro[NCR_INTR] &= ~NCRINTR_SBR;
906
907 if (idata & NCRCMD_DMA) {
908 if (!quiet_mode)
909 debug("[DMA] ");
910
911 /*
912 * DMA commands load the transfer count from the
913 * write-only registers to the read-only ones, and
914 * the Terminal Count bit is cleared.
915 */
916 d->reg_ro[NCR_TCL] = d->reg_wo[NCR_TCL];
917 d->reg_ro[NCR_TCM] = d->reg_wo[NCR_TCM];
918 d->reg_ro[NCR_TCH] = d->reg_wo[NCR_TCH];
919 d->reg_ro[NCR_STAT] &= ~NCRSTAT_TC;
920 }
921
922 switch (idata & ~NCRCMD_DMA) {
923
924 case NCRCMD_NOP:
925 if (!quiet_mode)
926 debug("NOP");
927 break;
928
929 case NCRCMD_FLUSH:
930 if (!quiet_mode)
931 debug("FLUSH");
932 /* Flush the FIFO: */
933 dev_asc_fifo_flush(d);
934 break;
935
936 case NCRCMD_RSTCHIP:
937 if (!quiet_mode)
938 debug("RSTCHIP");
939 /* Hardware reset. */
940 dev_asc_reset(d);
941 break;
942
943 case NCRCMD_RSTSCSI:
944 if (!quiet_mode)
945 debug("RSTSCSI");
946 /* No interrupt if interrupts are disabled. */
947 if (!(d->reg_wo[NCR_CFG1] & NCRCFG1_SRR))
948 d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
949 d->reg_ro[NCR_INTR] |= NCRINTR_SBR;
950 d->reg_ro[NCR_INTR] |= NCRINTR_FC;
951 d->cur_state = STATE_DISCONNECTED;
952 break;
953
954 case NCRCMD_ENSEL:
955 if (!quiet_mode)
956 debug("ENSEL");
957 /* TODO */
958 break;
959
960 case NCRCMD_ICCS:
961 if (!quiet_mode)
962 debug("ICCS");
963 /* Reveice a status byte + a message byte. */
964
965 /* TODO: how about other status and message bytes? */
966 if (d->xferp != NULL && d->xferp->status != NULL)
967 dev_asc_fifo_write(d, d->xferp->status[0]);
968 else
969 dev_asc_fifo_write(d, 0x00);
970
971 if (d->xferp != NULL && d->xferp->msg_in != NULL)
972 dev_asc_fifo_write(d, d->xferp->msg_in[0]);
973 else
974 dev_asc_fifo_write(d, 0x00);
975
976 d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
977 d->reg_ro[NCR_INTR] |= NCRINTR_FC;
978 /* d->reg_ro[NCR_INTR] |= NCRINTR_BS; */
979 d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | 7;
980 /* ? probably 7 */
981 d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 4;
982 /* ? */
983 break;
984
985 case NCRCMD_MSGOK:
986 /* Message is being Rejected if ATN is set,
987 otherwise Accepted. */
988 if (!quiet_mode) {
989 debug("MSGOK");
990 if (d->atn)
991 debug("; Rejecting message");
992 else
993 debug("; Accepting message");
994 }
995 d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
996 d->reg_ro[NCR_INTR] |= NCRINTR_DIS;
997
998 d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) |
999 d->cur_phase; /* 6? */
1000 d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) |
1001 4; /* ? */
1002
1003 d->cur_state = STATE_DISCONNECTED;
1004
1005 if (d->xferp != NULL)
1006 scsi_transfer_free(d->xferp);
1007 d->xferp = NULL;
1008 break;
1009
1010 case NCRCMD_SETATN:
1011 if (!quiet_mode)
1012 debug("SETATN");
1013 d->atn = 1;
1014 break;
1015
1016 case NCRCMD_RSTATN:
1017 if (!quiet_mode)
1018 debug("RSTATN");
1019 d->atn = 0;
1020 break;
1021
1022 case NCRCMD_SELNATN:
1023 case NCRCMD_SELATN:
1024 case NCRCMD_SELATNS:
1025 case NCRCMD_SELATN3:
1026 d->cur_phase = PHASE_COMMAND;
1027 switch (idata & ~NCRCMD_DMA) {
1028 case NCRCMD_SELATN:
1029 case NCRCMD_SELATNS:
1030 if ((idata & ~NCRCMD_DMA) == NCRCMD_SELATNS) {
1031 if (!quiet_mode)
1032 debug("SELATNS: select with "
1033 "atn and stop, id %i",
1034 d->reg_wo[NCR_SELID] & 7);
1035 d->cur_phase = PHASE_MSG_OUT;
1036 } else {
1037 if (!quiet_mode)
1038 debug("SELATN: select with atn"
1039 ", id %i",
1040 d->reg_wo[NCR_SELID] & 7);
1041 }
1042 n_messagebytes = 1;
1043 break;
1044 case NCRCMD_SELATN3:
1045 if (!quiet_mode)
1046 debug("SELNATN: select with atn3, "
1047 "id %i", d->reg_wo[NCR_SELID] & 7);
1048 n_messagebytes = 3;
1049 break;
1050 case NCRCMD_SELNATN:
1051 if (!quiet_mode)
1052 debug("SELNATN: select without atn, "
1053 "id %i", d->reg_wo[NCR_SELID] & 7);
1054 n_messagebytes = 0;
1055 }
1056
1057 /* TODO: not just disk, but some generic
1058 SCSI device */
1059 target_exists = diskimage_exist(cpu->machine,
1060 d->reg_wo[NCR_SELID] & 7, DISKIMAGE_SCSI);
1061
1062 if (target_exists) {
1063 /*
1064 * Select a SCSI device, send message bytes
1065 * (if any) and command bytes to the target.
1066 */
1067 int ok;
1068
1069 dev_asc_newxfer(d);
1070
1071 ok = dev_asc_select(cpu, d,
1072 d->reg_ro[NCR_CFG1] & 7,
1073 d->reg_wo[NCR_SELID] & 7,
1074 idata & NCRCMD_DMA? 1 : 0,
1075 n_messagebytes);
1076
1077 if (ok)
1078 d->cur_state = STATE_INITIATOR;
1079 else {
1080 d->cur_state = STATE_DISCONNECTED;
1081 d->reg_ro[NCR_INTR] |= NCRINTR_DIS;
1082 d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
1083 d->reg_ro[NCR_STEP] =
1084 (d->reg_ro[NCR_STEP] & ~7) | 0;
1085 if (d->xferp != NULL)
1086 scsi_transfer_free(d->xferp);
1087 d->xferp = NULL;
1088 }
1089 } else {
1090 /*
1091 * Selection failed, non-existant scsi ID:
1092 *
1093 * This is good enough to fool Ultrix, NetBSD,
1094 * OpenBSD and Linux to continue detection of
1095 * other IDs, without giving any warnings.
1096 */
1097 d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
1098 d->reg_ro[NCR_INTR] |= NCRINTR_DIS;
1099 d->reg_ro[NCR_STEP] &= ~7;
1100 d->reg_ro[NCR_STEP] |= 0;
1101 dev_asc_fifo_flush(d);
1102 d->cur_state = STATE_DISCONNECTED;
1103 }
1104 break;
1105
1106 case NCRCMD_TRPAD:
1107 if (!quiet_mode)
1108 debug("TRPAD");
1109
1110 dev_asc_newxfer(d);
1111 {
1112 int ok;
1113
1114 ok = dev_asc_transfer(cpu, d,
1115 idata & NCRCMD_DMA? 1 : 0);
1116 if (!ok) {
1117 d->cur_state = STATE_DISCONNECTED;
1118 d->reg_ro[NCR_INTR] |= NCRINTR_DIS;
1119 d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
1120 d->reg_ro[NCR_STEP] = (d->reg_ro[
1121 NCR_STEP] & ~7) | 0;
1122 if (d->xferp != NULL)
1123 scsi_transfer_free(d->xferp);
1124 d->xferp = NULL;
1125 }
1126 }
1127 break;
1128
1129 /* Old code which didn't work with Mach: */
1130 #if 0
1131 d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
1132 d->reg_ro[NCR_INTR] |= NCRINTR_BS;
1133 d->reg_ro[NCR_INTR] |= NCRINTR_FC;
1134 d->reg_ro[NCR_STAT] |= NCRSTAT_TC;
1135
1136 d->reg_ro[NCR_TCL] = 0;
1137 d->reg_ro[NCR_TCM] = 0;
1138
1139 d->reg_ro[NCR_STEP] &= ~7;
1140 #if 0
1141 d->reg_ro[NCR_STEP] |= 0;
1142 dev_asc_fifo_flush(d);
1143 #else
1144 d->reg_ro[NCR_STEP] |= 4;
1145 #endif
1146 break;
1147 #endif
1148
1149 case NCRCMD_TRANS:
1150 if (!quiet_mode)
1151 debug("TRANS");
1152
1153 {
1154 int ok;
1155
1156 ok = dev_asc_transfer(cpu, d,
1157 idata & NCRCMD_DMA? 1 : 0);
1158 if (!ok) {
1159 d->cur_state = STATE_DISCONNECTED;
1160 d->reg_ro[NCR_INTR] |= NCRINTR_DIS;
1161 d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
1162 d->reg_ro[NCR_STEP] = (d->reg_ro[
1163 NCR_STEP] & ~7) | 0;
1164 if (d->xferp != NULL)
1165 scsi_transfer_free(d->xferp);
1166 d->xferp = NULL;
1167 }
1168 }
1169 break;
1170
1171 default:
1172 fatal("(unimplemented asc cmd 0x%02x)", (int)idata);
1173 d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
1174 d->reg_ro[NCR_INTR] |= NCRINTR_ILL;
1175 /*
1176 * TODO: exit or continue with Illegal command
1177 * interrupt?
1178 */
1179 exit(1);
1180 }
1181 }
1182
1183 if (regnr == NCR_INTR && writeflag == MEM_READ) {
1184 /*
1185 * Reading the interrupt register de-asserts the
1186 * interrupt pin. Also, INTR, STEP, and STAT are all
1187 * cleared, according to page 64 of the LSI53CF92A manual,
1188 * if "interrupt output is true".
1189 */
1190 if (d->reg_ro[NCR_STAT] & NCRSTAT_INT) {
1191 d->reg_ro[NCR_INTR] = 0;
1192 d->reg_ro[NCR_STEP] = 0;
1193 d->reg_ro[NCR_STAT] = 0;
1194
1195 /* For Mach/PMAX? TODO */
1196 d->reg_ro[NCR_STAT] = PHASE_COMMAND;
1197 }
1198
1199 cpu_interrupt_ack(cpu, d->irq_nr);
1200 }
1201
1202 if (regnr == NCR_CFG1) {
1203 /* TODO: other bits */
1204 if (!quiet_mode) {
1205 debug(" parity %s,", d->reg_ro[regnr] &
1206 NCRCFG1_PARENB? "enabled" : "disabled");
1207 debug(" scsi_id %i", d->reg_ro[regnr] & 0x7);
1208 }
1209 }
1210
1211 #ifdef ASC_FULL_REGISTER_ACCESS_DEBUG
1212 debug(" ]\n");
1213 #endif
1214 dev_asc_tick(cpu, extra);
1215
1216 if (writeflag == MEM_READ)
1217 memory_writemax64(cpu, data, len, odata);
1218
1219 return 1;
1220 }
1221
1222
1223 /*
1224 * dev_asc_init():
1225 *
1226 * Register an 'asc' device.
1227 */
1228 void dev_asc_init(struct machine *machine, struct memory *mem,
1229 uint64_t baseaddr, int irq_nr, void *turbochannel,
1230 int mode,
1231 size_t (*dma_controller)(void *dma_controller_data,
1232 unsigned char *data, size_t len, int writeflag),
1233 void *dma_controller_data)
1234 {
1235 struct asc_data *d;
1236
1237 d = malloc(sizeof(struct asc_data));
1238 if (d == NULL) {
1239 fprintf(stderr, "out of memory\n");
1240 exit(1);
1241 }
1242 memset(d, 0, sizeof(struct asc_data));
1243 d->irq_nr = irq_nr;
1244 d->turbochannel = turbochannel;
1245 d->mode = mode;
1246
1247 d->reg_ro[NCR_CFG3] = NCRF9XCFG3_CDB;
1248
1249 d->dma_address_reg_memory = malloc(machine->arch_pagesize);
1250 d->dma = malloc(ASC_DMA_SIZE);
1251 if (d->dma == NULL || d->dma_address_reg_memory == NULL) {
1252 fprintf(stderr, "out of memory\n");
1253 exit(1);
1254 }
1255 memset(d->dma_address_reg_memory, 0, machine->arch_pagesize);
1256 memset(d->dma, 0, ASC_DMA_SIZE);
1257
1258 d->dma_controller = dma_controller;
1259 d->dma_controller_data = dma_controller_data;
1260
1261 memory_device_register(mem, "asc", baseaddr,
1262 mode == DEV_ASC_PICA? DEV_ASC_PICA_LENGTH : DEV_ASC_DEC_LENGTH,
1263 dev_asc_access, d, DM_DEFAULT, NULL);
1264
1265 if (mode == DEV_ASC_DEC) {
1266 memory_device_register(mem, "asc_dma_address_reg",
1267 baseaddr + 0x40000, 4096, dev_asc_address_reg_access, d,
1268 DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK,
1269 (unsigned char *)&d->dma_address_reg_memory[0]);
1270 memory_device_register(mem, "asc_dma", baseaddr + 0x80000,
1271 ASC_DMA_SIZE, dev_asc_dma_access, d,
1272 DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK, d->dma);
1273 }
1274
1275 machine_add_tickfunction(machine, dev_asc_tick, d, ASC_TICK_SHIFT, 0.0);
1276 }
1277

  ViewVC Help
Powered by ViewVC 1.1.26