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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26