dev_adb.cc Source File

Back to the index.

dev_adb.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-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: Apple Desktop Bus (ADB) controller
29  *
30  * Based on intuition from reverse-engineering NetBSD/macppc source code,
31  * so it probably only works with that OS.
32  *
33  * The comment "OK" means that 100% of the functionality used by NetBSD/macppc
34  * is covered.
35  *
36  * TODO:
37  * o) Clean up, don't hardcode values.
38  * o) Convert into a separate controller, bus, device architecture.
39  */
40 
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sys/time.h>
45 
46 #include "console.h"
47 #include "cpu.h"
48 #include "device.h"
49 #include "interrupt.h"
50 #include "machine.h"
51 #include "memory.h"
52 #include "misc.h"
53 
54 #include "thirdparty/adb_viareg.h"
55 
56 
57 #define debug fatal
58 /* #define ADB_DEBUG */
59 
60 
61 #define TICK_SHIFT 17
62 #define DEV_ADB_LENGTH 0x2000
63 
64 #define N_VIA_REGS 0x10
65 #define VIA_REG_SHIFT 9
66 
67 #define MAX_BUF 100
68 
69 
70 static const char *via_regname[N_VIA_REGS] = {
71  "vBufB", "vBufA", "vDirB", "vDirA",
72  "vT1C", "vT1CH", "vT1L", "vT1LH",
73  "vT2C", "vT2CH", "vSR", "vACR",
74  "vPCR", "vIFR", "vIER", "(unknown)" };
75 
76 struct adb_data {
77  struct interrupt irq;
79 
80  int kbd_dev;
81 
82  long long transfer_nr;
83 
84  uint8_t reg[N_VIA_REGS];
85 
87  uint8_t output_buf[MAX_BUF];
88 
91  uint8_t input_buf[MAX_BUF];
92 
93  int dir;
95  int ack; /* last ack state */
96  int tip; /* transfer in progress */
97 };
98 
99 #define DIR_INPUT 0
100 #define DIR_OUTPUT 1
101 
102 #define BUFB_nINTR 0x08
103 #define BUFB_ACK 0x10
104 #define BUFB_nTIP 0x20
105 #define IFR_SR 0x04
106 #define IFR_ANY 0x80
107 #define ACR_SR_OUT 0x10
108 
109 
110 
112 {
113  struct adb_data *d = (struct adb_data *) extra;
114  int assert;
115 
116  assert = d->reg[vIFR >> VIA_REG_SHIFT] & IFR_ANY;
117  if (assert == IFR_ANY && d->int_enable)
118  assert = 1;
119 
120  if (assert)
121  INTERRUPT_ASSERT(d->irq);
122  else if (d->int_asserted)
124 
125  d->int_asserted = assert;
126 }
127 
128 
129 /*
130  * adb_reset():
131  *
132  * Reset registers to default values.
133  */
134 static void adb_reset(struct adb_data *d)
135 {
136  d->kbd_dev = 2;
137 
138  memset(d->reg, 0, sizeof(d->reg));
140 
141  d->cur_output_offset = 0;
142  memset(d->output_buf, 0, sizeof(d->output_buf));
143 
144  d->dir = 0;
145  d->int_enable = 0;
146  d->ack = 0;
147  d->tip = 0;
148 }
149 
150 
151 /*
152  * adb_process_cmd():
153  *
154  * This function should be called whenever a complete ADB command has been
155  * received.
156  */
157 static void adb_process_cmd(struct cpu *cpu, struct adb_data *d)
158 {
159  int i, reg, dev;
160 
161  debug("[ adb: COMMAND:");
162  for (i=0; i<d->cur_output_offset; i++)
163  debug(" %02x", d->output_buf[i]);
164  debug(" ]\n");
165 
166  if (d->cur_output_offset < 2) {
167  fatal("[ adb: WEIRD output length: %i ]\n",
168  d->cur_output_offset);
169  exit(1);
170  }
171 
172  switch (d->output_buf[0]) {
173 
174  case 0: /* ADB commands: */
175  if (d->output_buf[1] == 0x00) {
176  /* Reset. */
177  return;
178  }
179  if ((d->output_buf[1] & 0x0c) == 0x0c) {
180  /* ADBTALK: */
181  reg = d->output_buf[1] & 3;
182  dev = d->output_buf[1] >> 4;
183  fatal("dev=%i reg=%i\n", dev, reg);
184  /* Default values: nothing here */
185  d->input_buf[0] = 0x00;
186  d->input_buf[1] = 0x00;
187  d->input_buf[2] = d->output_buf[1];
188  d->cur_input_length = 3;
189  if (dev == d->kbd_dev) {
190  /* Keyboard. */
191  d->input_buf[0] = 0x01;
192  d->input_buf[1] = 0x01;
193  d->input_buf[2] = d->output_buf[1];
194  d->input_buf[3] = 0x01;
195  d->input_buf[4] = 0x01;
196  d->cur_input_length = 5;
197  }
198  } else if ((d->output_buf[1] & 0x0c) == 0x08) {
199  int new_dev_pos = d->output_buf[2] & 15;
200  /* ADBLISTEN: */
201  if ((d->output_buf[1] >> 4) != d->kbd_dev) {
202  fatal("[ adb: ADBLISTEN not to kbd ]\n");
203  exit(1);
204  }
205  if (d->output_buf[3] != 0xfe ||
206  (d->output_buf[2] & 0xf0) != 0x60) {
207  fatal("[ adb: unknown ADBLISTEN ]\n");
208  exit(1);
209  }
210  /* Move device. */
211  d->kbd_dev = new_dev_pos;
212  } else {
213  fatal("[ adb: unknown ADB command? ]\n");
214  exit(1);
215  }
216  break;
217 
218  case 1: /* PRAM/RTC: */
219  if (d->cur_output_offset == 3 &&
220  d->output_buf[1] == 0x01 &&
221  d->output_buf[2] == 0x01) {
222  /* Autopoll: */
223  d->input_buf[0] = 0x00;
224  d->input_buf[1] = 0x00;
225  d->input_buf[2] = d->output_buf[1];
226  d->cur_input_length = 3;
227  } else if (d->cur_output_offset == 2 &&
228  d->output_buf[1] == 0x03) {
229  /* Read RTC date/time: */
230  struct timeval tv;
231  gettimeofday(&tv, NULL);
232  d->input_buf[0] = tv.tv_sec >> 24;
233  d->input_buf[1] = tv.tv_sec >> 16;
234  d->input_buf[2] = tv.tv_sec >> 8;
235  d->input_buf[3] = tv.tv_sec;
236  d->cur_input_length = 4;
237  } else if (d->cur_output_offset == 2 &&
238  d->output_buf[1] == 0x11) {
239  /* Reboot. */
240  fatal("[ adb: reboot. TODO: make this nicer ]\n");
241  exit(1);
242  } else {
243  fatal("[ adb: UNIMPLEMENTED PRAM/RTC command ]\n");
244  exit(1);
245  }
246  break;
247 
248  default:fatal("[ adb: UNKNOWN command type 0x%02x ]\n",
249  d->output_buf[0]);
250  exit(1);
251  }
252 
253  d->reg[vBufB >> VIA_REG_SHIFT] &= ~BUFB_nINTR;
254  d->reg[vIFR >> VIA_REG_SHIFT] |= IFR_ANY | IFR_SR;
255  d->reg[vSR >> VIA_REG_SHIFT] = 0x00; /* Dummy. */
256 }
257 
258 
259 /*
260  * adb_transfer():
261  *
262  * This function should be called whenever a new transfer is started, a
263  * transfer is finished, or when the next byte in a transfer should be
264  * sent/received.
265  */
266 static void adb_transfer(struct cpu *cpu, struct adb_data *d, int state_change)
267 {
268  unsigned char c = 0x00;
269 
270  if (state_change) {
271  if (d->tip == 0) {
272  debug("[ adb: transfer #%lli done ]\n",
273  (long long)d->transfer_nr);
274  if (d->cur_output_offset > 0)
275  adb_process_cmd(cpu, d);
276  d->transfer_nr ++;
277  return;
278  }
279  debug("[ adb: starting transfer #%lli: %s ]\n", (long long)
280  d->transfer_nr, d->dir == DIR_INPUT? "INPUT" : "OUTPUT");
282  }
283 
284  debug("[ adb: transfer #%lli: ", (long long)d->transfer_nr);
285 
286  switch (d->dir) {
287 
288  case DIR_INPUT:
289  if (d->cur_input_offset >= d->cur_input_length)
290  fatal("[ adb: INPUT beyond end of data? ]\n");
291  else
292  c = d->input_buf[d->cur_input_offset ++];
293  debug("input 0x%02x", c);
294  d->reg[vSR >> VIA_REG_SHIFT] = c;
295  d->reg[vIFR >> VIA_REG_SHIFT] |= IFR_ANY | IFR_SR;
296  if (d->cur_input_offset >= d->cur_input_length)
297  d->reg[vBufB >> VIA_REG_SHIFT] |= BUFB_nINTR;
298  break;
299 
300  case DIR_OUTPUT:
301  c = d->reg[vSR >> VIA_REG_SHIFT];
302  debug("output 0x%02x", c);
303  d->reg[vIFR >> VIA_REG_SHIFT] |= IFR_ANY | IFR_SR;
304  d->reg[vBufB >> VIA_REG_SHIFT] |= BUFB_nINTR;
305  d->output_buf[d->cur_output_offset ++] = c;
306  break;
307  }
308 
309  debug(" ]\n");
310 }
311 
312 
314 {
315  uint64_t idata = 0, odata = 0;
316  struct adb_data *d = (struct adb_data *) extra;
317  // uint8_t old = 0;
318 
319  if (writeflag == MEM_WRITE)
320  idata = memory_readmax64(cpu, data, len);
321 
322 #ifdef ADB_DEBUG
323  if ((relative_addr & ((1 << VIA_REG_SHIFT) - 1)) != 0)
324  fatal("[ adb: %s non-via register? offset 0x%x ]\n",
325  writeflag == MEM_READ? "read from" : "write to",
326  (int)relative_addr);
327  else if (writeflag == MEM_READ)
328  fatal("[ adb: read from %s: 0x%02x ]\n",
329  via_regname[relative_addr >> VIA_REG_SHIFT],
330  (int)d->reg[relative_addr >> VIA_REG_SHIFT]);
331  else
332  fatal("[ adb: write to %s: 0x%02x ]\n", via_regname[
333  relative_addr >> VIA_REG_SHIFT], (int)idata);
334 #endif
335 
336  if (writeflag == MEM_READ)
337  odata = d->reg[relative_addr >> VIA_REG_SHIFT];
338  else {
339  // old = d->reg[relative_addr >> VIA_REG_SHIFT];
340  switch (relative_addr) {
341  case vIFR:
342  /*
343  * vIFR is write-ones-to-clear, and the highest bit
344  * (IFR_ANY) is set if any of the lower bits are set.
345  */
346  d->reg[relative_addr >> VIA_REG_SHIFT] &= ~(idata|0x80);
347  if (d->reg[relative_addr >> VIA_REG_SHIFT] & 0x7f)
348  d->reg[relative_addr >> VIA_REG_SHIFT] |= 0x80;
349  break;
350  default:
351  d->reg[relative_addr >> VIA_REG_SHIFT] = idata;
352  }
353  }
354 
355  switch (relative_addr) {
356 
357  case vBufB:
358  /* OK */
359  if (writeflag == MEM_WRITE) {
360  int old_tip = d->tip;
361  int old_ack = d->ack;
362  if (idata & BUFB_nINTR)
363  idata &= ~BUFB_nINTR;
364  d->ack = 0;
365  if (idata & BUFB_ACK) {
366  idata &= ~BUFB_ACK;
367  d->ack = 1;
368  }
369  d->tip = 1;
370  if (idata & BUFB_nTIP) {
371  idata &= ~BUFB_nTIP;
372  d->tip = 0;
373  }
374  if (idata != 0)
375  fatal("[ adb: WARNING! UNIMPLEMENTED bits in"
376  " vBufB: 0x%02x ]\n", (int)idata);
377  if (old_tip != d->tip)
378  adb_transfer(cpu, d, 1);
379  else if (old_ack != d->ack)
380  adb_transfer(cpu, d, 0);
381  }
382  break;
383 
384  case vDirB:
385  break;
386 
387  case vSR:
388  /* Clear the SR interrupt flag, if set: */
389  d->reg[vIFR >> VIA_REG_SHIFT] &= ~IFR_SR;
390  break;
391 
392  case vACR:
393  /* OK */
394  if (writeflag == MEM_WRITE) {
395  if (idata & ACR_SR_OUT)
396  d->dir = DIR_OUTPUT;
397  else
398  d->dir = DIR_INPUT;
399  }
400  break;
401 
402  case vIFR:
403  /* OK */
404  break;
405 
406  case vIER:
407  /* OK */
408  if (writeflag == MEM_WRITE) {
409  d->int_enable = idata & 0x80? 1 : 0;
410  if (idata != 0x04 && idata != 0x84)
411  fatal("[ adb: WARNING! vIER value 0x%x is"
412  " UNKNOWN ]\n", (int)idata);
413  }
414  break;
415 
416  default:if ((relative_addr & ((1 << VIA_REG_SHIFT) - 1)) != 0)
417  fatal("[ adb: %s non-via register? offset 0x%x ]\n",
418  writeflag == MEM_READ? "read from" : "write to",
419  (int)relative_addr);
420  else if (writeflag == MEM_READ)
421  fatal("[ adb: READ from UNIMPLEMENTED %s ]\n",
422  via_regname[relative_addr >> VIA_REG_SHIFT]);
423  else
424  fatal("[ adb: WRITE to UNIMPLEMENTED %s: 0x%x ]\n",
425  via_regname[relative_addr >> VIA_REG_SHIFT],
426  (int)idata);
427  exit(1);
428  }
429 
430  if (writeflag == MEM_READ)
431  memory_writemax64(cpu, data, len, odata);
432 
433  return 1;
434 }
435 
436 
438 {
439  struct adb_data *d;
440 
441  CHECK_ALLOCATION(d = (struct adb_data *) malloc(sizeof(struct adb_data)));
442  memset(d, 0, sizeof(struct adb_data));
443 
445 
446  adb_reset(d);
447 
449  devinit->addr, DEV_ADB_LENGTH, dev_adb_access, d, DM_DEFAULT, NULL);
450  machine_add_tickfunction(devinit->machine, dev_adb_tick, d,
451  TICK_SHIFT);
452 
453  return 1;
454 }
455 
adb_data::irq
struct interrupt irq
Definition: dev_adb.cc:77
data
u_short data
Definition: siireg.h:79
INTERRUPT_CONNECT
#define INTERRUPT_CONNECT(name, istruct)
Definition: interrupt.h:77
adb_data::cur_output_offset
int cur_output_offset
Definition: dev_adb.cc:86
adb_data::cur_input_offset
int cur_input_offset
Definition: dev_adb.cc:89
BUFB_nTIP
#define BUFB_nTIP
Definition: dev_adb.cc:104
INTERRUPT_ASSERT
#define INTERRUPT_ASSERT(istruct)
Definition: interrupt.h:74
ACR_SR_OUT
#define ACR_SR_OUT
Definition: dev_adb.cc:107
debug
#define debug
Definition: dev_adb.cc:57
vIER
#define vIER
Definition: adb_viareg.h:172
adb_data::reg
uint8_t reg[N_VIA_REGS]
Definition: dev_adb.cc:84
adb_data::int_enable
int int_enable
Definition: dev_adb.cc:94
adb_data
Definition: dev_adb.cc:76
devinit::addr
uint64_t addr
Definition: device.h:46
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
adb_viareg.h
adb_data::input_buf
uint8_t input_buf[MAX_BUF]
Definition: dev_adb.cc:91
MEM_READ
#define MEM_READ
Definition: memory.h:116
DM_DEFAULT
#define DM_DEFAULT
Definition: memory.h:130
devinit::machine
struct machine * machine
Definition: device.h:41
console.h
device.h
vIFR
#define vIFR
Definition: adb_viareg.h:171
vDirB
#define vDirB
Definition: adb_viareg.h:160
MEM_WRITE
#define MEM_WRITE
Definition: memory.h:117
IFR_SR
#define IFR_SR
Definition: dev_adb.cc:105
vACR
#define vACR
Definition: adb_viareg.h:169
adb_data::cur_input_length
int cur_input_length
Definition: dev_adb.cc:90
machine_add_tickfunction
void machine_add_tickfunction(struct machine *machine, void(*func)(struct cpu *, void *), void *extra, int clockshift)
Definition: machine.cc:280
MAX_BUF
#define MAX_BUF
Definition: dev_adb.cc:67
devinit::interrupt_path
char * interrupt_path
Definition: device.h:50
BUFB_ACK
#define BUFB_ACK
Definition: dev_adb.cc:103
adb_data::kbd_dev
int kbd_dev
Definition: dev_adb.cc:80
interrupt.h
fatal
void fatal(const char *fmt,...)
Definition: main.cc:152
N_VIA_REGS
#define N_VIA_REGS
Definition: dev_adb.cc:64
TICK_SHIFT
#define TICK_SHIFT
Definition: dev_adb.cc:61
adb_data::ack
int ack
Definition: dev_adb.cc:95
misc.h
adb_data::transfer_nr
long long transfer_nr
Definition: dev_adb.cc:82
memory_readmax64
uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len)
Definition: memory.cc:55
machine.h
adb_data::dir
int dir
Definition: dev_adb.cc:93
IFR_ANY
#define IFR_ANY
Definition: dev_adb.cc:106
devinit::name
char * name
Definition: device.h:43
devinit
Definition: device.h:40
cpu.h
DEVICE_ACCESS
DEVICE_ACCESS(adb)
Definition: dev_adb.cc:313
adb_data::output_buf
uint8_t output_buf[MAX_BUF]
Definition: dev_adb.cc:87
machine::memory
struct memory * memory
Definition: machine.h:126
reg
#define reg(x)
Definition: tmp_alpha_tail.cc:53
vBufB
#define vBufB
Definition: adb_viareg.h:158
BUFB_nINTR
#define BUFB_nINTR
Definition: dev_adb.cc:102
DEVICE_TICK
DEVICE_TICK(adb)
Definition: dev_adb.cc:111
INTERRUPT_DEASSERT
#define INTERRUPT_DEASSERT(istruct)
Definition: interrupt.h:75
vSR
#define vSR
Definition: adb_viareg.h:168
adb_data::tip
int tip
Definition: dev_adb.cc:96
VIA_REG_SHIFT
#define VIA_REG_SHIFT
Definition: dev_adb.cc:65
DIR_OUTPUT
#define DIR_OUTPUT
Definition: dev_adb.cc:100
interrupt
Definition: interrupt.h:36
DIR_INPUT
#define DIR_INPUT
Definition: dev_adb.cc:99
memory_writemax64
void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len, uint64_t data)
Definition: memory.cc:89
cpu
Definition: cpu.h:326
adb_data::int_asserted
int int_asserted
Definition: dev_adb.cc:78
DEVINIT
DEVINIT(adb)
Definition: dev_adb.cc:437
memory.h
DEV_ADB_LENGTH
#define DEV_ADB_LENGTH
Definition: dev_adb.cc:62
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