dev_sii.cc Source File

Back to the index.

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

Generated on Tue Mar 24 2020 14:04:48 for GXemul by doxygen 1.8.17