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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 21 - (show annotations)
Mon Oct 8 16:19:28 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 13067 byte(s)
0.3.7
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.15 2005/11/13 00:14:10 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, DM_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