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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 43 - (show annotations)
Mon Oct 8 16:22:43 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 12839 byte(s)
0.4.6
1 /*
2 * Copyright (C) 2003-2007 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.21 2007/06/15 19:57:34 debug Exp $
29 *
30 * COMMENT: 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 "interrupt.h"
42 #include "machine.h"
43 #include "memory.h"
44 #include "misc.h"
45
46 #include "siireg.h"
47
48
49 #define SII_TICK_SHIFT 14
50
51
52 struct sii_data {
53 struct interrupt irq;
54
55 uint64_t buf_start;
56 uint64_t buf_end;
57
58 int connected;
59 int connected_to_id;
60
61 int register_choice;
62 SIIRegs siiregs;
63 uint16_t *regs;
64 };
65
66
67 /*
68 * combine_sii_bits():
69 *
70 * Combines some bits of CSTAT and DSTAT that are connected.
71 */
72 void combine_sii_bits(struct sii_data *d)
73 {
74 int ci, di;
75
76 di = ((d->siiregs.dstat & SII_MIS) |
77 (d->siiregs.dstat & SII_IBF) |
78 (d->siiregs.dstat & SII_TBE) |
79 (d->siiregs.dstat & SII_DNE))==0? 0 : SII_DI;
80
81 ci = ((d->siiregs.cstat & SII_RST) |
82 (d->siiregs.cstat & SII_BER) |
83 (d->siiregs.cstat & SII_OBC) |
84 (d->siiregs.cstat & SII_BUF) |
85 (d->siiregs.cstat & SII_LDN) |
86 (d->siiregs.cstat & SII_SCH))==0? 0 : SII_CI;
87
88 d->siiregs.cstat &= ~(SII_CI | SII_DI);
89 d->siiregs.dstat &= ~(SII_CI | SII_DI);
90
91 d->siiregs.cstat |= (ci | di);
92 d->siiregs.dstat |= (ci | di);
93 }
94
95
96 DEVICE_TICK(sii)
97 {
98 struct sii_data *d = extra;
99
100 /* ? */
101 d->siiregs.dstat = (d->siiregs.dstat & ~0x7)
102 | ((d->siiregs.dstat + 1) & 0x7);
103
104 /* SCSI Commands: */
105
106 if (d->siiregs.comm & SII_CHRESET) { /* (I,T,D) */
107 /* debug("[ sii: command TODO: CHRESET ]\n"); */
108 }
109
110 if (d->siiregs.comm & SII_DISCON) { /* (I,T,D) */
111 /* debug("[ sii: command TODO: DISCON ]\n"); */
112 d->siiregs.cstat &= ~SII_CON; /* Connected */
113
114 if (d->connected) {
115 d->siiregs.cstat |= SII_SCH; /* State change */
116 d->connected = 0;
117 }
118
119 d->siiregs.cstat &= ~SII_SIP; /* Selection in progress */
120 d->siiregs.comm &= ~SII_DISCON;
121 }
122
123 if (d->siiregs.comm & SII_REQDATA) { /* (T) */
124 /* debug("[ sii: command TODO: REQDATA ]\n"); */
125 }
126
127 if (d->siiregs.comm & SII_SELECT) { /* (D) */
128 /* debug("[ sii: command SELECT ]\n"); */
129 d->siiregs.comm &= ~SII_SELECT;
130
131 /* slcsr contains the other target's id */
132 d->siiregs.cstat |= SII_SIP; /* Selection in progress */
133 d->connected = 0;
134 d->connected_to_id = 0;
135
136 /* Is the target available for selection?
137 TODO: make this nicer */
138 #if 0
139 if ((d->siiregs.slcsr & 7) == 0) {
140 d->siiregs.cstat |= SII_CON; /* Connected */
141 d->siiregs.cstat |= SII_SCH; /* State change */
142 d->siiregs.cstat &= ~SII_SIP; /* Sel. in progress */
143
144 d->connected = 1;
145 d->connected_to_id = 0;
146 }
147 #endif
148 }
149
150 if (d->siiregs.comm & SII_INXFER
151 && (d->siiregs.comm & 0x70) == (d->siiregs.cstat & 0x70) &&
152 (d->siiregs.comm & 0x03) == (d->siiregs.dstat & 0x03) &&
153 !(d->siiregs.cstat & SII_SIP)) { /* (I,T) */
154 debug("[ sii: command INXFER to scsiid=%i ]\n",
155 d->siiregs.slcsr);
156 if (d->siiregs.comm & SII_DMA)
157 debug("[ sii DMA: TODO ]\n");
158 else {
159 debug("[ sii: transmitting byte 0x%02x using "
160 "PIO mode ]\n", d->siiregs.data);
161 d->siiregs.comm &= ~SII_INXFER;
162
163 /* d->siiregs.dstat |= SII_DNE; */
164 /* Done, only for DMA? */
165 d->siiregs.dstat |= SII_TBE; /* Buffer empty? */
166 }
167 }
168
169 combine_sii_bits(d);
170
171 if (d->siiregs.csr & SII_IE && d->siiregs.cstat & (SII_CI | SII_DI))
172 INTERRUPT_ASSERT(d->irq);
173 else
174 INTERRUPT_DEASSERT(d->irq);
175 }
176
177
178 DEVICE_ACCESS(sii)
179 {
180 uint64_t idata = 0, odata = 0;
181 int regnr;
182 struct sii_data *d = extra;
183
184 if (relative_addr & 3) {
185 debug("[ sii relative_addr = 0x%x !!! ]\n",
186 (int) relative_addr);
187 return 0;
188 }
189
190 dev_sii_tick(cpu, extra);
191
192 if (writeflag == MEM_WRITE)
193 idata = memory_readmax64(cpu, data, len);
194
195 regnr = relative_addr / 2;
196 odata = d->regs[regnr];
197
198 switch (relative_addr) {
199 case 0x00: /* SII_SDB: Diagnostic */
200 if (writeflag == MEM_READ) {
201 debug("[ sii: read from SDB (data=0x%04x) ]\n",
202 d->regs[regnr]);
203 } else {
204 debug("[ sii: write to SDB (data=0x%04x) ]\n",
205 (int)idata);
206 d->regs[regnr] = idata;
207 return 1;
208 }
209 break;
210 case 0x0c: /* SII_CSR: Control/status */
211 if (writeflag == MEM_READ) {
212 debug("[ sii: read from CSR (data=0x%04x) ]\n",
213 d->regs[regnr]);
214 } else {
215 debug("[ sii: write to CSR (data=0x%04x: %s %s "
216 "%s %s %s) ]\n", (int)idata,
217 idata & SII_HPM? "HPM" : "!hpm",
218 idata & SII_RSE? "RSE" : "!rse",
219 idata & SII_SLE? "SLE" : "!sle",
220 idata & SII_PCE? "PCE" : "!pce",
221 idata & SII_IE? "IE" : "!ie");
222 d->regs[regnr] = idata;
223 return 1;
224 }
225 break;
226 case 0x10: /* SII_ID: SCSI ID */
227 if (writeflag == MEM_READ) {
228 debug("[ sii: read from ID (data=0x%04x) ]\n",
229 d->regs[regnr]);
230 } else {
231 debug("[ sii: write to ID (data=0x%04x: scsi id %i)"
232 " ]\n", (int)idata, (int)(idata & 7));
233 if (!(idata & SII_ID_IO))
234 debug("WARNING: sii ID bit SII_ID_IO not "
235 "set on write!\n");
236 idata &= ~SII_ID_IO;
237 if ((idata & ~0x7) != 0)
238 debug("WARNING: sii ID bits that should "
239 "be zero are not zero!\n");
240 idata &= 0x7;
241 d->regs[regnr] = idata & 0x7;
242 return 1;
243 }
244 break;
245 case 0x14: /* SII_SLCSR: Selector control */
246 if (writeflag == MEM_READ) {
247 debug("[ sii: read from SLCSR (data=0x%04x: "
248 "scsi_id=%i) ]\n", d->regs[regnr],
249 d->regs[regnr] & 7);
250 } else {
251 debug("[ sii: write to SLCSR (data=0x%04x: "
252 "scsi_id=%i) ]\n", (int)idata, (int)(idata & 7));
253 if ((idata & ~0x7) != 0)
254 debug("WARNING: sii SLCSR bits that should "
255 "be zero are not zero!\n");
256 idata &= 0x7;
257 d->regs[regnr] = idata & 0x7;
258 return 1;
259 }
260 break;
261 case 0x18: /* SII_DESTAT: Selection detector status */
262 if (writeflag == MEM_READ) {
263 /* TODO: set DESTAT from somewhere else? */
264 debug("[ sii: read from DESTAT (data=0x%04x: "
265 "scsi_id=%i) ]\n", d->regs[regnr],
266 d->regs[regnr] & 7);
267 } else {
268 debug("[ sii: write to DESTAT (data=0x%04x: "
269 "scsi_id=%i) ]\n", (int)idata, (int)(idata & 7));
270 debug("WARNING: sii DESTAT is read-only!\n");
271 return 1;
272 }
273 break;
274 case 0x20: /* SII_DATA: Data register */
275 if (writeflag == MEM_READ) {
276 /* TODO */
277 debug("[ sii: read from DATA (data=0x%04x) ]\n",
278 d->regs[regnr]);
279 } else {
280 /* TODO */
281 debug("[ sii: write to DATA (data=0x%04x) ]\n",
282 (int)idata);
283 idata &= 0xff;
284 d->regs[regnr] = idata;
285 return 1;
286 }
287 break;
288 case 0x24: /* SII_DMCTRL: DMA control */
289 if (writeflag == MEM_READ) {
290 debug("[ sii: read from DMCTRL (data=0x%04x) ]\n",
291 d->regs[regnr]);
292 } else {
293 debug("[ sii: write to DMCTRL (data=0x%04x: %s) ]\n",
294 (int)idata, (idata & 3)==0? "async" : "sync");
295 if ((idata & ~0x3) != 0)
296 debug("WARNING: sii DMCTRL bits that "
297 "should be zero are not zero!\n");
298 idata &= 0x3;
299 d->regs[regnr] = idata;
300 return 1;
301 }
302 break;
303 case 0x48: /* SII_CSTAT: Connection status */
304 if (writeflag == MEM_READ) {
305 debug("[ sii: read from CSTAT (data=0x%04x) ]\n",
306 d->regs[regnr]);
307 } else {
308 debug("[ sii: write to CSTAT (data=0x%04x) ]\n",
309 (int)idata);
310
311 /* readonly / writeoncetoclear bits according
312 to page 21 in the DS3100 manual: */
313 if (idata & (1<<13)) {
314 idata &= ~(1<<13); d->regs[regnr] &= ~(1<<13);
315 }
316 if (idata & (1<<12)) {
317 idata &= ~(1<<12); d->regs[regnr] &= ~(1<<12);
318 }
319 if (idata & (1<<11)) {
320 /* is this actually write-1-to-clear? */
321 idata &= ~(1<<11); d->regs[regnr] &= ~(1<<11);
322 }
323 if (idata & (1<<9)) {
324 /* ? */
325 idata &= ~(1<<9); d->regs[regnr] &= ~(1<<9);
326 }
327 if (idata & (1<<8)) {
328 /* ? */
329 idata &= ~(1<<8); d->regs[regnr] &= ~(1<<8);
330 }
331 if (idata & (1<<7)) {
332 idata &= ~(1<<7); d->regs[regnr] &= ~(1<<7);
333 }
334 if (idata & (1<<3)) {
335 idata &= ~(1<<3); d->regs[regnr] &= ~(1<<3);
336 }
337
338 /* Read-only bits are taken from the old register: */
339 idata &= ~0x3bf7;
340 idata |= d->regs[regnr] & 0x3bf7;
341
342 d->regs[regnr] = idata;
343 return 1;
344 }
345 break;
346 case 0x4c: /* SII_DSTAT: Data transfer status */
347 if (writeflag == MEM_READ) {
348 debug("[ sii: read from DSTAT (data=0x%04x) ]\n",
349 d->regs[regnr]);
350 } else {
351 debug("[ sii: write to DSTAT (data=0x%04x) ]\n",
352 (int)idata);
353
354 /* readonly / writeoncetoclear bits
355 according to page 22 in the DS3100 manual: */
356 if (idata & (1<<13)) {
357 idata &= ~(1<<13); d->regs[regnr] &= ~(1<<13);
358 }
359 if (idata & (1<<11)) {
360 /* is this write-1-to-clear? */
361 idata &= ~(1<<11); d->regs[regnr] &= ~(1<<11);
362 }
363 if (idata & (1<<10)) {
364 /* is this write-1-to-clear? */
365 idata &= ~(1<<10); d->regs[regnr] &= ~(1<<10);
366 }
367 if (idata & (1<<4)) {
368 /* is this write-1-to-clear? */
369 idata &= ~(1<<4); d->regs[regnr] &= ~(1<<4);
370 }
371 if (idata & (1<<3)) {
372 idata &= ~(1<<3); d->regs[regnr] &= ~(1<<3);
373 }
374
375 /* Read-only bits are taken from the old register: */
376 idata &= ~0x0c17;
377 idata |= d->regs[regnr] & 0x0c17;
378
379 d->regs[regnr] = idata;
380 return 1;
381 }
382 break;
383 case 0x50: /* SII_COMM: Command */
384 if (writeflag == MEM_READ) {
385 debug("[ sii: read from COMM (data=0x%04x) ]\n",
386 d->regs[regnr]);
387 } else {
388 debug("[ sii: write to COMM (data=0x%04x: %s %s "
389 "%s command=0x%02x rest=0x%02x) ]\n", (int)idata,
390 idata & SII_DMA? "DMA" : "!dma",
391 idata & SII_DO_RST? "RST" : "!rst",
392 idata & SII_RSL? "RSL" : "!rsl",
393 /* command, 5 bits: */
394 (int)((idata >> 7) & 0x1f),
395 /* rest, 7 bits: */
396 (int)(idata & 0x3f));
397
398 if (idata & SII_DO_RST) {
399 /* Reset: TODO */
400 }
401
402 idata &= ~SII_DO_RST;
403 d->regs[regnr] = idata;
404
405 dev_sii_tick(cpu, extra);
406 return 1;
407 }
408 break;
409 case 0x54: /* SII_DICTRL: Diagnostics control */
410 if (writeflag == MEM_READ) {
411 debug("[ sii: read from DICTRL (data=0x%04x) ]\n",
412 d->regs[regnr]);
413 } else {
414 debug("[ sii: write to DICTRL (data=0x%04x: "
415 "port=%s) ]\n", (int)idata,
416 idata & SII_PRE? "enabled" : "disabled");
417 if ((idata & ~0xf) != 0)
418 debug("WARNING: sii DICTRL bits that "
419 "should be zero are not zero!\n");
420 d->regs[regnr] = idata;
421 return 1;
422 }
423 break;
424 default:
425 if (writeflag==MEM_READ) {
426 debug("[ sii: read from %08lx (data=0x%04x) ]\n",
427 (long)relative_addr, d->regs[regnr]);
428 } else {
429 debug("[ sii: write to %08lx (data=0x%04x) ]\n",
430 (long)relative_addr, (int)idata);
431 d->regs[regnr] = idata;
432 }
433 }
434
435 if (writeflag == MEM_READ)
436 memory_writemax64(cpu, data, len, odata);
437
438 return 1;
439 }
440
441
442 void dev_sii_init(struct machine *machine, struct memory *mem,
443 uint64_t baseaddr, uint64_t buf_start, uint64_t buf_end,
444 char *irq_path)
445 {
446 struct sii_data *d;
447
448 CHECK_ALLOCATION(d = malloc(sizeof(struct sii_data)));
449 memset(d, 0, sizeof(struct sii_data));
450
451 INTERRUPT_CONNECT(irq_path, d->irq);
452 d->buf_start = buf_start;
453 d->buf_end = buf_end;
454 d->regs = (uint16_t *) &d->siiregs;
455
456 memory_device_register(mem, "sii", baseaddr, DEV_SII_LENGTH,
457 dev_sii_access, (void *)d, DM_DEFAULT, NULL);
458
459 machine_add_tickfunction(machine, dev_sii_tick, d,
460 SII_TICK_SHIFT);
461 }
462

  ViewVC Help
Powered by ViewVC 1.1.26