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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (show annotations)
Mon Oct 8 16:19:43 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 12943 byte(s)
0.3.8
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_sii.c,v 1.16 2006/01/01 13:17:17 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 DEVICE_ACCESS(sii)
183 {
184 uint64_t idata = 0, odata = 0;
185 int regnr;
186 struct sii_data *d = extra;
187
188 if (relative_addr & 3) {
189 debug("[ sii relative_addr = 0x%x !!! ]\n",
190 (int) relative_addr);
191 return 0;
192 }
193
194 dev_sii_tick(cpu, extra);
195
196 if (writeflag == MEM_WRITE)
197 idata = memory_readmax64(cpu, data, len);
198
199 regnr = relative_addr / 2;
200 odata = d->regs[regnr];
201
202 switch (relative_addr) {
203 case 0x00: /* SII_SDB: Diagnostic */
204 if (writeflag == MEM_READ) {
205 debug("[ sii: read from SDB (data=0x%04x) ]\n",
206 d->regs[regnr]);
207 } else {
208 debug("[ sii: write to SDB (data=0x%04x) ]\n",
209 (int)idata);
210 d->regs[regnr] = idata;
211 return 1;
212 }
213 break;
214 case 0x0c: /* SII_CSR: Control/status */
215 if (writeflag == MEM_READ) {
216 debug("[ sii: read from CSR (data=0x%04x) ]\n",
217 d->regs[regnr]);
218 } else {
219 debug("[ sii: write to CSR (data=0x%04x: %s %s "
220 "%s %s %s) ]\n", (int)idata,
221 idata & SII_HPM? "HPM" : "!hpm",
222 idata & SII_RSE? "RSE" : "!rse",
223 idata & SII_SLE? "SLE" : "!sle",
224 idata & SII_PCE? "PCE" : "!pce",
225 idata & SII_IE? "IE" : "!ie");
226 d->regs[regnr] = idata;
227 return 1;
228 }
229 break;
230 case 0x10: /* SII_ID: SCSI ID */
231 if (writeflag == MEM_READ) {
232 debug("[ sii: read from ID (data=0x%04x) ]\n",
233 d->regs[regnr]);
234 } else {
235 debug("[ sii: write to ID (data=0x%04x: scsi id %i)"
236 " ]\n", (int)idata, (int)(idata & 7));
237 if (!(idata & SII_ID_IO))
238 debug("WARNING: sii ID bit SII_ID_IO not "
239 "set on write!\n");
240 idata &= ~SII_ID_IO;
241 if ((idata & ~0x7) != 0)
242 debug("WARNING: sii ID bits that should "
243 "be zero are not zero!\n");
244 idata &= 0x7;
245 d->regs[regnr] = idata & 0x7;
246 return 1;
247 }
248 break;
249 case 0x14: /* SII_SLCSR: Selector control */
250 if (writeflag == MEM_READ) {
251 debug("[ sii: read from SLCSR (data=0x%04x: "
252 "scsi_id=%i) ]\n", d->regs[regnr],
253 d->regs[regnr] & 7);
254 } else {
255 debug("[ sii: write to SLCSR (data=0x%04x: "
256 "scsi_id=%i) ]\n", (int)idata, (int)(idata & 7));
257 if ((idata & ~0x7) != 0)
258 debug("WARNING: sii SLCSR bits that should "
259 "be zero are not zero!\n");
260 idata &= 0x7;
261 d->regs[regnr] = idata & 0x7;
262 return 1;
263 }
264 break;
265 case 0x18: /* SII_DESTAT: Selection detector status */
266 if (writeflag == MEM_READ) {
267 /* TODO: set DESTAT from somewhere else? */
268 debug("[ sii: read from DESTAT (data=0x%04x: "
269 "scsi_id=%i) ]\n", d->regs[regnr],
270 d->regs[regnr] & 7);
271 } else {
272 debug("[ sii: write to DESTAT (data=0x%04x: "
273 "scsi_id=%i) ]\n", (int)idata, (int)(idata & 7));
274 debug("WARNING: sii DESTAT is read-only!\n");
275 return 1;
276 }
277 break;
278 case 0x20: /* SII_DATA: Data register */
279 if (writeflag == MEM_READ) {
280 /* TODO */
281 debug("[ sii: read from DATA (data=0x%04x) ]\n",
282 d->regs[regnr]);
283 } else {
284 /* TODO */
285 debug("[ sii: write to DATA (data=0x%04x) ]\n",
286 (int)idata);
287 idata &= 0xff;
288 d->regs[regnr] = idata;
289 return 1;
290 }
291 break;
292 case 0x24: /* SII_DMCTRL: DMA control */
293 if (writeflag == MEM_READ) {
294 debug("[ sii: read from DMCTRL (data=0x%04x) ]\n",
295 d->regs[regnr]);
296 } else {
297 debug("[ sii: write to DMCTRL (data=0x%04x: %s) ]\n",
298 (int)idata, (idata & 3)==0? "async" : "sync");
299 if ((idata & ~0x3) != 0)
300 debug("WARNING: sii DMCTRL bits that "
301 "should be zero are not zero!\n");
302 idata &= 0x3;
303 d->regs[regnr] = idata;
304 return 1;
305 }
306 break;
307 case 0x48: /* SII_CSTAT: Connection status */
308 if (writeflag == MEM_READ) {
309 debug("[ sii: read from CSTAT (data=0x%04x) ]\n",
310 d->regs[regnr]);
311 } else {
312 debug("[ sii: write to CSTAT (data=0x%04x) ]\n",
313 (int)idata);
314
315 /* readonly / writeoncetoclear bits according
316 to page 21 in the DS3100 manual: */
317 if (idata & (1<<13)) {
318 idata &= ~(1<<13); d->regs[regnr] &= ~(1<<13);
319 }
320 if (idata & (1<<12)) {
321 idata &= ~(1<<12); d->regs[regnr] &= ~(1<<12);
322 }
323 if (idata & (1<<11)) {
324 /* is this actually write-1-to-clear? */
325 idata &= ~(1<<11); d->regs[regnr] &= ~(1<<11);
326 }
327 if (idata & (1<<9)) {
328 /* ? */
329 idata &= ~(1<<9); d->regs[regnr] &= ~(1<<9);
330 }
331 if (idata & (1<<8)) {
332 /* ? */
333 idata &= ~(1<<8); d->regs[regnr] &= ~(1<<8);
334 }
335 if (idata & (1<<7)) {
336 idata &= ~(1<<7); d->regs[regnr] &= ~(1<<7);
337 }
338 if (idata & (1<<3)) {
339 idata &= ~(1<<3); d->regs[regnr] &= ~(1<<3);
340 }
341
342 /* Read-only bits are taken from the old register: */
343 idata &= ~0x3bf7;
344 idata |= d->regs[regnr] & 0x3bf7;
345
346 d->regs[regnr] = idata;
347 return 1;
348 }
349 break;
350 case 0x4c: /* SII_DSTAT: Data transfer status */
351 if (writeflag == MEM_READ) {
352 debug("[ sii: read from DSTAT (data=0x%04x) ]\n",
353 d->regs[regnr]);
354 } else {
355 debug("[ sii: write to DSTAT (data=0x%04x) ]\n",
356 (int)idata);
357
358 /* readonly / writeoncetoclear bits
359 according to page 22 in the DS3100 manual: */
360 if (idata & (1<<13)) {
361 idata &= ~(1<<13); d->regs[regnr] &= ~(1<<13);
362 }
363 if (idata & (1<<11)) {
364 /* is this write-1-to-clear? */
365 idata &= ~(1<<11); d->regs[regnr] &= ~(1<<11);
366 }
367 if (idata & (1<<10)) {
368 /* is this write-1-to-clear? */
369 idata &= ~(1<<10); d->regs[regnr] &= ~(1<<10);
370 }
371 if (idata & (1<<4)) {
372 /* is this write-1-to-clear? */
373 idata &= ~(1<<4); d->regs[regnr] &= ~(1<<4);
374 }
375 if (idata & (1<<3)) {
376 idata &= ~(1<<3); d->regs[regnr] &= ~(1<<3);
377 }
378
379 /* Read-only bits are taken from the old register: */
380 idata &= ~0x0c17;
381 idata |= d->regs[regnr] & 0x0c17;
382
383 d->regs[regnr] = idata;
384 return 1;
385 }
386 break;
387 case 0x50: /* SII_COMM: Command */
388 if (writeflag == MEM_READ) {
389 debug("[ sii: read from COMM (data=0x%04x) ]\n",
390 d->regs[regnr]);
391 } else {
392 debug("[ sii: write to COMM (data=0x%04x: %s %s "
393 "%s command=0x%02x rest=0x%02x) ]\n", (int)idata,
394 idata & SII_DMA? "DMA" : "!dma",
395 idata & SII_DO_RST? "RST" : "!rst",
396 idata & SII_RSL? "RSL" : "!rsl",
397 /* command, 5 bits: */
398 (int)((idata >> 7) & 0x1f),
399 /* rest, 7 bits: */
400 (int)(idata & 0x3f));
401
402 if (idata & SII_DO_RST) {
403 /* Reset: TODO */
404 }
405
406 idata &= ~SII_DO_RST;
407 d->regs[regnr] = idata;
408
409 dev_sii_tick(cpu, extra);
410 return 1;
411 }
412 break;
413 case 0x54: /* SII_DICTRL: Diagnostics control */
414 if (writeflag == MEM_READ) {
415 debug("[ sii: read from DICTRL (data=0x%04x) ]\n",
416 d->regs[regnr]);
417 } else {
418 debug("[ sii: write to DICTRL (data=0x%04x: "
419 "port=%s) ]\n", (int)idata,
420 idata & SII_PRE? "enabled" : "disabled");
421 if ((idata & ~0xf) != 0)
422 debug("WARNING: sii DICTRL bits that "
423 "should be zero are not zero!\n");
424 d->regs[regnr] = idata;
425 return 1;
426 }
427 break;
428 default:
429 if (writeflag==MEM_READ) {
430 debug("[ sii: read from %08lx (data=0x%04x) ]\n",
431 (long)relative_addr, d->regs[regnr]);
432 } else {
433 debug("[ sii: write to %08lx (data=0x%04x) ]\n",
434 (long)relative_addr, (int)idata);
435 d->regs[regnr] = idata;
436 }
437 }
438
439 if (writeflag == MEM_READ)
440 memory_writemax64(cpu, data, len, odata);
441
442 return 1;
443 }
444
445
446 /*
447 * dev_sii_init():
448 */
449 void dev_sii_init(struct machine *machine, struct memory *mem,
450 uint64_t baseaddr, uint64_t buf_start, uint64_t buf_end, int irq_nr)
451 {
452 struct sii_data *d = malloc(sizeof(struct sii_data));
453 if (d == NULL) {
454 fprintf(stderr, "out of memory\n");
455 exit(1);
456 }
457
458 memset(d, 0, sizeof(struct sii_data));
459 d->irq_nr = irq_nr;
460 d->buf_start = buf_start;
461 d->buf_end = buf_end;
462
463 d->regs = (uint16_t *) &d->siiregs;
464
465 memory_device_register(mem, "sii", baseaddr, DEV_SII_LENGTH,
466 dev_sii_access, (void *)d, DM_DEFAULT, NULL);
467
468 machine_add_tickfunction(machine, dev_sii_tick, d, SII_TICK_SHIFT);
469 }
470

  ViewVC Help
Powered by ViewVC 1.1.26