/[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 24 - (show annotations)
Mon Oct 8 16:19:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 31651 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1256 2006/06/23 20:43:44 debug Exp $
20060219	Various minor updates. Removing the old MIPS16 skeleton code,
		because it will need to be rewritten for dyntrans anyway.
20060220-22	Removing the non-working dyntrans backend support.
		Continuing on the 64-bit dyntrans virtual memory generalization.
20060223	More work on the 64-bit vm generalization.
20060225	Beginning on MIPS dyntrans load/store instructions.
		Minor PPC updates (64-bit load/store, etc).
		Fixes for the variable-instruction-length framework, some
		minor AVR updates (a simple Hello World program works!).
		Beginning on a skeleton for automatically generating documen-
		tation (for devices etc.).
20060226	PPC updates (adding some more 64-bit instructions, etc).
		AVR updates (more instructions).
		FINALLY found and fixed the zs bug, making NetBSD/macppc
		accept the serial console.
20060301	Adding more AVR instructions.
20060304	Continuing on AVR-related stuff. Beginning on a framework for
		cycle-accurate device emulation. Adding an experimental "PAL
		TV" device (just a dummy so far).
20060305	Adding more AVR instructions.
		Adding a dummy epcom serial controller (for TS7200 emulation).
20060310	Removing the emul() command from configuration files, so only
		net() and machine() are supported.
		Minor progress on the MIPS dyntrans rewrite.
20060311	Continuing on the MIPS dyntrans rewrite (adding more
		instructions, etc).
20060315	Adding more instructions (sllv, srav, srlv, bgtz[l], blez[l],
		beql, bnel, slti[u], various loads and stores).
20060316	Removing the ALWAYS_SIGNEXTEND_32 option, since it was rarely
		used.
		Adding more MIPS dyntrans instructions, and fixing bugs.
20060318	Implementing fast loads/stores for MIPS dyntrans (big/little
		endian, 32-bit and 64-bit modes).
20060320	Making MIPS dyntrans the default configure option; use
		"--enable-oldmips" to use the old bintrans system.
		Adding MIPS dyntrans dmult[u]; minor updates.
20060322	Continuing... adding some more instructions.
		Adding a simple skeleton for demangling C++ "_ZN" symbols.
20060323	Moving src/debugger.c into a new directory (src/debugger/).
20060324	Fixing the hack used to load PPC ELFs (useful for relocated
		Linux/ppc kernels), and adding a dummy G3 machine mode.
20060325-26	Beginning to experiment with GDB remote serial protocol
		connections; adding a -G command line option for selecting
		which TCP port to listen to.
20060330	Beginning a major cleanup to replace things like "0x%016llx"
		with more correct "0x%016"PRIx64, etc.
		Continuing on the GDB remote serial protocol support.
20060331	More cleanup, and some minor GDB remote progress.
20060402	Adding a hack to the configure script, to allow compilation
		on systems that lack PRIx64 etc.
20060406	Removing the temporary FreeBSD/arm hack in dev_ns16550.c and
		replacing it with a better fix from Olivier Houchard.
20060407	A remote debugger (gdb or ddd) can now start and stop the
		emulator using the GDB remote serial protocol, and registers
		and memory can be read. MIPS only for now.
20060408	More GDB progress: single-stepping also works, and also adding
		support for ARM, PowerPC, and Alpha targets.
		Continuing on the delay-slot-across-page-boundary issue.
20060412	Minor update: beginning to add support for the SPARC target
		to the remote GDB functionality.
20060414	Various MIPS updates: adding more instructions for dyntrans
		(eret, add), and making some exceptions work. Fixing a bug
		in dmult[u].
		Implementing the first SPARC instructions (sethi, or).
20060415	Adding "magic trap" instructions so that PROM calls can be
		software emulated in MIPS dyntrans.
		Adding more MIPS dyntrans instructions (ddiv, dadd) and
		fixing another bug in dmult.
20060416	More MIPS dyntrans progress: adding [d]addi, movn, movz, dsllv,
		rfi, an ugly hack for supporting R2000/R3000 style faked caches,
		preliminary interrupt support, and various other updates and
		bugfixes.
20060417	Adding more SPARC instructions (add, sub, sll[x], sra[x],
		srl[x]), and useful SPARC header definitions.
		Adding the first (trivial) x86/AMD64 dyntrans instructions (nop,
		cli/sti, stc/clc, std/cld, simple mov, inc ax). Various other
		x86 updates related to variable instruction length stuff.
		Adding unaligned loads/stores to the MIPS dyntrans mode (but
		still using the pre-dyntrans (slow) imlementation).
20060419	Fixing a MIPS dyntrans exception-in-delay-slot bug.
		Removing the old "show opcode statistics" functionality, since
		it wasn't really useful and isn't implemented for dyntrans.
		Single-stepping (or running with instruction trace) now looks
		ok with dyntrans with delay-slot architectures.
20060420	Minor hacks (removing the -B command line option when compiled
		for non-bintrans, and some other very minor updates).
		Adding (slow) MIPS dyntrans load-linked/store-conditional.
20060422	Applying fixes for bugs discovered by Nils Weller's nwcc
		(static DEC memmap => now per machine, and adding an extern
		keyword in cpu_arm_instr.c).
		Finally found one of the MIPS dyntrans bugs that I've been
		looking for (copy/paste spelling error BIG vs LITTLE endian in
		cpu_mips_instr_loadstore.c for 16-bit fast stores).
		FINALLY found the major MIPS dyntrans bug: slti vs sltiu
		signed/unsigned code in cpu_mips_instr.c. :-)
		Adding more MIPS dyntrans instructions (lwc1, swc1, bgezal[l],
		ctc1, tlt[u], tge[u], tne, beginning on rdhwr).
		NetBSD/hpcmips can now reach userland when using dyntrans :-)
		Adding some more x86 dyntrans instructions.
		Finally removed the old Alpha-specific virtual memory code,
		and replaced it with the generic 64-bit version.
		Beginning to add disassembly support for SPECIAL3 MIPS opcodes.
20060423	Continuing on the delay-slot-across-page-boundary issue;
		adding an end_of_page2 ic slot (like I had planned before, but
		had removed for some reason).
		Adding a quick-and-dirty fallback to legacy coprocessor 1
		code (i.e. skipping dyntrans implementation for now).
		NetBSD/hpcmips and NetBSD/pmax (when running on an emulated
		R4400) can now be installed and run. :-)  (Many bugs left
		to fix, though.)
		Adding more MIPS dyntrans instructions: madd[u], msub[u].
		Cleaning up the SPECIAL2 vs R5900/TX79/C790 "MMI" opcode
		maps somewhat (disassembly and dyntrans instruction decoding).
20060424	Adding an isa_revision field to mips_cpu_types.h, and making
		sure that SPECIAL3 opcodes cause Reserved Instruction
		exceptions on MIPS32/64 revisions lower than 2.
		Adding the SPARC 'ba', 'call', 'jmpl/retl', 'and', and 'xor'
		instructions.
20060425	Removing the -m command line option ("run at most x 
		instructions") and -T ("single_step_on_bad_addr"), because
		they never worked correctly with dyntrans anyway.
		Freshening up the man page.
20060428	Adding more MIPS dyntrans instructions: bltzal[l], idle.
		Enabling MIPS dyntrans compare interrupts.
20060429	FINALLY found the weird dyntrans bug, causing NetBSD etc. to
		behave strangely: some floating point code (conditional
		coprocessor branches) could not be reused from the old
		non-dyntrans code. The "quick-and-dirty fallback" only appeared
		to work. Fixing by implementing bc1* for MIPS dyntrans.
		More MIPS instructions: [d]sub, sdc1, ldc1, dmtc1, dmfc1, cfc0.
		Freshening up MIPS floating point disassembly appearance.
20060430	Continuing on C790/R5900/TX79 disassembly; implementing 128-bit
		"por" and "pextlw".
20060504	Disabling -u (userland emulation) unless compiled as unstable
		development version.
		Beginning on freshening up the testmachine include files,
		to make it easier to reuse those files (placing them in
		src/include/testmachine/), and beginning on a set of "demos"
		or "tutorials" for the testmachine functionality.
		Minor updates to the MIPS GDB remote protocol stub.
		Refreshing doc/experiments.html and gdb_remote.html.
		Enabling Alpha emulation in the stable release configuration,
		even though no guest OSes for Alpha can run yet.
20060505	Adding a generic 'settings' object, which will contain
		references to settable variables (which will later be possible
		to access using the debugger).
20060506	Updating dev_disk and corresponding demo/documentation (and
		switching from SCSI to IDE disk types, so it actually works
		with current test machines :-).
20060510	Adding a -D_LARGEFILE_SOURCE hack for 64-bit Linux hosts,
		so that fseeko() doesn't give a warning.
		Updating the section about how dyntrans works (the "runnable
		IR") in doc/intro.html.
		Instruction updates (some x64=1 checks, some more R5900
		dyntrans stuff: better mul/mult separation from MIPS32/64,
		adding ei and di).
		Updating MIPS cpuregs.h to a newer one (from NetBSD).
		Adding more MIPS dyntrans instructions: deret, ehb.
20060514	Adding disassembly and beginning implementation of SPARC wr
		and wrpr instructions.
20060515	Adding a SUN SPARC machine mode, with dummy SS20 and Ultra1
		machines. Adding the 32-bit "rd psr" instruction.
20060517	Disassembly support for the general SPARC rd instruction.
		Partial implementation of the cmp (subcc) instruction.
		Some other minor updates (making sure that R5900 processors
		start up with the EIE bit enabled, otherwise Linux/playstation2
		receives no interrupts).
20060519	Minor MIPS updates/cleanups.
20060521	Moving the MeshCube machine into evbmips; this seems to work
		reasonably well with a snapshot of a NetBSD MeshCube kernel.
		Cleanup/fix of MIPS config0 register initialization.
20060529	Minor MIPS fixes, including a sign-extension fix to the
		unaligned load/store code, which makes NetBSD/pmax on R3000
		work better with dyntrans. (Ultrix and Linux/DECstation still
		don't work, though.)
20060530	Minor updates to the Alpha machine mode: adding an AlphaBook
		mode, an LCA bus (forwarding accesses to an ISA bus), etc.
20060531	Applying a bugfix for the MIPS dyntrans sc[d] instruction from
		Ondrej Palkovsky. (Many thanks.)
20060601	Minifix to allow ARM immediate msr instruction to not give
		an error for some valid values.
		More Alpha updates.
20060602	Some minor Alpha updates.
20060603	Adding the Alpha cmpbge instruction. NetBSD/alpha prints its
		first boot messages :-) on an emulated Alphabook 1.
20060612	Minor updates; adding a dev_ether.h include file for the
		testmachine ether device. Continuing the hunt for the dyntrans
		bug which makes Linux and Ultrix on DECstation behave
		strangely... FINALLY found it! It seems to be related to
		invalidation of the translation cache, on tlbw{r,i}. There
		also seems to be some remaining interrupt-related problems.
20060614	Correcting the implementation of ldc1/sdc1 for MIPS dyntrans
		(so that it uses 16 32-bit registers if the FR bit in the
		status register is not set).
20060616	REMOVING BINTRANS COMPLETELY!
		Removing the old MIPS interpretation mode.
		Removing the MFHILO_DELAY and instruction delay stuff, because
		they wouldn't work with dyntrans anyway.
20060617	Some documentation updates (adding "NetBSD-archive" to some
		URLs, and new Debian/DECstation installation screenshots).
		Removing the "tracenull" and "enable-caches" configure options.
		Improving MIPS dyntrans performance somewhat (only invalidate
		translations if necessary, on writes to the entryhi register,
		instead of doing it for all cop0 writes).
20060618	More cleanup after the removal of the old MIPS emulation.
		Trying to fix the MIPS dyntrans performance bugs/bottlenecks;
		only semi-successful so far (for R3000).
20060620	Minor update to allow clean compilation again on Tru64/Alpha.
20060622	MIPS cleanup and fixes (removing the pc_last stuff, which
		doesn't make sense with dyntrans anyway, and fixing a cross-
		page-delay-slot-with-exception case in end_of_page).
		Removing the old max_random_cycles_per_chunk stuff, and the
		concept of cycles vs instructions for MIPS emulation.
		FINALLY found and fixed the bug which caused NetBSD/pmax
		clocks to behave strangely (it was a load to the zero register,
		which was treated as a NOP; now it is treated as a load to a
		dummy scratch register).
20060623	Increasing the dyntrans chunk size back to
		N_SAFE_DYNTRANS_LIMIT, instead of N_SAFE_DYNTRANS_LIMIT/2.
		Preparing for a quick release, even though there are known
		bugs, and performance for non-R3000 MIPS emulation is very
		poor. :-/
		Reverting to half the dyntrans chunk size again, because
		NetBSD/cats seemed less stable with full size chunks. :(
		NetBSD/sgimips 3.0 can now run :-)  (With release 0.3.8, only
		NetBSD/sgimips 2.1 worked, not 3.0.)

==============  RELEASE 0.4.0  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26