/[gxemul]/trunk/src/devices/dev_asc.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (hide annotations)
Mon Oct 8 16:18:38 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 31789 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.905 2005/08/16 09:16:24 debug Exp $
20050628	Continuing the work on the ARM translation engine. end_of_page
		works. Experimenting with load/store translation caches
		(virtual -> physical -> host).
20050629	More ARM stuff (memory access translation cache, mostly). This
		might break a lot of stuff elsewhere, probably some MIPS-
		related translation things.
20050630	Many load/stores are now automatically generated and included
		into cpu_arm_instr.c; 1024 functions in total (!).
		Fixes based on feedback from Alec Voropay: only print 8 hex
		digits instead of 16 in some cases when emulating 32-bit
		machines; similar 8 vs 16 digit fix for breakpoint addresses;
		4Kc has 16 TLB entries, not 48; the MIPS config select1
		register is now printed with "reg ,0".
		Also changing many other occurances of 16 vs 8 digit output.
		Adding cache associativity fields to mips_cpu_types.h; updating
		some other cache fields; making the output of
		mips_cpu_dumpinfo() look nicer.
		Generalizing the bintrans stuff for device accesses to also
		work with the new translation system. (This might also break
		some MIPS things.)
		Adding multi-load/store instructions to the ARM disassembler
		and the translator, and some optimizations of various kinds.
20050701	Adding a simple dev_disk (it can read/write sectors from
		disk images).
20050712	Adding dev_ether (a simple ethernet send/receive device).
		Debugger command "ninstrs" for toggling show_nr_of_instructions
		during runtime.
		Removing the framebuffer logo.
20050713	Continuing on dev_ether.
		Adding a dummy cpu_alpha (again).
20050714	More work on cpu_alpha.
20050715	More work on cpu_alpha. Many instructions work, enough to run
		a simple framebuffer fill test (similar to the ARM test).
20050716	More Alpha stuff.
20050717	Minor updates (Alpha stuff).
20050718	Minor updates (Alpha stuff).
20050719	Generalizing some Alpha instructions.
20050720	More Alpha-related updates.
20050721	Continuing on cpu_alpha. Importing rpb.h from NetBSD/alpha.
20050722	Alpha-related updates: userland stuff (Hello World using
		write() compiled statically for FreeBSD/Alpha runs fine), and
		more instructions are now implemented.
20050723	Fixing ldq_u and stq_u.
		Adding more instructions (conditional moves, masks, extracts,
		shifts).
20050724	More FreeBSD/Alpha userland stuff, and adding some more
		instructions (inserts).
20050725	Continuing on the Alpha stuff. (Adding dummy ldt/stt.)
		Adding a -A command line option to turn off alignment checks
		in some cases (for translated code).
		Trying to remove the old bintrans code which updated the pc
		and nr_of_executed_instructions for every instruction.
20050726	Making another attempt att removing the pc/nr of instructions
		code. This time it worked, huge performance increase for
		artificial test code, but performance loss for real-world
		code :-( so I'm scrapping that code for now.
		Tiny performance increase on Alpha (by using ret instead of
		jmp, to play nice with the Alpha's branch prediction) for the
		old MIPS bintrans backend.
20050727	Various minor fixes and cleanups.
20050728	Switching from a 2-level virtual to host/physical translation
		system for ARM emulation, to a 1-level translation.
		Trying to switch from 2-level to 1-level for the MIPS bintrans
		system as well (Alpha only, so far), but there is at least one
		problem: caches and/or how they work with device mappings.
20050730	Doing the 2-level to 1-level conversion for the i386 backend.
		The cache/device bug is still there for R2K/3K :(
		Various other minor updates (Malta etc).
		The mc146818 clock now updates the UIP bit in a way which works
		better with Linux for at least sgimips and Malta emulation.
		Beginning the work on refactoring the dyntrans system.
20050731	Continuing the dyntrans refactoring.
		Fixing a small but serious host alignment bug in memory_rw.
		Adding support for big-endian load/stores to the i386 bintrans
		backend.
		Another minor i386 bintrans backend update: stores from the
		zero register are now one (or two) loads shorter.
		The slt and sltu instructions were incorrectly implemented for
		the i386 backend; only using them for 32-bit mode for now.
20050801	Continuing the dyntrans refactoring.
		Cleanup of the ns16550 serial controller (removing unnecessary
		code).
		Bugfix (memory corruption bug) in dev_gt, and a patch/hack from
		Alec Voropay for Linux/Malta.
20050802	More cleanup/refactoring of the dyntrans subsystem: adding
		phys_page pointers to the lookup tables, for quick jumps
		between translated pages.
		Better fix for the ns16550 device (but still no real FIFO
		functionality).
		Converting cpu_ppc to the new dyntrans system. This means that
		I will have to start from scratch with implementing each
		instruction, and figure out how to implement dual 64/32-bit
		modes etc.
		Removing the URISC CPU family, because it was useless.
20050803	When selecting a machine type, the main type can now be omitted
		if the subtype name is unique. (I.e. -E can be omitted.)
		Fixing a dyntrans/device update bug. (Writes to offset 0 of
		a device could sometimes go unnoticed.)
		Adding an experimental "instruction combination" hack for
		ARM for memset-like byte fill loops.
20050804	Minor progress on cpu_alpha and related things.
		Finally fixing the MIPS dmult/dmultu bugs.
		Fixing some minor TODOs.
20050805	Generalizing the 8259 PIC. It now also works with Cobalt
		and evbmips emulation, in addition to the x86 hack.
		Finally converting the ns16550 device to use devinit.
		Continuing the work on the dyntrans system. Thinking about
		how to add breakpoints.
20050806	More dyntrans updates. Breakpoints seem to work now.
20050807	Minor updates: cpu_alpha and related things; removing
		dev_malta (as it isn't used any more).
		Dyntrans: working on general "show trace tree" support.
		The trace tree stuff now works with both the old MIPS code and
		with newer dyntrans modes. :)
		Continuing on Alpha-related stuff (trying to get *BSD to boot
		a bit further, adding more instructions, etc).
20050808	Adding a dummy IA64 cpu family, and continuing the refactoring
		of the dyntrans system.
		Removing the regression test stuff, because it was more or
		less useless.
		Adding loadlinked/storeconditional type instructions to the
		Alpha emulation. (Needed for Linux/alpha. Not very well tested
		yet.)
20050809	The function call trace tree now prints a per-function nr of
		arguments. (Semi-meaningless, since that data isn't read yet
		from the ELFs; some hardcoded symbols such as memcpy() and
		strlen() work fine, though.)
		More dyntrans refactoring; taking out more of the things that
		are common to all cpu families.
20050810	Working on adding support for "dual mode" for PPC dyntrans
		(i.e. both 64-bit and 32-bit modes).
		(Re)adding some simple PPC instructions.
20050811	Adding a dummy M68K cpu family. The dyntrans system isn't ready
		for variable-length ISAs yet, so it's completely bogus so far.
		Re-adding more PPC instructions.
		Adding a hack to src/file.c which allows OpenBSD/mac68k a.out
		kernels to be loaded.
		Beginning to add PPC loads/stores. So far they only work in
		32-bit mode.
20050812	The configure file option "add_remote" now accepts symbolic
		host names, in addition to numeric IPv4 addresses.
		Re-adding more PPC instructions.
20050814	Continuing to port back more PPC instructions.
		Found and fixed the cache/device write-update bug for 32-bit
		MIPS bintrans. :-)
		Triggered a really weird and annoying bug in Compaq's C
		compiler; ccc sometimes outputs code which loads from an
		address _before_ checking whether the pointer was NULL or not.
		(I'm not sure how to handle this problem.)
20050815	Removing all of the old x86 instruction execution code; adding
		a new (dummy) dyntrans module for x86.
		Taking the first steps to extend the dyntrans system to support
		variable-length instructions.
		Slowly preparing for the next release.
20050816	Adding a dummy SPARC cpu module.
		Minor updates (documentation etc) for the release.

==============  RELEASE 0.3.5  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26