/[gxemul]/trunk/src/devices/dev_sii.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_sii.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 18 - (show annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 13068 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

==============  RELEASE 0.3.6.2  ==============


1 /*
2 * Copyright (C) 2003-2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: dev_sii.c,v 1.14 2005/10/26 14:37:04 debug Exp $
29 *
30 * SII SCSI controller, used in some DECstation systems.
31 *
32 * TODO: This is huge and ugly. Fix this.
33 */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include "cpu.h"
40 #include "devices.h"
41 #include "machine.h"
42 #include "memory.h"
43 #include "misc.h"
44
45 #include "siireg.h"
46
47
48 #define SII_TICK_SHIFT 14
49
50
51 struct sii_data {
52 int irq_nr;
53 uint64_t buf_start;
54 uint64_t buf_end;
55
56 int connected;
57 int connected_to_id;
58
59 int register_choice;
60 SIIRegs siiregs;
61 uint16_t *regs;
62 };
63
64
65 /*
66 * combine_sii_bits():
67 *
68 * Combines some bits of CSTAT and DSTAT that are connected.
69 */
70 void combine_sii_bits(struct sii_data *d)
71 {
72 int ci, di;
73
74 di = ((d->siiregs.dstat & SII_MIS) |
75 (d->siiregs.dstat & SII_IBF) |
76 (d->siiregs.dstat & SII_TBE) |
77 (d->siiregs.dstat & SII_DNE))==0? 0 : SII_DI;
78
79 ci = ((d->siiregs.cstat & SII_RST) |
80 (d->siiregs.cstat & SII_BER) |
81 (d->siiregs.cstat & SII_OBC) |
82 (d->siiregs.cstat & SII_BUF) |
83 (d->siiregs.cstat & SII_LDN) |
84 (d->siiregs.cstat & SII_SCH))==0? 0 : SII_CI;
85
86 d->siiregs.cstat &= ~(SII_CI | SII_DI);
87 d->siiregs.dstat &= ~(SII_CI | SII_DI);
88
89 d->siiregs.cstat |= (ci | di);
90 d->siiregs.dstat |= (ci | di);
91 }
92
93
94 /*
95 * dev_sii_tick():
96 */
97 void dev_sii_tick(struct cpu *cpu, void *extra)
98 {
99 struct sii_data *d = extra;
100
101 /* ? */
102 d->siiregs.dstat = (d->siiregs.dstat & ~0x7)
103 | ((d->siiregs.dstat + 1) & 0x7);
104
105 /* SCSI Commands: */
106
107 if (d->siiregs.comm & SII_CHRESET) { /* (I,T,D) */
108 /* debug("[ sii: command TODO: CHRESET ]\n"); */
109 }
110
111 if (d->siiregs.comm & SII_DISCON) { /* (I,T,D) */
112 /* debug("[ sii: command TODO: DISCON ]\n"); */
113 d->siiregs.cstat &= ~SII_CON; /* Connected */
114
115 if (d->connected) {
116 d->siiregs.cstat |= SII_SCH; /* State change */
117 d->connected = 0;
118 }
119
120 d->siiregs.cstat &= ~SII_SIP; /* Selection in progress */
121 d->siiregs.comm &= ~SII_DISCON;
122 }
123
124 if (d->siiregs.comm & SII_REQDATA) { /* (T) */
125 /* debug("[ sii: command TODO: REQDATA ]\n"); */
126 }
127
128 if (d->siiregs.comm & SII_SELECT) { /* (D) */
129 /* debug("[ sii: command SELECT ]\n"); */
130 d->siiregs.comm &= ~SII_SELECT;
131
132 /* slcsr contains the other target's id */
133 d->siiregs.cstat |= SII_SIP; /* Selection in progress */
134 d->connected = 0;
135 d->connected_to_id = 0;
136
137 /* Is the target available for selection?
138 TODO: make this nicer */
139 #if 0
140 if ((d->siiregs.slcsr & 7) == 0) {
141 d->siiregs.cstat |= SII_CON; /* Connected */
142 d->siiregs.cstat |= SII_SCH; /* State change */
143 d->siiregs.cstat &= ~SII_SIP; /* Sel. in progress */
144
145 d->connected = 1;
146 d->connected_to_id = 0;
147 }
148 #endif
149 }
150
151 if (d->siiregs.comm & SII_INXFER
152 && (d->siiregs.comm & 0x70) == (d->siiregs.cstat & 0x70) &&
153 (d->siiregs.comm & 0x03) == (d->siiregs.dstat & 0x03) &&
154 !(d->siiregs.cstat & SII_SIP)) { /* (I,T) */
155 debug("[ sii: command INXFER to scsiid=%i ]\n",
156 d->siiregs.slcsr);
157 if (d->siiregs.comm & SII_DMA)
158 debug("[ sii DMA: TODO ]\n");
159 else {
160 debug("[ sii: transmitting byte 0x%02x using "
161 "PIO mode ]\n", d->siiregs.data);
162 d->siiregs.comm &= ~SII_INXFER;
163
164 /* d->siiregs.dstat |= SII_DNE; */
165 /* Done, only for DMA? */
166 d->siiregs.dstat |= SII_TBE; /* Buffer empty? */
167 }
168 }
169
170 combine_sii_bits(d);
171
172 if (d->siiregs.csr & SII_IE && d->siiregs.cstat & (SII_CI | SII_DI))
173 cpu_interrupt(cpu, d->irq_nr);
174 else
175 cpu_interrupt_ack(cpu, d->irq_nr);
176 }
177
178
179 /*
180 * dev_sii_access():
181 */
182 int dev_sii_access(struct cpu *cpu, struct memory *mem,
183 uint64_t relative_addr, unsigned char *data, size_t len,
184 int writeflag, void *extra)
185 {
186 uint64_t idata = 0, odata = 0;
187 int regnr;
188 struct sii_data *d = extra;
189
190 if (relative_addr & 3) {
191 debug("[ sii relative_addr = 0x%x !!! ]\n",
192 (int) relative_addr);
193 return 0;
194 }
195
196 dev_sii_tick(cpu, extra);
197
198 if (writeflag == MEM_WRITE)
199 idata = memory_readmax64(cpu, data, len);
200
201 regnr = relative_addr / 2;
202 odata = d->regs[regnr];
203
204 switch (relative_addr) {
205 case 0x00: /* SII_SDB: Diagnostic */
206 if (writeflag == MEM_READ) {
207 debug("[ sii: read from SDB (data=0x%04x) ]\n",
208 d->regs[regnr]);
209 } else {
210 debug("[ sii: write to SDB (data=0x%04x) ]\n",
211 (int)idata);
212 d->regs[regnr] = idata;
213 return 1;
214 }
215 break;
216 case 0x0c: /* SII_CSR: Control/status */
217 if (writeflag == MEM_READ) {
218 debug("[ sii: read from CSR (data=0x%04x) ]\n",
219 d->regs[regnr]);
220 } else {
221 debug("[ sii: write to CSR (data=0x%04x: %s %s "
222 "%s %s %s) ]\n", (int)idata,
223 idata & SII_HPM? "HPM" : "!hpm",
224 idata & SII_RSE? "RSE" : "!rse",
225 idata & SII_SLE? "SLE" : "!sle",
226 idata & SII_PCE? "PCE" : "!pce",
227 idata & SII_IE? "IE" : "!ie");
228 d->regs[regnr] = idata;
229 return 1;
230 }
231 break;
232 case 0x10: /* SII_ID: SCSI ID */
233 if (writeflag == MEM_READ) {
234 debug("[ sii: read from ID (data=0x%04x) ]\n",
235 d->regs[regnr]);
236 } else {
237 debug("[ sii: write to ID (data=0x%04x: scsi id %i)"
238 " ]\n", (int)idata, (int)(idata & 7));
239 if (!(idata & SII_ID_IO))
240 debug("WARNING: sii ID bit SII_ID_IO not "
241 "set on write!\n");
242 idata &= ~SII_ID_IO;
243 if ((idata & ~0x7) != 0)
244 debug("WARNING: sii ID bits that should "
245 "be zero are not zero!\n");
246 idata &= 0x7;
247 d->regs[regnr] = idata & 0x7;
248 return 1;
249 }
250 break;
251 case 0x14: /* SII_SLCSR: Selector control */
252 if (writeflag == MEM_READ) {
253 debug("[ sii: read from SLCSR (data=0x%04x: "
254 "scsi_id=%i) ]\n", d->regs[regnr],
255 d->regs[regnr] & 7);
256 } else {
257 debug("[ sii: write to SLCSR (data=0x%04x: "
258 "scsi_id=%i) ]\n", (int)idata, (int)(idata & 7));
259 if ((idata & ~0x7) != 0)
260 debug("WARNING: sii SLCSR bits that should "
261 "be zero are not zero!\n");
262 idata &= 0x7;
263 d->regs[regnr] = idata & 0x7;
264 return 1;
265 }
266 break;
267 case 0x18: /* SII_DESTAT: Selection detector status */
268 if (writeflag == MEM_READ) {
269 /* TODO: set DESTAT from somewhere else? */
270 debug("[ sii: read from DESTAT (data=0x%04x: "
271 "scsi_id=%i) ]\n", d->regs[regnr],
272 d->regs[regnr] & 7);
273 } else {
274 debug("[ sii: write to DESTAT (data=0x%04x: "
275 "scsi_id=%i) ]\n", (int)idata, (int)(idata & 7));
276 debug("WARNING: sii DESTAT is read-only!\n");
277 return 1;
278 }
279 break;
280 case 0x20: /* SII_DATA: Data register */
281 if (writeflag == MEM_READ) {
282 /* TODO */
283 debug("[ sii: read from DATA (data=0x%04x) ]\n",
284 d->regs[regnr]);
285 } else {
286 /* TODO */
287 debug("[ sii: write to DATA (data=0x%04x) ]\n",
288 (int)idata);
289 idata &= 0xff;
290 d->regs[regnr] = idata;
291 return 1;
292 }
293 break;
294 case 0x24: /* SII_DMCTRL: DMA control */
295 if (writeflag == MEM_READ) {
296 debug("[ sii: read from DMCTRL (data=0x%04x) ]\n",
297 d->regs[regnr]);
298 } else {
299 debug("[ sii: write to DMCTRL (data=0x%04x: %s) ]\n",
300 (int)idata, (idata & 3)==0? "async" : "sync");
301 if ((idata & ~0x3) != 0)
302 debug("WARNING: sii DMCTRL bits that "
303 "should be zero are not zero!\n");
304 idata &= 0x3;
305 d->regs[regnr] = idata;
306 return 1;
307 }
308 break;
309 case 0x48: /* SII_CSTAT: Connection status */
310 if (writeflag == MEM_READ) {
311 debug("[ sii: read from CSTAT (data=0x%04x) ]\n",
312 d->regs[regnr]);
313 } else {
314 debug("[ sii: write to CSTAT (data=0x%04x) ]\n",
315 (int)idata);
316
317 /* readonly / writeoncetoclear bits according
318 to page 21 in the DS3100 manual: */
319 if (idata & (1<<13)) {
320 idata &= ~(1<<13); d->regs[regnr] &= ~(1<<13);
321 }
322 if (idata & (1<<12)) {
323 idata &= ~(1<<12); d->regs[regnr] &= ~(1<<12);
324 }
325 if (idata & (1<<11)) {
326 /* is this actually write-1-to-clear? */
327 idata &= ~(1<<11); d->regs[regnr] &= ~(1<<11);
328 }
329 if (idata & (1<<9)) {
330 /* ? */
331 idata &= ~(1<<9); d->regs[regnr] &= ~(1<<9);
332 }
333 if (idata & (1<<8)) {
334 /* ? */
335 idata &= ~(1<<8); d->regs[regnr] &= ~(1<<8);
336 }
337 if (idata & (1<<7)) {
338 idata &= ~(1<<7); d->regs[regnr] &= ~(1<<7);
339 }
340 if (idata & (1<<3)) {
341 idata &= ~(1<<3); d->regs[regnr] &= ~(1<<3);
342 }
343
344 /* Read-only bits are taken from the old register: */
345 idata &= ~0x3bf7;
346 idata |= d->regs[regnr] & 0x3bf7;
347
348 d->regs[regnr] = idata;
349 return 1;
350 }
351 break;
352 case 0x4c: /* SII_DSTAT: Data transfer status */
353 if (writeflag == MEM_READ) {
354 debug("[ sii: read from DSTAT (data=0x%04x) ]\n",
355 d->regs[regnr]);
356 } else {
357 debug("[ sii: write to DSTAT (data=0x%04x) ]\n",
358 (int)idata);
359
360 /* readonly / writeoncetoclear bits
361 according to page 22 in the DS3100 manual: */
362 if (idata & (1<<13)) {
363 idata &= ~(1<<13); d->regs[regnr] &= ~(1<<13);
364 }
365 if (idata & (1<<11)) {
366 /* is this write-1-to-clear? */
367 idata &= ~(1<<11); d->regs[regnr] &= ~(1<<11);
368 }
369 if (idata & (1<<10)) {
370 /* is this write-1-to-clear? */
371 idata &= ~(1<<10); d->regs[regnr] &= ~(1<<10);
372 }
373 if (idata & (1<<4)) {
374 /* is this write-1-to-clear? */
375 idata &= ~(1<<4); d->regs[regnr] &= ~(1<<4);
376 }
377 if (idata & (1<<3)) {
378 idata &= ~(1<<3); d->regs[regnr] &= ~(1<<3);
379 }
380
381 /* Read-only bits are taken from the old register: */
382 idata &= ~0x0c17;
383 idata |= d->regs[regnr] & 0x0c17;
384
385 d->regs[regnr] = idata;
386 return 1;
387 }
388 break;
389 case 0x50: /* SII_COMM: Command */
390 if (writeflag == MEM_READ) {
391 debug("[ sii: read from COMM (data=0x%04x) ]\n",
392 d->regs[regnr]);
393 } else {
394 debug("[ sii: write to COMM (data=0x%04x: %s %s "
395 "%s command=0x%02x rest=0x%02x) ]\n", (int)idata,
396 idata & SII_DMA? "DMA" : "!dma",
397 idata & SII_DO_RST? "RST" : "!rst",
398 idata & SII_RSL? "RSL" : "!rsl",
399 /* command, 5 bits: */
400 (int)((idata >> 7) & 0x1f),
401 /* rest, 7 bits: */
402 (int)(idata & 0x3f));
403
404 if (idata & SII_DO_RST) {
405 /* Reset: TODO */
406 }
407
408 idata &= ~SII_DO_RST;
409 d->regs[regnr] = idata;
410
411 dev_sii_tick(cpu, extra);
412 return 1;
413 }
414 break;
415 case 0x54: /* SII_DICTRL: Diagnostics control */
416 if (writeflag == MEM_READ) {
417 debug("[ sii: read from DICTRL (data=0x%04x) ]\n",
418 d->regs[regnr]);
419 } else {
420 debug("[ sii: write to DICTRL (data=0x%04x: "
421 "port=%s) ]\n", (int)idata,
422 idata & SII_PRE? "enabled" : "disabled");
423 if ((idata & ~0xf) != 0)
424 debug("WARNING: sii DICTRL bits that "
425 "should be zero are not zero!\n");
426 d->regs[regnr] = idata;
427 return 1;
428 }
429 break;
430 default:
431 if (writeflag==MEM_READ) {
432 debug("[ sii: read from %08lx (data=0x%04x) ]\n",
433 (long)relative_addr, d->regs[regnr]);
434 } else {
435 debug("[ sii: write to %08lx (data=0x%04x) ]\n",
436 (long)relative_addr, (int)idata);
437 d->regs[regnr] = idata;
438 }
439 }
440
441 if (writeflag == MEM_READ)
442 memory_writemax64(cpu, data, len, odata);
443
444 return 1;
445 }
446
447
448 /*
449 * dev_sii_init():
450 */
451 void dev_sii_init(struct machine *machine, struct memory *mem,
452 uint64_t baseaddr, uint64_t buf_start, uint64_t buf_end, int irq_nr)
453 {
454 struct sii_data *d = malloc(sizeof(struct sii_data));
455 if (d == NULL) {
456 fprintf(stderr, "out of memory\n");
457 exit(1);
458 }
459
460 memset(d, 0, sizeof(struct sii_data));
461 d->irq_nr = irq_nr;
462 d->buf_start = buf_start;
463 d->buf_end = buf_end;
464
465 d->regs = (uint16_t *) &d->siiregs;
466
467 memory_device_register(mem, "sii", baseaddr, DEV_SII_LENGTH,
468 dev_sii_access, (void *)d, MEM_DEFAULT, NULL);
469
470 machine_add_tickfunction(machine, dev_sii_tick, d, SII_TICK_SHIFT);
471 }
472

  ViewVC Help
Powered by ViewVC 1.1.26